X-Git-Url: http://git.chise.org/gitweb/?p=chise%2Fxemacs-chise.git.1;a=blobdiff_plain;f=lib-src%2Fmovemail.c;h=941ada90596c1daeb76bc3cc0c05144a6be9bc65;hp=fd578c081390561ec7dbd07a9b1fe3c0f2e9a232;hb=716cfba952c1dc0d2cf5c968971f3780ba728a89;hpb=cb9f6f4eadc44f1becb32cbbd1db26449e347755 diff --git a/lib-src/movemail.c b/lib-src/movemail.c index fd578c0..941ada9 100644 --- a/lib-src/movemail.c +++ b/lib-src/movemail.c @@ -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. -/* 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. + Please mail bugs and suggestions to the XEmacs maintainer. +*/ - 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. */ +/* 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. + */ + +/* + * Mike Sperber reorganized + * everything that has to with locking in December 1999. + */ /* * Modified January, 1986 by Michael R. Gretzinger (Project Athena) @@ -56,10 +62,9 @@ Boston, MA 02111-1307, USA. */ #define NO_SHORTNAMES /* Tell config not to load remap.h */ #define DONT_ENCAPSULATE -#include <../src/config.h> +#include #include #include -#include #include #include #include "../src/sysfile.h" @@ -79,7 +84,7 @@ extern char *optarg; extern int optind, opterr; #ifndef HAVE_STRERROR -static char * strerror (int errnum); +char * strerror (int errnum); #endif /* HAVE_STRERROR */ #ifdef MSDOS @@ -107,7 +112,7 @@ static char * strerror (int errnum); #include #endif /* WINDOWSNT */ -#if defined (HAVE_UNISTD_H) || defined (USG) +#if defined (HAVE_UNISTD_H) #include #endif /* unistd.h */ #ifndef F_OK @@ -117,23 +122,15 @@ static char * strerror (int errnum); #define R_OK 4 #endif /* No F_OK */ -#if defined (HAVE_FCNTL_H) || defined (USG) +#if defined (HAVE_FCNTL_H) #include #endif /* fcntl.h */ -#if defined (XENIX) || defined (WINDOWSNT) +#ifdef HAVE_LOCKING #include #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 @@ -145,13 +142,15 @@ extern int lk_open (), lk_close (); 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)(), void *arg); +static int pop_retr (popserver server, int msgno, + int (*action)(char *, FILE *), FILE *arg); static int mbx_write (char *, FILE *); static int mbx_delimit_begin (FILE *); static int mbx_delimit_end (FILE *); @@ -160,9 +159,6 @@ static int pop_search_top (popserver server, int msgno, int lines, 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 @@ struct option longopts[] = { "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 @@ main (int argc, char *argv[]) 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 @@ main (int argc, char *argv[]) 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 @@ main (int argc, char *argv[]) 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,121 +352,83 @@ main (int argc, char *argv[]) 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. - - On systems that use a lock file, extracting the mail without locking - WILL occasionally cause loss of mail due to timing errors! - - 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. - - You might also wish to verify that your system is one - which uses lock files for this purpose. Some systems use other methods. - - 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. */ - - 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--; - *p = 0; - strcpy (p, "EXXXXXX"); - mktemp (tempname); - unlink (tempname); - while (1) + if (fork () == 0) { - /* Create the lock file, but not under the lock file name. */ - /* Give up if cannot do that. */ - desc = open (tempname, O_WRONLY | O_CREAT | O_EXCL, 0666); - if (desc < 0) - { - char *message = (char *) xmalloc (strlen (tempname) + 50); - sprintf (message, "%s--see source file lib-src/movemail.c", - tempname); - pfatal_with_name (message); - } - close (desc); + setuid (getuid ()); - tem = link (tempname, lockname); - unlink (tempname); - if (tem >= 0) - break; - sleep (1); + VERBOSE(("opening input file\n")); - /* If lock file is five minutes old, unlock it. - Five minutes should be good enough to cope with crashes - and wedgitude, and long enough to avoid being fooled - by time differences between machines. */ - if (stat (lockname, &st) >= 0) + switch (lock_method) { - now = time (0); - if (st.st_ctime < now - 300) - unlink (lockname); + 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(); } - } - - 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) +#ifdef HAVE_UMASK /* 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 */ +#endif + 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); + + VERBOSE(("locking input file\n")); + + 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 -#endif /* not MAIL_USE_LOCKF */ -#endif /* MAIL_USE_SYSTEM_LOCK */ + case DOTLOCKING: + lock_dot(inname); + break; + } + VERBOSE(("copying input file to output file\n")); + { char buf[1024]; @@ -453,7 +447,7 @@ main (int argc, char *argv[]) } } -#ifdef BSD +#ifdef HAVE_FSYNC if (fsync (outdesc) < 0) pfatal_and_delete (outname); #endif @@ -462,31 +456,29 @@ main (int argc, char *argv[]) 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 */ + VERBOSE(("deleting or truncating input file\n")); -#ifdef MAIL_USE_MMDF - lk_close (indesc, 0, 0, 0); + switch (lock_method) + { + case LOCKFING: + case FLOCKING: + case LOCKING: +#ifdef HAVE_FTRUNCATE + ftruncate (indesc, 0L); #else - close (indesc); + close (open (inname, O_CREAT | O_TRUNC | O_RDWR, 0666)); #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 */ + close (indesc); + break; +#ifdef HAVE_MMDF + case MMDF: + lk_close (indesc, 0, 0, 0); + break; +#endif + case DOTLOCKING: + creat (inname, 0600); + break; + } exit (0); } @@ -497,22 +489,162 @@ main (int argc, char *argv[]) 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 */ + if (lock_method == DOTLOCKING) + unlock_dot(inname); -#endif /* ! DISABLE_DIRECT_ACCESS */ +#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)); + +} + +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; + } +} + +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--; + *p = 0; + strcpy (p, "EXXXXXX"); + mktemp (tempname); + unlink (tempname); + + for (;;) + { + /* Create the lock file, but not under the lock file name. */ + /* Give up if cannot do that. */ + desc = open (tempname, O_WRONLY | O_CREAT | O_EXCL, 0666); + if (desc < 0) + { + char *message = (char *) xmalloc (strlen (tempname) + 50); + sprintf (message, "%s--see source file lib-src/movemail.c", + tempname); + pfatal_with_name (message); + } + close (desc); + + tem = link (tempname, lockname); + unlink (tempname); + if (tem >= 0) + break; + sleep (1); + + /* If lock file is five minutes old, unlock it. + Five minutes should be good enough to cope with crashes + and wedgitude, and long enough to avoid being fooled + by time differences between machines. */ + if (stat (lockname, &st) >= 0) + { + now = time (0); + if (st.st_ctime < now - 300) + unlink (lockname); + } + } + strcpy(dotlock_filename, filename); +} + +static void +unlock_dot(char *filename) +{ + unlink(dot_filename(filename)); +} + +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) { - if (delete_lockname) - unlink (delete_lockname); + maybe_unlock_dot(); error (s1, s2, NULL); exit (1); } @@ -568,7 +700,7 @@ xmalloc (unsigned int size) 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 @@ popmail (char *user, char *outfile, char *password) 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 @@ popmail (char *user, char *outfile, char *password) return (1); } - VERBOSE(("stat'ing messages\r")); + VERBOSE(("stat'ing messages\n")); if (pop_stat (server, &nmsgs, &nbytes)) { error (pop_error, NULL, NULL); @@ -639,7 +771,7 @@ popmail (char *user, char *outfile, char *password) return (1); } #if !defined(__CYGWIN32__) && !defined(WINDOWSNT) - fchown (mbfi, getuid (), -1); + fchown (mbfi, getuid (), (gid_t) -1); #endif if ((mbf = fdopen (mbfi, "wb")) == NULL) @@ -654,13 +786,13 @@ popmail (char *user, char *outfile, char *password) 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 @@ popmail (char *user, char *outfile, char *password) * 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 @@ popmail (char *user, char *outfile, char *password) { 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); @@ -731,7 +863,7 @@ popmail (char *user, char *outfile, char *password) } static int -pop_retr (popserver server, int msgno, int (*action)(), void *arg) +pop_retr (popserver server, int msgno, int (*action)(char *, FILE *), FILE *arg) { char *line; int ret; @@ -877,9 +1009,9 @@ compile_regex (char* pattern) #endif /* MAIL_USE_POP */ - + #ifndef HAVE_STRERROR -static char * +char * strerror (int errnum) { extern char *sys_errlist[];