home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 4 / FreshFish_May-June1994.bin / bbs / gnu / emacs-18.59-bin.lha / lib / emacs / 18.59 / etc / movemail.c < prev    next >
C/C++ Source or Header  |  1992-05-07  |  16KB  |  753 lines

  1. /* movemail foo bar -- move file foo to file bar,
  2.    locking file foo the way /bin/mail respects.
  3.    Copyright (C) 1986 Free Software Foundation, Inc.
  4.  
  5. This file is part of GNU Emacs.
  6.  
  7. GNU Emacs is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 1, or (at your option)
  10. any later version.
  11.  
  12. GNU Emacs is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with GNU Emacs; see the file COPYING.  If not, write to
  19. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  20.  
  21. /* Important notice: defining MAIL_USE_FLOCK *will cause loss of mail*
  22.    if you do it on a system that does not normally use flock as its way of
  23.    interlocking access to inbox files.  The setting of MAIL_USE_FLOCK
  24.    *must agree* with the system's own conventions.
  25.    It is not a choice that is up to you.
  26.  
  27.    So, if your system uses lock files rather than flock, then the only way
  28.    you can get proper operation is to enable movemail to write lockfiles there.
  29.    This means you must either give that directory access modes
  30.    that permit everyone to write lockfiles in it, or you must make movemail
  31.    a setuid or setgid program.  */
  32.  
  33. /*
  34.  * Modified January, 1986 by Michael R. Gretzinger (Project Athena)
  35.  *
  36.  * Added POP (Post Office Protocol) service.  When compiled -DPOP
  37.  * movemail will accept input filename arguments of the form
  38.  * "po:username".  This will cause movemail to open a connection to
  39.  * a pop server running on $MAILHOST (environment variable).  Movemail
  40.  * must be setuid to root in order to work with POP.
  41.  * 
  42.  * New module: popmail.c
  43.  * Modified routines:
  44.  *    main - added code within #ifdef MAIL_USE_POP; added setuid (getuid ())
  45.  *        after POP code. 
  46.  * New routines in movemail.c:
  47.  *    get_errmsg - return pointer to system error message
  48.  *
  49.  */
  50.  
  51. #include <sys/types.h>
  52. #include <sys/stat.h>
  53. #include <sys/file.h>
  54. #include <errno.h>
  55. #define NO_SHORTNAMES   /* Tell config not to load remap.h */
  56. #include "../src/config.h"
  57.  
  58. #ifdef USG
  59. #include <fcntl.h>
  60. #include <unistd.h>
  61. #ifndef F_OK
  62. #define F_OK 0
  63. #define X_OK 1
  64. #define W_OK 2
  65. #define R_OK 4
  66. #endif
  67. #endif /* USG */
  68.  
  69. #ifdef XENIX
  70. #include <sys/locking.h>
  71. #endif
  72.  
  73. #ifdef MAIL_USE_MMDF
  74. extern int lk_open (), lk_close ();
  75. #endif
  76.  
  77. /* Cancel substitutions made by config.h for Emacs.  */
  78. #undef open
  79. #undef read
  80. #undef write
  81. #undef close
  82.  
  83. char *concat ();
  84. extern int errno;
  85.  
  86. /* Nonzero means this is name of a lock file to delete on fatal error.  */
  87. char *delete_lockname;
  88.  
  89. main (argc, argv)
  90.      int argc;
  91.      char **argv;
  92. {
  93.   char *inname, *outname;
  94.   int indesc, outdesc;
  95.   char buf[1024];
  96.   int nread;
  97.  
  98. #ifndef MAIL_USE_FLOCK
  99.   struct stat st;
  100.   long now;
  101.   int tem;
  102.   char *lockname, *p;
  103.   char *tempname;
  104.   int desc;
  105. #endif /* not MAIL_USE_FLOCK */
  106.  
  107.   delete_lockname = 0;
  108.  
  109.   if (argc < 3)
  110.     fatal ("two arguments required");
  111.  
  112.   inname = argv[1];
  113.   outname = argv[2];
  114.  
  115. #ifdef MAIL_USE_MMDF
  116.   mmdf_init (argv[0]);
  117. #endif
  118.  
  119.   /* Check access to output file.  */
  120.   if (access (outname, F_OK) == 0 && access (outname, W_OK) != 0)
  121.     pfatal_with_name (outname);
  122.  
  123.   /* Also check that outname's directory is writeable to the real uid.  */
  124.   {
  125.     char *buf = (char *) malloc (strlen (outname) + 1);
  126.     char *p, q;
  127.     strcpy (buf, outname);
  128.     p = buf + strlen (buf);
  129.     while (p > buf && p[-1] != '/')
  130.       *--p = 0;
  131.     if (p == buf)
  132.       *p++ = '.';
  133.     if (access (buf, W_OK) != 0)
  134.       pfatal_with_name (buf);
  135.     free (buf);
  136.   }
  137.  
  138. #ifdef MAIL_USE_POP
  139.   if (!bcmp (inname, "po:", 3))
  140.     {
  141.       int status; char *user;
  142.  
  143.       user = (char *) rindex (inname, ':') + 1;
  144.       status = popmail (user, outname);
  145.       exit (status);
  146.     }
  147.  
  148.   setuid (getuid ());
  149. #endif /* MAIL_USE_POP */
  150.  
  151.   /* Check access to input file.  */
  152.   if (access (inname, R_OK | W_OK) != 0)
  153.     pfatal_with_name (inname);
  154.  
  155. #ifndef MAIL_USE_MMDF
  156. #ifndef MAIL_USE_FLOCK
  157.   /* Use a lock file named /usr/spool/mail/$USER.lock:
  158.      If it exists, the mail file is locked.  */
  159.   /* Note: this locking mechanism is *required* by the mailer
  160.      (on systems which use it) to prevent loss of mail.
  161.  
  162.      On systems that use a lock file, extracting the mail without locking
  163.      WILL occasionally cause loss of mail due to timing errors!
  164.  
  165.      So, if creation of the lock file fails
  166.      due to access permission on /usr/spool/mail,
  167.      you simply MUST change the permission
  168.      and/or make movemail a setgid program
  169.      so it can create lock files properly.
  170.  
  171.      You might also wish to verify that your system is one
  172.      which uses lock files for this purpose.  Some systems use other methods.
  173.  
  174.      If your system uses the `flock' system call for mail locking,
  175.      define MAIL_USE_FLOCK in config.h or the s-*.h file
  176.      and recompile movemail.  If the s- file for your system
  177.      should define MAIL_USE_FLOCK but does not, send a bug report
  178.      to bug-gnu-emacs@prep.ai.mit.edu so we can fix it.  */
  179.  
  180.   lockname = concat (inname, ".lock", "");
  181.   tempname = (char *) xmalloc (strlen (inname) + 20);
  182.   strcpy (tempname, inname);
  183.   p = tempname + strlen (tempname);
  184.   while (p != tempname && p[-1] != '/')
  185.     p--;
  186.   *p = 0;
  187.   strcpy (p, "EXXXXXX");
  188.   mktemp (tempname);
  189.   unlink (tempname);
  190.  
  191.   while (1)
  192.     {
  193.       /* Create the lock file, but not under the lock file name.  */
  194.       /* Give up if cannot do that.  */
  195.       desc = open (tempname, O_WRONLY | O_CREAT, 0666);
  196.       if (desc < 0)
  197.         pfatal_with_name ("lock file--see source file etc/movemail.c");
  198.       close (desc);
  199.  
  200.       tem = link (tempname, lockname);
  201.       unlink (tempname);
  202.       if (tem >= 0)
  203.     break;
  204.       sleep (1);
  205.  
  206.       /* If lock file is a minute old, unlock it.  */
  207.       if (stat (lockname, &st) >= 0)
  208.     {
  209.       now = time (0);
  210.       if (st.st_ctime < now - 60)
  211.         unlink (lockname);
  212.     }
  213.     }
  214.  
  215.   delete_lockname = lockname;
  216. #endif /* not MAIL_USE_FLOCK */
  217.  
  218. #ifdef MAIL_USE_FLOCK
  219.   indesc = open (inname, O_RDWR);
  220. #else /* if not MAIL_USE_FLOCK */
  221.   indesc = open (inname, O_RDONLY);
  222. #endif /* not MAIL_USE_FLOCK */
  223. #else /* MAIL_USE_MMDF */
  224.   indesc = lk_open (inname, O_RDONLY, 0, 0, 10);
  225. #endif /* MAIL_USE_MMDF */
  226.  
  227.   if (indesc < 0)
  228.     pfatal_with_name (inname);
  229.  
  230. #if defined (BSD) || defined (XENIX)
  231.   /* In case movemail is setuid to root, make sure the user can
  232.      read the output file.  */
  233.   /* This is desirable for all systems
  234.      but I don't want to assume all have the umask system call */
  235.   umask (umask (0) & 0333);
  236. #endif /* BSD or Xenix */
  237.   outdesc = open (outname, O_WRONLY | O_CREAT | O_EXCL, 0666);
  238.   if (outdesc < 0)
  239.     pfatal_with_name (outname);
  240. #ifdef MAIL_USE_FLOCK
  241. #ifdef XENIX
  242.   if (locking (indesc, LK_RLCK, 0L) < 0) pfatal_with_name (inname);
  243. #else
  244.   if (flock (indesc, LOCK_EX) < 0) pfatal_with_name (inname);
  245. #endif
  246. #endif /* MAIL_USE_FLOCK */
  247.  
  248.   while (1)
  249.     {
  250.       nread = read (indesc, buf, sizeof buf);
  251.       if (nread != write (outdesc, buf, nread))
  252.     {
  253.       int saved_errno = errno;
  254.       unlink (outname);
  255.       errno = saved_errno;
  256.       pfatal_with_name (outname);
  257.     }
  258.       if (nread < sizeof buf)
  259.     break;
  260.     }
  261.  
  262. #ifdef BSD
  263.   if (fsync (outdesc) < 0)
  264.     pfatal_and_delete (outname);
  265. #endif
  266.  
  267.   /* Check to make sure no errors before we zap the inbox.  */
  268.   if (close (outdesc) != 0)
  269.     pfatal_and_delete (outname);
  270.  
  271. #ifdef MAIL_USE_FLOCK
  272. #if defined (STRIDE) || defined (XENIX)
  273.   /* Stride, xenix have file locking, but no ftruncate.  This mess will do. */
  274.   close (open (inname, O_CREAT | O_TRUNC | O_RDWR, 0666));
  275. #else
  276.   ftruncate (indesc, 0L);
  277. #endif /* STRIDE or XENIX */
  278. #endif /* MAIL_USE_FLOCK */
  279.  
  280. #ifdef MAIL_USE_MMDF
  281.   lk_close (indesc, 0, 0, 0);
  282. #else
  283.   close (indesc);
  284. #endif
  285.  
  286. #ifndef MAIL_USE_FLOCK
  287.   /* Delete the input file; if we can't, at least get rid of its contents.  */
  288.   if (unlink (inname) < 0)
  289.     if (errno != ENOENT)
  290.       creat (inname, 0666);
  291. #ifndef MAIL_USE_MMDF
  292.   unlink (lockname);
  293. #endif /* not MAIL_USE_MMDF */
  294. #endif /* not MAIL_USE_FLO