Path: utzoo!utgpu!jarvis.csri.toronto.edu!cs.utexas.edu!tut.cis.ohio-state.edu!ABYSS.ENG.UMD.EDU!djm From: djm@ABYSS.ENG.UMD.EDU (David J. MacKenzie) Newsgroups: gnu.emacs.bug Subject: making movemail more flexible Message-ID: <8912020212.AA26644@abyss.eng.umd.edu> Date: 2 Dec 89 02:12:21 GMT Sender: daemon@tut.cis.ohio-state.edu Distribution: gnu Organization: GNUs Not Usenet Lines: 177 On our Sun NFS network here, /usr/spool/mail/ is a symbolic link to /mail//, where is one of several machines that depends on how the user got the account. All mail is delivered (by /usr/bin/mail) on the servers. The /usr/spool directories are actually symbolic links to /var/spool, and are local to each workstation. This setup allows us to have the various /mail/ directories automounted with NFS only when they are needed. It is my impression that this is a fairly common arrangement for Sun NFS networks. It has two implications for movemail: 1. Locking /usr/spool/mail/ is useless, because it locks the symbolic link in the workstation's /var/spool rather than the actual mail spool file on the server. 2. /usr/spool/mail/ should not be deleted, because if it were, the link to /mail// would be lost. Instead, the file that it points to should be deleted. Below are some additions to etc/movemail.c that 1) automatically trace any number of levels of symbolic links encountered when trying to lstat /usr/spool/mail/, to arrive at the mail file's real pathname (so that when ".lock" can be appended to it, the lock will appear in the server's mail directory) 2) add a compile-time option to never try to unlink the mail spool file, but always truncate it. Some sites have permissions set up so that this is necessary. If it is removed (this option is not defined), the file that will be removed is the one on the server, not the local symbolic link. *** movemail.c Mon Nov 27 12:57:30 1989 --- movemail-local.c Wed Nov 29 10:20:01 1989 *************** *** 70,75 **** --- 70,179 ---- /* Nonzero means this is name of a lock file to delete on fatal error. */ char *delete_lockname; + #ifdef S_IFLNK + /* The amount of memory to increase the size of the symbolic link name + buffer by until the name fits. */ + #define BLOCK 100 + + char *malloc (); + char *strrchr (); + + static char * + basename (str) + char *str; + { + char *base; + + base = strrchr (str, '/'); + if (base) + return base + 1; + else + return 0; + } + + static char * + follow_link (path) + char *path; + { + char *linkval, *newlink, *pathend; + size_t linklen; + int ret; + + linklen = BLOCK; + linkval = malloc (linklen); + if (linkval == 0) + return 0; + while ((ret = readlink (path, linkval, linklen)) != -1 && ret == linklen) + { + free (linkval); + linklen += BLOCK; + linkval = malloc (linklen); + if (linkval == 0) + return 0; + } + + if (ret == -1) + return 0; + linkval[ret] = 0; /* readlink does not null terminate. */ + + /* Correct for a relative link. */ + if (*linkval != '/') + { + pathend = basename (path); + newlink = malloc (ret + strlen (path) + 1); + if (newlink == 0) + return 0; + strncpy (newlink, path, pathend - path); + if (newlink [strlen (newlink) - 1] != '/') + strcat (newlink, "/"); + strcat (newlink, linkval); + return newlink; + } + else + return linkval; + } + + static int + filetype (path) + char *path; + { + struct stat stats; + + if (lstat (path, &stats) == -1) + return 0; + else + return stats.st_mode & S_IFMT; + } + + /* Follow any number of levels of symbolic links to return a non-symlink + file that is referenced by `path'. If `path' does not refer to a symlink, + return `path'. If there is an error, return 0. */ + + char * + realpath(path) + char *path; + { + char *newpath; + int len; + + if (path == 0) + return 0; + + /* Remove trailing slashes. */ + len = strlen (path) - 1; + while (len > 0 && path[len] == '/') + path[len--] = 0; + + while (path && filetype (path) == S_IFLNK) + { + newpath = follow_link (path); + free (path); + path = newpath; + } + return path; + } + #endif /* S_IFLNK */ + main (argc, argv) int argc; char **argv; *************** *** 93,99 **** --- 197,207 ---- if (argc < 3) fatal ("two arguments required"); + #ifdef S_IFLNK + inname = realpath (argv[1]); + #else inname = argv[1]; + #endif /* S_IFLNK */ outname = argv[2]; /* Check access to input and output file. */ *************** *** 235,242 **** --- 343,352 ---- #ifndef MAIL_USE_FLOCK /* Delete the input file; if we can't, at least get rid of its contents. */ + #ifndef SAVE_INBOX if (unlink (inname) < 0) if (errno != ENOENT) + #endif /* SAVE_INBOX */ creat (inname, 0666); (void) unlink (lockname); #endif /* not MAIL_USE_FLOCK */ *************** Brought to you by Super Global Mega Corp .com