/* movemail foo bar -- move file foo to file bar,
locking file foo the way /bin/mail respects.
- Copyright (C) 1986, 1992, 1993, 1994, 1996, 1999, 2001, 2002, 2003, 2004,
- 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+
+Copyright (C) 1986, 1992-1994, 1996, 1999, 2001-2012
+ Free Software Foundation, Inc.
This file is part of GNU Emacs.
/* 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
+ use flock/lockf 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.
#include <time.h>
#include <getopt.h>
-#ifdef HAVE_UNISTD_H
#include <unistd.h>
-#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
+#include <string.h>
#include "syswait.h"
#ifdef MAIL_USE_POP
#include "pop.h"
#undef access
#endif /* MSDOS */
-#ifndef DIRECTORY_SEP
-#define DIRECTORY_SEP '/'
-#endif
-#ifndef IS_DIRECTORY_SEP
-#define IS_DIRECTORY_SEP(_c_) ((_c_) == DIRECTORY_SEP)
-#endif
-
#ifdef WINDOWSNT
#include "ntlib.h"
#undef access
#include <sys/locking.h>
#endif
+/* If your system uses the `flock' or `lockf' system call for mail locking,
+ define MAIL_USE_SYSTEM_LOCK. If your system type should always define
+ MAIL_USE_LOCKF or MAIL_USE_FLOCK but configure does not do this,
+ please make a bug report. */
+
#ifdef MAIL_USE_LOCKF
#define MAIL_USE_SYSTEM_LOCK
#endif
files appear in. */
#ifdef MAILDIR
#define MAIL_USE_MAILLOCK
-static char *mail_spool_name ();
+static char *mail_spool_name (char *);
#endif
#endif
-char *strerror ();
-#ifdef HAVE_INDEX
-extern char *index __P ((const char *, int));
-#endif
-#ifdef HAVE_RINDEX
-extern char *rindex __P((const char *, int));
+static _Noreturn void fatal (const char *s1, const char *s2, const char *s3);
+static void error (const char *s1, const char *s2, const char *s3);
+static _Noreturn void pfatal_with_name (char *name);
+static _Noreturn void pfatal_and_delete (char *name);
+#ifdef MAIL_USE_POP
+static int popmail (char *mailbox, char *outfile, int preserve, char *password, int reverse_order);
+static int pop_retr (popserver server, int msgno, FILE *arg);
+static int mbx_write (char *line, int len, FILE *mbf);
+static int mbx_delimit_begin (FILE *mbf);
+static int mbx_delimit_end (FILE *mbf);
#endif
-void fatal ();
-void error ();
-void pfatal_with_name ();
-void pfatal_and_delete ();
-char *concat ();
-long *xmalloc ();
-int popmail ();
-int pop_retr ();
-int mbx_write ();
-int mbx_delimit_begin ();
-int mbx_delimit_end ();
+#if (defined MAIL_USE_MAILLOCK \
+ || (!defined DISABLE_DIRECT_ACCESS && !defined MAIL_USE_MMDF \
+ && !defined MAIL_USE_SYSTEM_LOCK))
+/* Like malloc but get fatal error if memory is exhausted. */
+
+static void *
+xmalloc (size_t size)
+{
+ void *result = malloc (size);
+ if (!result)
+ fatal ("virtual memory exhausted", 0, 0);
+ return result;
+}
+#endif
/* Nonzero means this is name of a lock file to delete on fatal error. */
-char *delete_lockname;
+static char *delete_lockname;
int
-main (argc, argv)
- int argc;
- char **argv;
+main (int argc, char **argv)
{
char *inname, *outname;
int indesc, outdesc;
- int nread;
- int status;
+ ssize_t nread;
+ int wait_status;
int c, preserve_mail = 0;
#ifndef MAIL_USE_SYSTEM_LOCK
struct stat st;
- long now;
int tem;
- char *lockname, *p;
+ char *lockname;
char *tempname;
+ size_t inname_len, inname_dirlen;
int desc;
#endif /* not MAIL_USE_SYSTEM_LOCK */
# define ARGSTR "p"
#endif /* MAIL_USE_POP */
- uid_t real_gid = getgid();
- uid_t priv_gid = getegid();
+ uid_t real_gid = getgid ();
+ uid_t priv_gid = getegid ();
#ifdef WINDOWSNT
/* Ensure all file i/o is in binary mode. */
#ifndef MAIL_USE_SYSTEM_LOCK
#ifdef MAIL_USE_MAILLOCK
spool_name = mail_spool_name (inname);
- if (! spool_name)
+ if (spool_name)
+ {
+#ifdef lint
+ lockname = 0;
+#endif
+ }
+ else
#endif
{
/* Use a lock file named after our first argument with .lock appended:
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, 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);
+ You might also wish to verify that your system is one which
+ uses lock files for this purpose. Some systems use other methods. */
+
+ inname_len = strlen (inname);
+ lockname = xmalloc (inname_len + sizeof ".lock");
+ strcpy (lockname, inname);
+ strcpy (lockname + inname_len, ".lock");
+ for (inname_dirlen = inname_len;
+ inname_dirlen && !IS_DIRECTORY_SEP (inname[inname_dirlen - 1]);
+ inname_dirlen--)
+ continue;
+ tempname = xmalloc (inname_dirlen + sizeof "EXXXXXX");
while (1)
{
/* 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);
+
+ memcpy (tempname, inname, inname_dirlen);
+ strcpy (tempname + inname_dirlen, "EXXXXXX");
+#ifdef HAVE_MKSTEMP
+ desc = mkstemp (tempname);
+#else
+ mktemp (tempname);
+ if (!*tempname)
+ desc = -1;
+ else
+ {
+ unlink (tempname);
+ desc = open (tempname, O_WRONLY | O_CREAT | O_EXCL, 0600);
+ }
+#endif
if (desc < 0)
{
- char *message = (char *) xmalloc (strlen (tempname) + 50);
- sprintf (message, "creating %s, which would become the lock file",
- tempname);
- pfatal_with_name (message);
+ int mkstemp_errno = errno;
+ error ("error while creating what would become the lock file",
+ 0, 0);
+ errno = mkstemp_errno;
+ pfatal_with_name (tempname);
}
close (desc);
by time differences between machines. */
if (stat (lockname, &st) >= 0)
{
- now = time (0);
+ time_t now = time (0);
if (st.st_ctime < now - 300)
unlink (lockname);
}
int lockcount = 0;
int status = 0;
#if defined (MAIL_USE_MAILLOCK) && defined (HAVE_TOUCHLOCK)
- time_t touched_lock, now;
+ time_t touched_lock;
+# ifdef lint
+ touched_lock = 0;
+# endif
#endif
- if (setuid (getuid ()) < 0 || setegid (real_gid) < 0)
+ if (setuid (getuid ()) < 0 || setregid (-1, real_gid) < 0)
fatal ("Failed to drop privileges", 0, 0);
#ifndef MAIL_USE_MMDF
if (outdesc < 0)
pfatal_with_name (outname);
- if (setegid (priv_gid) < 0)
+ if (setregid (-1, priv_gid) < 0)
fatal ("Failed to regain privileges", 0, 0);
/* This label exists so we can retry locking
#if defined (MAIL_USE_MAILLOCK) && defined (HAVE_TOUCHLOCK)
if (spool_name)
{
- now = time (0);
+ time_t now = time (0);
if (now - touched_lock > 60)
{
touchlock ();
#endif
/* Prevent symlink attacks truncating other users' mailboxes */
- if (setegid (real_gid) < 0)
+ if (setregid (-1, real_gid) < 0)
fatal ("Failed to drop privileges", 0, 0);
/* Check to make sure no errors before we zap the inbox. */
#ifdef MAIL_USE_SYSTEM_LOCK
if (! preserve_mail)
{
- ftruncate (indesc, 0L);
+ if (ftruncate (indesc, 0L) != 0)
+ pfatal_with_name (inname);
}
#endif /* MAIL_USE_SYSTEM_LOCK */
#endif /* not MAIL_USE_SYSTEM_LOCK */
/* End of mailbox truncation */
- if (setegid (priv_gid) < 0)
+ if (setregid (-1, priv_gid) < 0)
fatal ("Failed to regain privileges", 0, 0);
#ifdef MAIL_USE_MAILLOCK
exit (EXIT_SUCCESS);
}
- wait (&status);
- if (!WIFEXITED (status))
+ wait (&wait_status);
+ if (!WIFEXITED (wait_status))
exit (EXIT_FAILURE);
- else if (WRETCODE (status) != 0)
- exit (WRETCODE (status));
+ else if (WEXITSTATUS (wait_status) != 0)
+ exit (WEXITSTATUS (wait_status));
#if !defined (MAIL_USE_MMDF) && !defined (MAIL_USE_SYSTEM_LOCK)
#ifdef MAIL_USE_MAILLOCK
string-comparing the two paths, because one or both of them might
be symbolic links pointing to some other directory. */
static char *
-mail_spool_name (inname)
- char *inname;
+mail_spool_name (char *inname)
{
struct stat stat1, stat2;
char *indir, *fname;
int status;
- if (! (fname = rindex (inname, '/')))
+ if (! (fname = strrchr (inname, '/')))
return NULL;
fname++;
if (stat (MAILDIR, &stat1) < 0)
return NULL;
- indir = (char *) xmalloc (fname - inname + 1);
- strncpy (indir, inname, fname - inname);
+ indir = xmalloc (fname - inname + 1);
+ memcpy (indir, inname, fname - inname);
indir[fname-inname] = '\0';
\f
/* Print error message and exit. */
-void
-fatal (s1, s2, s3)
- char *s1, *s2, *s3;
+static void
+fatal (const char *s1, const char *s2, const char *s3)
{
if (delete_lockname)
unlink (delete_lockname);
/* Print error message. `s1' is printf control string, `s2' and `s3'
are args for it or null. */
-void
-error (s1, s2, s3)
- char *s1, *s2, *s3;
+static void
+error (const char *s1, const char *s2, const char *s3)
{
fprintf (stderr, "movemail: ");
if (s3)
else if (s2)
fprintf (stderr, s1, s2);
else
- fprintf (stderr, s1);
+ fprintf (stderr, "%s", s1);
fprintf (stderr, "\n");
}
-void
-pfatal_with_name (name)
- char *name;
+static void
+pfatal_with_name (char *name)
{
fatal ("%s for %s", strerror (errno), name);
}
-void
-pfatal_and_delete (name)
- char *name;
+static void
+pfatal_and_delete (char *name)
{
char *s = strerror (errno);
unlink (name);
fatal ("%s for %s", s, name);
}
-
-/* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
-
-char *
-concat (s1, s2, s3)
- char *s1, *s2, *s3;
-{
- int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
- char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
-
- strcpy (result, s1);
- strcpy (result + len1, s2);
- strcpy (result + len1 + len2, s3);
- *(result + len1 + len2 + len3) = 0;
-
- return result;
-}
-
-/* Like malloc but get fatal error if memory is exhausted. */
-
-long *
-xmalloc (size)
- unsigned size;
-{
- long *result = (long *) malloc (size);
- if (!result)
- fatal ("virtual memory exhausted", 0, 0);
- return result;
-}
\f
/* This is the guts of the interface to the Post Office Protocol. */
#define NOTOK (-1)
#define OK 0
-#define DONE 1
-
-char *progname;
-FILE *sfi;
-FILE *sfo;
-char ibuffer[BUFSIZ];
-char obuffer[BUFSIZ];
-char Errmsg[200]; /* POP errors, at least, can exceed
+
+static char Errmsg[200]; /* POP errors, at least, can exceed
the original length of 80. */
/*
* Return a value suitable for passing to `exit'.
*/
-int
-popmail (mailbox, outfile, preserve, password, reverse_order)
- char *mailbox;
- char *outfile;
- int preserve;
- char *password;
- int reverse_order;
+static int
+popmail (char *mailbox, char *outfile, int preserve, char *password, int reverse_order)
{
int nmsgs, nbytes;
register int i;
int mbfi;
FILE *mbf;
- char *getenv ();
+ char *getenv (const char *);
popserver server;
int start, end, increment;
char *user, *hostname;
user = mailbox;
- if ((hostname = index(mailbox, ':')))
+ if ((hostname = strchr (mailbox, ':')))
*hostname++ = '\0';
server = pop_open (hostname, user, password, POP_NO_GETPASS);
error ("Error in open: %s, %s", strerror (errno), outfile);
return EXIT_FAILURE;
}
- fchown (mbfi, getuid (), -1);
+
+ if (fchown (mbfi, getuid (), -1) != 0)
+ {
+ int fchown_errno = errno;
+ struct stat st;
+ if (fstat (mbfi, &st) != 0 || st.st_uid != getuid ())
+ {
+ pop_close (server);
+ error ("Error in fchown: %s, %s", strerror (fchown_errno), outfile);
+ return EXIT_FAILURE;
+ }
+ }
if ((mbf = fdopen (mbfi, "wb")) == NULL)
{
return EXIT_SUCCESS;
}
-int
-pop_retr (server, msgno, arg)
- popserver server;
- int msgno;
- FILE *arg;
+static int
+pop_retr (popserver server, int msgno, FILE *arg)
{
- extern char *strerror ();
char *line;
int ret;
if (pop_retrieve_first (server, msgno, &line))
{
- char *error = concat ("Error from POP server: ", pop_error, "");
- strncpy (Errmsg, error, sizeof (Errmsg));
- Errmsg[sizeof (Errmsg)-1] = '\0';
- free(error);
+ snprintf (Errmsg, sizeof Errmsg, "Error from POP server: %s", pop_error);
return (NOTOK);
}
if (ret)
{
- char *error = concat ("Error from POP server: ", pop_error, "");
- strncpy (Errmsg, error, sizeof (Errmsg));
- Errmsg[sizeof (Errmsg)-1] = '\0';
- free(error);
+ snprintf (Errmsg, sizeof Errmsg, "Error from POP server: %s", pop_error);
return (NOTOK);
}
return (OK);
}
-/* Do this as a macro instead of using strcmp to save on execution time. */
-#define IS_FROM_LINE(a) ((a[0] == 'F') \
- && (a[1] == 'r') \
- && (a[2] == 'o') \
- && (a[3] == 'm') \
- && (a[4] == ' '))
-
-int
-mbx_write (line, len, mbf)
- char *line;
- int len;
- FILE *mbf;
+static int
+mbx_write (char *line, int len, FILE *mbf)
{
#ifdef MOVEMAIL_QUOTE_POP_FROM_LINES
+ /* Do this as a macro instead of using strcmp to save on execution time. */
+ # define IS_FROM_LINE(a) ((a[0] == 'F') \
+ && (a[1] == 'r') \
+ && (a[2] == 'o') \
+ && (a[3] == 'm') \
+ && (a[4] == ' '))
if (IS_FROM_LINE (line))
{
if (fputc ('>', mbf) == EOF)
return (OK);
}
-int
-mbx_delimit_begin (mbf)
- FILE *mbf;
+static int
+mbx_delimit_begin (FILE *mbf)
{
time_t now;
struct tm *ltime;
return (OK);
}
-int
-mbx_delimit_end (mbf)
- FILE *mbf;
+static int
+mbx_delimit_end (FILE *mbf)
{
if (putc ('\n', mbf) == EOF)
return (NOTOK);
}
#endif /* MAIL_USE_POP */
-\f
-#ifndef HAVE_STRERROR
-char *
-strerror (errnum)
- int errnum;
-{
- extern char *sys_errlist[];
- extern int sys_nerr;
-
- if (errnum >= 0 && errnum < sys_nerr)
- return sys_errlist[errnum];
- return (char *) "Unknown error";
-}
-
-#endif /* ! HAVE_STRERROR */
-
-/* arch-tag: 1c323112-41fe-4fe5-8de9-494de631f73f
- (do not change this comment) */
-
-/* movemail.c ends here */