Mercurial > hg > xemacs-beta
diff lib-src/movemail.c @ 438:84b14dcb0985 r21-2-27
Import from CVS: tag r21-2-27
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:32:25 +0200 |
parents | 3ecd8885ac67 |
children | 8de8e3f6228a |
line wrap: on
line diff
--- a/lib-src/movemail.c Mon Aug 13 11:31:26 2007 +0200 +++ b/lib-src/movemail.c Mon Aug 13 11:32:25 2007 +0200 @@ -1,35 +1,41 @@ /* movemail foo bar -- move file foo to file bar, - locking file foo the way /bin/mail respects. + locking file foo. Copyright (C) 1986, 1992, 1993, 1994, 1996 Free Software Foundation, Inc. -This file is part of GNU Emacs. +This file is part of XEmacs. -GNU Emacs is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +XEmacs is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. -GNU Emacs is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +XEmacs is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. You should have received a copy of the GNU General Public License -along with GNU Emacs; see the file COPYING. If not, write to +along with XEmacs; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +Boston, MA 02111-1307, USA. + + Please mail bugs and suggestions to the XEmacs maintainer. +*/ -/* Important notice: defining MAIL_USE_FLOCK or MAIL_USE_LOCKF *will - cause loss of mail* if you do it on a system that does not normally - use flock as its way of interlocking access to inbox files. The - setting of MAIL_USE_FLOCK and MAIL_USE_LOCKF *must agree* with the - system's own conventions. It is not a choice that is up to you. +/* Important notice: + * + * You *must* coordinate the locking method used by movemail with that + * used by your mail delivery agent, as well as that of the other mail + * user agents on your system. movemail allows you to do this at run + * time via the -m flag. Moreover, it uses a default determined by + * the MAIL_LOCK_DOT, MAIL_LOCK_LOCKF, MAIL_LOCK_FLOCK, + * MAIL_LOCK_LOCKING, and MAIL_LOCK_MMDF preprocessor settings. + */ - So, if your system uses lock files rather than flock, then the only way - you can get proper operation is to enable movemail to write lockfiles there. - This means you must either give that directory access modes - that permit everyone to write lockfiles in it, or you must make movemail - a setuid or setgid program. */ +/* + * Mike Sperber <sperber@informatik.uni-tuebingen.de> reorganized + * everything that has to with locking in December 1999. + */ /* * Modified January, 1986 by Michael R. Gretzinger (Project Athena) @@ -56,7 +62,7 @@ #define NO_SHORTNAMES /* Tell config not to load remap.h */ #define DONT_ENCAPSULATE -#include <../src/config.h> +#include <config.h> #include <sys/types.h> #include <sys/stat.h> #include <stdio.h> @@ -106,7 +112,7 @@ #include <io.h> #endif /* WINDOWSNT */ -#if defined (HAVE_UNISTD_H) || defined (USG) +#if defined (HAVE_UNISTD_H) #include <unistd.h> #endif /* unistd.h */ #ifndef F_OK @@ -116,23 +122,15 @@ #define R_OK 4 #endif /* No F_OK */ -#if defined (HAVE_FCNTL_H) || defined (USG) +#if defined (HAVE_FCNTL_H) #include <fcntl.h> #endif /* fcntl.h */ -#if defined (XENIX) || defined (WINDOWSNT) +#ifdef HAVE_LOCKING #include <sys/locking.h> #endif -#ifdef MAIL_USE_LOCKF -#define MAIL_USE_SYSTEM_LOCK -#endif - -#ifdef MAIL_USE_FLOCK -#define MAIL_USE_SYSTEM_LOCK -#endif - -#ifdef MAIL_USE_MMDF +#ifdef HAVE_MMDF extern int lk_open (), lk_close (); #endif @@ -144,6 +142,7 @@ static void fatal (char *, char*); static void error (char *, char *, char *); +static void usage(int); static void pfatal_with_name (char *); static void pfatal_and_delete (char *); static char *concat (char *, char *, char *); @@ -160,9 +159,6 @@ struct re_pattern_buffer* regexp); #endif -/* Nonzero means this is name of a lock file to delete on fatal error. */ -char *delete_lockname; - int verbose=0; #ifdef MAIL_USE_POP int reverse=0; @@ -184,10 +180,35 @@ { "regex", required_argument, NULL, 'r' }, { "match-lines", required_argument, NULL, 'l' }, #endif + { "lock-method", required_argument, NULL, 'm' }, + { "help", no_argument, NULL, 'h' }, { "verbose", no_argument, NULL, 'v' }, { 0 } }; +#define DOTLOCKING 0 +#define FLOCKING 1 +#define LOCKFING 2 +#define MMDF 3 +#define LOCKING 4 + +#if defined(MAIL_LOCK_FLOCK) && defined(HAVE_FLOCK) +#define DEFAULT_LOCKING FLOCKING +#elif defined(MAIL_LOCK_LOCKF) && defined(HAVE_LOCKF) +#define DEFAULT_LOCKING LOCKFING +#elif defined(MAIL_LOCK_MMDF) && defined(HAVE_MMDF) +#define DEFAULT_LOCKING MMDF +#elif defined(MAIL_LOCK_LOCKING) && defined(HAVE_LOCKING) +#define DEFAULT_LOCKING LOCKING +#else +#define DEFAULT_LOCKING DOTLOCKING +#endif + +static void lock_dot(char *); +static void unlock_dot(char *); +static int parse_lock_method(char *); +static char *unparse_lock_method(int); + int main (int argc, char *argv[]) { @@ -198,23 +219,23 @@ int status; #endif -#ifndef MAIL_USE_SYSTEM_LOCK - struct stat st; - long now; - int tem; - char *lockname, *p; - char *tempname; - int desc; -#endif /* not MAIL_USE_SYSTEM_LOCK */ + int lock_method = DEFAULT_LOCKING; + + char *maybe_lock_env; - delete_lockname = 0; + maybe_lock_env = getenv("EMACSLOCKMETHOD"); + if (maybe_lock_env) + { + printf("maybe-lock_env: %s\n", maybe_lock_env); + lock_method = parse_lock_method(maybe_lock_env); + } - while (1) + for (;;) { #ifdef MAIL_USE_POP - char* optstring = "i:o:p:l:r:xvk"; + char* optstring = "i:o:m:p:l:r:xvhk"; #else - char* optstring = "i:o:v"; + char* optstring = "i:o:m:vh"; #endif int opt = getopt_long (argc, argv, optstring, longopts, 0); @@ -255,7 +276,16 @@ regexp_pattern = compile_regex (optarg); break; #endif - case 'v': verbose = 1; break; + + case 'm': + lock_method = parse_lock_method(optarg); + break; + case 'h': + usage(lock_method); + exit(0); + case 'v': + verbose = 1; + break; } } @@ -272,17 +302,19 @@ if (!inname || !outname) { - fprintf (stderr, "Usage: movemail [-rvxk] [-l lines ] [-i] inbox [-o] destfile [[-p] POP-password]\n"); + usage(lock_method); exit(1); } -#ifdef MAIL_USE_MMDF - mmdf_init (argv[0]); +#ifdef HAVE_MMDF + if (lock_method == MMDF) + mmdf_init (argv[0]); #endif if (*outname == 0) fatal ("Destination file name is empty", 0); + VERBOSE(("checking access to output file\n")); /* Check access to output file. */ if (access (outname, F_OK) == 0 && access (outname, W_OK) != 0) pfatal_with_name (outname); @@ -320,34 +352,238 @@ if (access (inname, R_OK | W_OK) != 0) pfatal_with_name (inname); -#ifndef MAIL_USE_MMDF -#ifndef MAIL_USE_SYSTEM_LOCK - /* Use a lock file named after our first argument with .lock appended: - If it exists, the mail file is locked. */ - /* Note: this locking mechanism is *required* by the mailer - (on systems which use it) to prevent loss of mail. + + if (fork () == 0) + { + setuid (getuid ()); + + VERBOSE(("opening input file\n")); + + switch (lock_method) + { + case DOTLOCKING: + indesc = open (inname, O_RDONLY); + break; +#ifdef HAVE_LOCKF + case LOCKFING: + indesc = open (inname, O_RDWR); + break; +#endif +#ifdef HAVE_FLOCK + case FLOCKING: + indesc = open (inname, O_RDWR); + break; +#endif +#ifdef HAVE_LOCKING + case LOCKING: + indesc = open (inname, O_RDWR); + break; +#endif +#ifdef HAVE_MMDF + case MMDF: + indesc = lk_open (inname, O_RDONLY, 0, 0, 10); + break; +#endif + default: abort(); + } + + if (indesc < 0) + pfatal_with_name (inname); + +#ifdef HAVE_UMASK + /* In case movemail is setuid to root, make sure the user can + read the output file. */ + umask (umask (0) & 0333); +#endif + + outdesc = open (outname, O_WRONLY | O_CREAT | O_EXCL, 0666); + if (outdesc < 0) + pfatal_with_name (outname); + + VERBOSE(("locking input file\n")); - On systems that use a lock file, extracting the mail without locking - WILL occasionally cause loss of mail due to timing errors! + switch (lock_method) + { +#ifdef HAVE_LOCKF + case LOCKFING: + if (lockf (indesc, F_LOCK, 0) < 0) + pfatal_with_name (inname); + break; +#endif +#ifdef HAVE_FLOCK + case FLOCKING: + if (flock (indesc, LOCK_EX) < 0) + pfatal_with_name (inname); + break; +#endif +#ifdef HAVE_LOCKING + case LOCKING: + if (locking (indesc, LK_RLCK, -1L) < 0) + pfatal_with_name (inname); + break; +#endif + case DOTLOCKING: + lock_dot(inname); + break; + } + + VERBOSE(("copying input file to output file\n")); + + { + char buf[1024]; + + while (1) + { + nread = read (indesc, buf, sizeof buf); + if (nread != write (outdesc, buf, nread)) + { + int saved_errno = errno; + unlink (outname); + errno = saved_errno; + pfatal_with_name (outname); + } + if (nread < sizeof buf) + break; + } + } + +#ifdef HAVE_FSYNC + if (fsync (outdesc) < 0) + pfatal_and_delete (outname); +#endif + + /* Check to make sure no errors before we zap the inbox. */ + if (close (outdesc) != 0) + pfatal_and_delete (outname); + + VERBOSE(("deleting or truncating input file\n")); - So, if creation of the lock file fails - due to access permission on the mail spool directory, - you simply MUST change the permission - and/or make movemail a setgid program - so it can create lock files properly. + switch (lock_method) + { + case LOCKFING: + case FLOCKING: + case LOCKING: +#ifdef HAVE_FTRUNCATE + ftruncate (indesc, 0L); +#else + close (open (inname, O_CREAT | O_TRUNC | O_RDWR, 0666)); +#endif + close (indesc); + break; +#ifdef HAVE_MMDF + case MMDF: + lk_close (indesc, 0, 0, 0); + break; +#endif + case DOTLOCKING: + creat (inname, 0600); + break; + } + + exit (0); + } - You might also wish to verify that your system is one - which uses lock files for this purpose. Some systems use other methods. + wait (&status); + if (!WIFEXITED (status)) + exit (1); + else if (WEXITSTATUS (status) != 0) + exit (WEXITSTATUS (status)); + + if (lock_method == DOTLOCKING) + unlock_dot(inname); + +#endif /* not DISABLE_DIRECT_ACCESS */ + + return 0; +} + +static void +usage(int lock_method) +{ + printf ("Usage: movemail [-rvxkh] [-l lines ] [-m method ] [-i] inbox [-o] destfile [[-p] POP-password]\n"); + printf("where method is one of: dot"); +#ifdef HAVE_LOCKF + printf(", lockf"); +#endif +#ifdef HAVE_FLOCK + printf(", flock"); +#endif +#ifdef HAVE_MMDF + printf(", mmdf"); +#endif +#ifdef HAVE_LOCKING + printf(", locking"); +#endif + printf("\nDefault is: %s\n", unparse_lock_method(lock_method)); + +} - If your system uses the `flock' system call for mail locking, - define MAIL_USE_SYSTEM_LOCK in config.h or the s-*.h file - and recompile movemail. If the s- file for your system - should define MAIL_USE_SYSTEM_LOCK but does not, send a bug report - to bug-gnu-emacs@prep.ai.mit.edu so we can fix it. */ +static char * +unparse_lock_method(int lock_method) +{ + switch (lock_method) + { + case DOTLOCKING: return "dot"; + case FLOCKING: return "flock"; + case LOCKFING: return "lockf"; + case LOCKING: return "locking"; + case MMDF: return "mmdf"; + default: abort();return 0; + } +} - lockname = concat (inname, ".lock", ""); - tempname = (char *) xmalloc (strlen (inname) + strlen ("EXXXXXX") + 1); - strcpy (tempname, inname); +static int +parse_lock_method(char *method_name) +{ + if (!strcmp("dot", method_name) || !strcmp("file", method_name)) + return DOTLOCKING; +#ifdef HAVE_LOCKF + else if (!strcmp("lockf", method_name)) + return LOCKFING; +#endif +#ifdef HAVE_FLOCK + else if (!strcmp("flock", method_name)) + return FLOCKING; +#endif +#ifdef HAVE_MMDF + else if (!strcmp("mmdf", method_name)) + return MMDF; +#endif +#ifdef HAVE_LOCKING + else if (!strcmp("locking", method_name)) + return LOCKING; +#endif + else + fatal("invalid lock method: %s", method_name); + return 0; /* unreached */ +} + +static char * +dot_filename(char *filename) +{ + return concat (filename, ".lock", ""); +} + +static char *dotlock_filename = NULL; + +static void +lock_dot(char *filename) +{ + struct stat st; + long now; + int tem; + char *lockname, *p; + char *tempname; + int desc; + + dotlock_filename = (char *) xmalloc(strlen(filename) + 1); + + /* Use a lock file named after our first argument with .lock appended: + If it exists, the mail file is locked. */ + + lockname = dot_filename(filename); + tempname = (char *) xmalloc (strlen (filename) + strlen ("EXXXXXX") + 1); + strcpy (tempname, filename); p = tempname + strlen (tempname); while (p != tempname && !IS_DIRECTORY_SEP (p[-1])) p--; @@ -356,7 +592,7 @@ mktemp (tempname); unlink (tempname); - while (1) + for (;;) { /* Create the lock file, but not under the lock file name. */ /* Give up if cannot do that. */ @@ -387,132 +623,28 @@ unlink (lockname); } } - - delete_lockname = lockname; -#endif /* not MAIL_USE_SYSTEM_LOCK */ -#endif /* not MAIL_USE_MMDF */ - - if (fork () == 0) - { - setuid (getuid ()); - -#ifndef MAIL_USE_MMDF -#ifdef MAIL_USE_SYSTEM_LOCK - indesc = open (inname, O_RDWR); -#else /* if not MAIL_USE_SYSTEM_LOCK */ - indesc = open (inname, O_RDONLY); -#endif /* not MAIL_USE_SYSTEM_LOCK */ -#else /* MAIL_USE_MMDF */ - indesc = lk_open (inname, O_RDONLY, 0, 0, 10); -#endif /* MAIL_USE_MMDF */ - - if (indesc < 0) - pfatal_with_name (inname); - -#if defined (BSD) || defined (XENIX) - /* In case movemail is setuid to root, make sure the user can - read the output file. */ - /* This is desirable for all systems - but I don't want to assume all have the umask system call */ - umask (umask (0) & 0333); -#endif /* BSD or Xenix */ - outdesc = open (outname, O_WRONLY | O_CREAT | O_EXCL, 0666); - if (outdesc < 0) - pfatal_with_name (outname); -#ifdef MAIL_USE_SYSTEM_LOCK -#ifdef MAIL_USE_LOCKF - if (lockf (indesc, F_LOCK, 0) < 0) pfatal_with_name (inname); -#else /* not MAIL_USE_LOCKF */ -#ifdef XENIX - if (locking (indesc, LK_RLCK, 0L) < 0) pfatal_with_name (inname); -#else -#ifdef WINDOWSNT - if (locking (indesc, LK_RLCK, -1L) < 0) pfatal_with_name (inname); -#else - if (flock (indesc, LOCK_EX) < 0) pfatal_with_name (inname); -#endif -#endif -#endif /* not MAIL_USE_LOCKF */ -#endif /* MAIL_USE_SYSTEM_LOCK */ - - { - char buf[1024]; + strcpy(dotlock_filename, filename); +} - while (1) - { - nread = read (indesc, buf, sizeof buf); - if (nread != write (outdesc, buf, nread)) - { - int saved_errno = errno; - unlink (outname); - errno = saved_errno; - pfatal_with_name (outname); - } - if (nread < sizeof buf) - break; - } - } - -#ifdef BSD - if (fsync (outdesc) < 0) - pfatal_and_delete (outname); -#endif - - /* Check to make sure no errors before we zap the inbox. */ - if (close (outdesc) != 0) - pfatal_and_delete (outname); - -#ifdef MAIL_USE_SYSTEM_LOCK -#if defined (STRIDE) || defined (XENIX) || defined (WINDOWSNT) - /* Stride, xenix have file locking, but no ftruncate. This mess will do. */ - close (open (inname, O_CREAT | O_TRUNC | O_RDWR, 0666)); -#else - ftruncate (indesc, 0L); -#endif /* STRIDE or XENIX */ -#endif /* MAIL_USE_SYSTEM_LOCK */ +static void +unlock_dot(char *filename) +{ + unlink(dot_filename(filename)); +} -#ifdef MAIL_USE_MMDF - lk_close (indesc, 0, 0, 0); -#else - close (indesc); -#endif - -#ifndef MAIL_USE_SYSTEM_LOCK - /* Delete the input file; if we can't, at least get rid of its - contents. */ -#ifdef MAIL_UNLINK_SPOOL - /* This is generally bad to do, because it destroys the permissions - that were set on the file. Better to just empty the file. */ - if (unlink (inname) < 0 && errno != ENOENT) -#endif /* MAIL_UNLINK_SPOOL */ - creat (inname, 0600); -#endif /* not MAIL_USE_SYSTEM_LOCK */ +static void +maybe_unlock_dot(void) +{ + if (dotlock_filename) + unlock_dot(dotlock_filename); +} - exit (0); - } - - wait (&status); - if (!WIFEXITED (status)) - exit (1); - else if (WEXITSTATUS (status) != 0) - exit (WEXITSTATUS (status)); - -#if !defined (MAIL_USE_MMDF) && !defined (MAIL_USE_SYSTEM_LOCK) - unlink (lockname); -#endif /* not MAIL_USE_MMDF and not MAIL_USE_SYSTEM_LOCK */ - -#endif /* ! DISABLE_DIRECT_ACCESS */ - - return 0; -} - /* Print error message and exit. */ static void fatal (char *s1, char *s2) { - if (delete_lockname) - unlink (delete_lockname); + maybe_unlock_dot(); error (s1, s2, NULL); exit (1); } @@ -568,7 +700,7 @@ fatal ("virtual memory exhausted", 0); return result; } - + /* This is the guts of the interface to the Post Office Protocol. */ #ifdef MAIL_USE_POP @@ -605,7 +737,7 @@ FILE *mbf; popserver server; - VERBOSE(("opening server\r")); + VERBOSE(("opening server\n")); server = pop_open (0, user, password, POP_NO_GETPASS); if (! server) { @@ -613,7 +745,7 @@ return (1); } - VERBOSE(("stat'ing messages\r")); + VERBOSE(("stat'ing messages\n")); if (pop_stat (server, &nmsgs, &nbytes)) { error (pop_error, NULL, NULL); @@ -654,13 +786,13 @@ for (idx = 0; idx < nmsgs; idx++) { i = reverse ? nmsgs - idx : idx + 1; - VERBOSE(("checking message %d \r", i)); + VERBOSE(("checking message %d \n", i)); if (!regexp_pattern || pop_search_top (server, i, match_lines, regexp_pattern) == POP_RETRIEVED) { - VERBOSE(("retrieving message %d \r", i)); + VERBOSE(("retrieving message %d \n", i)); mbx_delimit_begin (mbf); if (pop_retr (server, i, mbx_write, mbf) != POP_RETRIEVED) { @@ -689,7 +821,7 @@ * directories have lost mail when over quota because these checks were * not made in previous versions of movemail. */ -#ifdef BSD +#ifdef HAVE_FSYNC if (fsync (mbfi) < 0) { error ("Error in fsync: %s", strerror (errno), NULL); @@ -709,7 +841,7 @@ { if (retrieved_list[i] == 1) { - VERBOSE(("deleting message %d \r", i)); + VERBOSE(("deleting message %d \n", i)); if (pop_delete (server, i)) { error (pop_error, NULL, NULL); @@ -877,7 +1009,7 @@ #endif /* MAIL_USE_POP */ - + #ifndef HAVE_STRERROR char * strerror (int errnum)