Mercurial > hg > xemacs-beta
diff lib-src/movemail.c @ 412:697ef44129c6 r21-2-14
Import from CVS: tag r21-2-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:20:41 +0200 |
parents | de805c49cfc1 |
children | 11054d720c21 |
line wrap: on
line diff
--- a/lib-src/movemail.c Mon Aug 13 11:19:22 2007 +0200 +++ b/lib-src/movemail.c Mon Aug 13 11:20:41 2007 +0200 @@ -1,41 +1,35 @@ /* movemail foo bar -- move file foo to file bar, - locking file foo. + locking file foo the way /bin/mail respects. Copyright (C) 1986, 1992, 1993, 1994, 1996 Free Software Foundation, Inc. -This file is part of XEmacs. +This file is part of GNU Emacs. -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 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 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. +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. You should have received a copy of the GNU General Public License -along with XEmacs; see the file COPYING. If not, write to +along with GNU Emacs; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. - - Please mail bugs and suggestions to the XEmacs maintainer. -*/ +Boston, MA 02111-1307, USA. */ -/* 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. - */ +/* 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. -/* - * Mike Sperber <sperber@informatik.uni-tuebingen.de> reorganized - * everything that has to with locking in December 1999. - */ + 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. */ /* * Modified January, 1986 by Michael R. Gretzinger (Project Athena) @@ -62,14 +56,14 @@ #define NO_SHORTNAMES /* Tell config not to load remap.h */ #define DONT_ENCAPSULATE -#include <config.h> +#include <../src/config.h> #include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <errno.h> #include "../src/sysfile.h" #include "../src/syswait.h" -#ifndef WIN32_NATIVE +#ifndef WINDOWSNT #include "../src/systime.h" #endif #include <stdlib.h> @@ -87,6 +81,10 @@ char * strerror (int errnum); #endif /* HAVE_STRERROR */ +#ifdef MSDOS +#undef access +#endif /* MSDOS */ + #ifndef DIRECTORY_SEP #define DIRECTORY_SEP '/' #endif @@ -94,7 +92,7 @@ #define IS_DIRECTORY_SEP(_c_) ((_c_) == DIRECTORY_SEP) #endif -#ifdef WIN32_NATIVE +#ifdef WINDOWSNT #undef access #undef unlink #define fork() 0 @@ -106,9 +104,9 @@ properly - make sure it does before you enable this! */ #define DISABLE_DIRECT_ACCESS #include <io.h> -#endif /* WIN32_NATIVE */ +#endif /* WINDOWSNT */ -#if defined (HAVE_UNISTD_H) +#if defined (HAVE_UNISTD_H) || defined (USG) #include <unistd.h> #endif /* unistd.h */ #ifndef F_OK @@ -118,15 +116,23 @@ #define R_OK 4 #endif /* No F_OK */ -#if defined (HAVE_FCNTL_H) +#if defined (HAVE_FCNTL_H) || defined (USG) #include <fcntl.h> #endif /* fcntl.h */ -#ifdef HAVE_LOCKING +#if defined (XENIX) || defined (WINDOWSNT) #include <sys/locking.h> #endif -#ifdef HAVE_MMDF +#ifdef MAIL_USE_LOCKF +#define MAIL_USE_SYSTEM_LOCK +#endif + +#ifdef MAIL_USE_FLOCK +#define MAIL_USE_SYSTEM_LOCK +#endif + +#ifdef MAIL_USE_MMDF extern int lk_open (), lk_close (); #endif @@ -138,15 +144,13 @@ 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 *); static long *xmalloc (unsigned int); #ifdef MAIL_USE_POP static int popmail (char *, char *, char *); -static int pop_retr (popserver server, int msgno, - int (*action)(char *, FILE *), FILE *arg); +static int pop_retr (popserver server, int msgno, int (*action)(), void *arg); static int mbx_write (char *, FILE *); static int mbx_delimit_begin (FILE *); static int mbx_delimit_end (FILE *); @@ -155,6 +159,9 @@ 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; @@ -176,37 +183,10 @@ { "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 - -#ifndef DISABLE_DIRECT_ACCESS -static void lock_dot(char *); -#endif -static void unlock_dot(char *); -static int parse_lock_method(char *); -static char *unparse_lock_method(int); - int main (int argc, char *argv[]) { @@ -217,23 +197,23 @@ int status; #endif - int lock_method = DEFAULT_LOCKING; - - char *maybe_lock_env; +#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 */ - 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); - } + delete_lockname = 0; - for (;;) + while (1) { #ifdef MAIL_USE_POP - char* optstring = "i:o:m:p:l:r:xvhk"; + char* optstring = "i:o:p:l:r:xvk"; #else - char* optstring = "i:o:m:vh"; + char* optstring = "i:o:v"; #endif int opt = getopt_long (argc, argv, optstring, longopts, 0); @@ -274,16 +254,7 @@ regexp_pattern = compile_regex (optarg); break; #endif - - case 'm': - lock_method = parse_lock_method(optarg); - break; - case 'h': - usage(lock_method); - exit(0); - case 'v': - verbose = 1; - break; + case 'v': verbose = 1; break; } } @@ -300,19 +271,17 @@ if (!inname || !outname) { - usage(lock_method); + fprintf (stderr, "Usage: movemail [-rvxk] [-l lines ] [-i] inbox [-o] destfile [[-p] POP-password]\n"); exit(1); } -#ifdef HAVE_MMDF - if (lock_method == MMDF) - mmdf_init (argv[0]); +#ifdef MAIL_USE_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); @@ -339,7 +308,7 @@ exit (retcode); } -#ifndef WIN32_NATIVE +#ifndef WINDOWSNT setuid (getuid ()); #endif #endif /* MAIL_USE_POP */ @@ -350,239 +319,34 @@ if (access (inname, R_OK | W_OK) != 0) pfatal_with_name (inname); - - 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")); +#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. - 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")); + 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) - { - 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); - } + 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. - 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)); - -} + You might also wish to verify that your system is one + which uses lock files for this purpose. Some systems use other methods. -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; - } -} + 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 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; - -#ifndef DISABLE_DIRECT_ACCESS -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); + lockname = concat (inname, ".lock", ""); + tempname = (char *) xmalloc (strlen (inname) + strlen ("EXXXXXX") + 1); + strcpy (tempname, inname); p = tempname + strlen (tempname); while (p != tempname && !IS_DIRECTORY_SEP (p[-1])) p--; @@ -591,7 +355,7 @@ mktemp (tempname); unlink (tempname); - for (;;) + while (1) { /* Create the lock file, but not under the lock file name. */ /* Give up if cannot do that. */ @@ -622,29 +386,132 @@ unlink (lockname); } } - strcpy(dotlock_filename, filename); -} -#endif /* not DISABLE_DIRECT_ACCESS */ + + 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]; -static void -unlock_dot(char *filename) -{ - unlink(dot_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 */ + +#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 */ + + 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; } - -static void -maybe_unlock_dot(void) -{ - if (dotlock_filename) - unlock_dot(dotlock_filename); -} - + /* Print error message and exit. */ static void fatal (char *s1, char *s2) { - maybe_unlock_dot(); + if (delete_lockname) + unlink (delete_lockname); error (s1, s2, NULL); exit (1); } @@ -700,12 +567,12 @@ fatal ("virtual memory exhausted", 0); return result; } - + /* This is the guts of the interface to the Post Office Protocol. */ #ifdef MAIL_USE_POP -#ifndef WIN32_NATIVE +#ifndef WINDOWSNT #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> @@ -714,7 +581,7 @@ #include <winsock.h> #endif #include <stdio.h> -#include "../src/syspwd.h" +#include <pwd.h> #define POP_ERROR (-1) #define POP_RETRIEVED (0) @@ -737,7 +604,7 @@ FILE *mbf; popserver server; - VERBOSE(("opening server\n")); + VERBOSE(("opening server\r")); server = pop_open (0, user, password, POP_NO_GETPASS); if (! server) { @@ -745,7 +612,7 @@ return (1); } - VERBOSE(("stat'ing messages\n")); + VERBOSE(("stat'ing messages\r")); if (pop_stat (server, &nmsgs, &nbytes)) { error (pop_error, NULL, NULL); @@ -770,8 +637,8 @@ error ("Error in open: %s, %s", strerror (errno), outfile); return (1); } -#if !defined(CYGWIN) && !defined(WIN32_NATIVE) - fchown (mbfi, getuid (), (gid_t) -1); +#if !defined(__CYGWIN32__) && !defined(WINDOWSNT) + fchown (mbfi, getuid (), -1); #endif if ((mbf = fdopen (mbfi, "wb")) == NULL) @@ -786,13 +653,13 @@ for (idx = 0; idx < nmsgs; idx++) { i = reverse ? nmsgs - idx : idx + 1; - VERBOSE(("checking message %d \n", i)); + VERBOSE(("checking message %d \r", i)); if (!regexp_pattern || pop_search_top (server, i, match_lines, regexp_pattern) == POP_RETRIEVED) { - VERBOSE(("retrieving message %d \n", i)); + VERBOSE(("retrieving message %d \r", i)); mbx_delimit_begin (mbf); if (pop_retr (server, i, mbx_write, mbf) != POP_RETRIEVED) { @@ -821,7 +688,7 @@ * directories have lost mail when over quota because these checks were * not made in previous versions of movemail. */ -#ifdef HAVE_FSYNC +#ifdef BSD if (fsync (mbfi) < 0) { error ("Error in fsync: %s", strerror (errno), NULL); @@ -841,7 +708,7 @@ { if (retrieved_list[i] == 1) { - VERBOSE(("deleting message %d \n", i)); + VERBOSE(("deleting message %d \r", i)); if (pop_delete (server, i)) { error (pop_error, NULL, NULL); @@ -863,7 +730,7 @@ } static int -pop_retr (popserver server, int msgno, int (*action)(char *, FILE *), FILE *arg) +pop_retr (popserver server, int msgno, int (*action)(), void *arg) { char *line; int ret; @@ -1009,7 +876,7 @@ #endif /* MAIL_USE_POP */ - + #ifndef HAVE_STRERROR char * strerror (int errnum)