This is getmail.c in view mode; [Download] [Up]
/*-------------------------------*- C -*--------------------------------*\
* File: getmail.c
*
* Usage: getmail <infile> <outfile>
*
* typical usage:
* getmail /usr/spool/mail/$USER $HOME/Mail/#NewMail#
*
* -----------------------------------------------------------------------
* Moving mail from a maildir. Written in C to avoid a race condition.
*
* Two methods of file locking.
*
* 1) Write a lock file into the mail spool directory
* file = "/usr/mail/spool/username"
* lock = "/usr/mail/spool/username.lock"
*
* * Requires sgid (possible security hole) or a world-writeable
* spool directory (minor security hole - but not serious)
*
* 2) use fcntl () call.
*
* * Should always work provided the fcntl call supports file locking.
* This code was inspired by the Pine mailer implementation of flock.
*
* Depending on your system, you may need to define or comment out
* the following line:
\*----------------------------------------------------------------------*/
/* #define USE_LOCK_FILE */ /* mail spool is writeable */
/*----------------------------------------------------------------------*/
#include <config.h>
#include <stdio.h>
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <sys/file.h>
#include <time.h>
#ifdef SYSV
# include <sys/fcntl.h>
#endif
#ifndef F_WRLCK
# define USE_LOCK_FILE
#endif
static char *Program_Name;
static void usage (void)
{
fprintf (stderr, "%s: usage: %s infile outfile\n",
Program_Name, Program_Name);
exit (-1);
}
#ifdef USE_LOCK_FILE
static char Lock_File [256];
#endif
static void unlock_mail_file (void)
{
#ifdef USE_LOCK_FILE
unlink (Lock_File);
#endif
}
static void exit_error (char *msg, int l)
{
fprintf (stderr, "%s: %s\n", Program_Name, msg);
if (l) unlock_mail_file ();
exit (-1);
}
static int my_close (int fd)
{
while (-1 == close(fd))
{
#ifdef EINTR
if (errno == EINTR)
{
errno = 0;
sleep (1);
continue;
}
#endif
return -1;
}
return 0;
}
#ifdef USE_LOCK_FILE
static int lock_mail_file (char *file, int attempts)
{
struct stat s;
char buf[80];
int fd;
sprintf (Lock_File, "%s.lock", file);
while (attempts-- > 0)
{
if (stat (Lock_File, &s) < 0)
{
if (errno != ENOENT) exit_error ("stat failed.", 0);
fd = open (Lock_File, O_EXCL | O_CREAT, 0666);
if (fd >= 0)
{
sprintf (buf, "%d", getpid());
write (fd, buf, strlen(buf));
if (0 == my_close (fd))
return (0);
exit_error ("Unable to lock file. File system full.");
}
perror (NULL);
fprintf (stderr, "Attempt %d: can\'t lock <%s>",
attempts, Lock_File);
}
else if (time((time_t *) NULL) - s.st_ctime > 60)
{
unlock_mail_file ();
}
sleep (1);
}
return (-1);
}
#endif
#ifndef USE_LOCK_FILE
/* This chunk was inspired by the way the pine mailer implemented flock. */
static void our_flock (int fd)
{
struct flock f;
f.l_type = F_WRLCK;
f.l_pid = 0; /* not used for setting locks*/
/* set up rest of structure to lock whole file */
f.l_whence = 0; /* from beginning of file */
f.l_start = f.l_len = 0; /* entire file */
/* we are going to block */
if (fcntl (fd, F_SETLKW, (int) &f) == -1)
{
exit_error ("Unable to lock file.", 0);
}
}
#endif
static void mv_mail (char *from, char *to)
{
char buf[8192];
int fdfrom, fdto;
int n;
int flags;
#ifdef USE_LOCK_FILE
flags = O_RDONLY;
#else
flags = O_RDWR;
#endif
if ((fdfrom = open (from, flags, 0666)) < 0)
exit_error ("Unable to open input file.", 1);
#ifndef USE_LOCK_FILE
our_flock (fdfrom);
#endif
if ((fdto = open (to, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0)
exit_error ("Unable to create output file.", 1);
while ((n = read (fdfrom, buf, sizeof(buf))) > 0)
{
if (n != write (fdto, buf, n))
{
exit_error ("write failed.", 1);
}
}
if (-1 == my_close (fdto))
exit_error ("File system full. write failed.", 1);
my_close (fdfrom);
#ifndef TEST_DONT_UNLINK
if ( unlink (from) )
{
if ((fdfrom = open (from, O_WRONLY | O_CREAT | O_TRUNC, 0600)) >= 0)
close (fdfrom);
}
#endif
unlock_mail_file ();
}
int main (int argc, char **argv)
{
char *in = argv[1];
char *out = argv[2];
Program_Name = argv [0];
if (argc != 3) usage ();
#ifdef USE_LOCK_FILE
if (lock_mail_file (in, 60))
exit_error ("Unable to lock file.", 0);
#endif
mv_mail (in, out);
return (0);
}
/* /////////////////////// end of file (c source) ///////////////////// */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.