1: /* movemail foo bar -- move file foo to file bar, 2: locking file foo the way /bin/mail respects. 3: Copyright (C) 1985 Richard M. Stallman. 4: 5: This file is part of GNU Emacs. 6: 7: GNU Emacs is distributed in the hope that it will be useful, 8: but without any warranty. No author or distributor 9: accepts responsibility to anyone for the consequences of using it 10: or for whether it serves any particular purpose or works at all, 11: unless he says so in writing. 12: 13: Everyone is granted permission to copy, modify and redistribute 14: GNU Emacs, but only under the conditions described in the 15: document "GNU Emacs copying permission notice". An exact copy 16: of the document is supposed to have been given to you along with 17: GNU Emacs so that you can know how you may redistribute it all. 18: It should be in a file named COPYING. Among other things, the 19: copyright notice and this notice must be preserved on all copies. */ 20: 21: #include <sys/types.h> 22: #include <sys/stat.h> 23: #include <sys/file.h> 24: #define NO_SHORTNAMES /* Tell config not to load remap.h */ 25: #include "../src/config.h" 26: 27: #ifdef USG 28: #include <fcntl.h> 29: #endif /* USG */ 30: 31: /* Cancel substitutions made by config.h for Emacs. */ 32: #undef open 33: #undef read 34: #undef write 35: 36: char *concat (); 37: 38: main (argc, argv) 39: int argc; 40: char **argv; 41: { 42: char *inname, *outname; 43: int indesc, outdesc; 44: char buf[1024]; 45: int nread; 46: 47: #ifndef MAIL_USE_FLOCK 48: struct stat st; 49: long now; 50: int tem; 51: char *lockname, *p; 52: char tempname[40]; 53: int desc; 54: #endif /* not MAIL_USE_FLOCK */ 55: 56: if (argc < 3) 57: fatal ("two arguments required"); 58: 59: inname = argv[1]; 60: outname = argv[2]; 61: 62: #ifndef MAIL_USE_FLOCK 63: /* Use a lock file named /usr/spool/mail/$USER.lock: 64: If it exists, the mail file is locked. */ 65: lockname = concat (inname, ".lock", ""); 66: strcpy (tempname, inname); 67: p = tempname + strlen (tempname); 68: while (p != tempname && p[-1] != '/') 69: p--; 70: *p = 0; 71: strcpy (p, "EXXXXXX"); 72: mktemp (tempname); 73: unlink (tempname); 74: 75: while (1) 76: { 77: /* Create the lock file, but not under the lock file name. */ 78: /* Give up if cannot do that. */ 79: desc = open (tempname, O_WRONLY | O_CREAT, 0666); 80: if (desc < 0) 81: exit (1); 82: close (desc); 83: 84: tem = link (tempname, lockname); 85: unlink (tempname); 86: if (tem >= 0) 87: break; 88: sleep (1); 89: 90: /* If lock file is a minute old, unlock it. */ 91: if (stat (lockname, &st) >= 0) 92: { 93: now = time (0); 94: if (st.st_ctime < now - 60) 95: unlink (lockname); 96: } 97: } 98: #endif /* not MAIL_USE_FLOCK */ 99: 100: #ifdef MAIL_USE_FLOCK 101: indesc = open (inname, O_RDWR); 102: #else /* if not MAIL_USE_FLOCK */ 103: indesc = open (inname, O_RDONLY); 104: #endif /* not MAIL_USE_FLOCK */ 105: if (indesc < 0) 106: pfatal_with_name (inname); 107: #ifdef BSD 108: /* In case movemail is setuid to root, make sure the user can 109: read the output file. */ 110: /* This is desirable for all systems 111: but I don't want to assume all have the umask system call */ 112: umask (umask (0) & 0333); 113: #endif /* BSD */ 114: outdesc = open (outname, O_WRONLY | O_CREAT | O_EXCL, 0666); 115: if (outdesc < 0) 116: pfatal_with_name (outname); 117: #ifdef MAIL_USE_FLOCK 118: (void) flock (indesc, LOCK_EX); 119: #endif /* MAIL_USE_FLOCK */ 120: 121: while (1) 122: { 123: nread = read (indesc, buf, sizeof buf); 124: if (nread != write (outdesc, buf, nread)) 125: fatal ("error writing to %s", outname); 126: if (nread < sizeof buf) 127: break; 128: } 129: 130: #ifdef MAIL_USE_FLOCK 131: (void) ftruncate (indesc, 0L); 132: #endif /* MAIL_USE_FLOCK */ 133: close (indesc); 134: close (outdesc); 135: #ifndef MAIL_USE_FLOCK 136: unlink (inname); 137: unlink (lockname); 138: #endif /* not MAIL_USE_FLOCK */ 139: exit (0); 140: } 141: 142: /* Print error message and exit. */ 143: 144: fatal (s1, s2) 145: char *s1, *s2; 146: { 147: error (s1, s2); 148: exit (1); 149: } 150: 151: /* Print error message. `s1' is printf control string, `s2' is arg for it. */ 152: 153: error (s1, s2) 154: char *s1, *s2; 155: { 156: printf ("movemail: "); 157: printf (s1, s2); 158: printf ("\n"); 159: } 160: 161: pfatal_with_name (name) 162: char *name; 163: { 164: extern int errno, sys_nerr; 165: extern char *sys_errlist[]; 166: char *s; 167: 168: if (errno < sys_nerr) 169: s = concat ("", sys_errlist[errno], " for %s"); 170: else 171: s = "cannot open %s"; 172: fatal (s, name); 173: } 174: 175: /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */ 176: 177: char * 178: concat (s1, s2, s3) 179: char *s1, *s2, *s3; 180: { 181: int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3); 182: char *result = (char *) xmalloc (len1 + len2 + len3 + 1); 183: 184: strcpy (result, s1); 185: strcpy (result + len1, s2); 186: strcpy (result + len1 + len2, s3); 187: *(result + len1 + len2 + len3) = 0; 188: 189: return result; 190: } 191: 192: /* Like malloc but get fatal error if memory is exhausted. */ 193: 194: int 195: xmalloc (size) 196: int size; 197: { 198: int result = malloc (size); 199: if (!result) 200: fatal ("virtual memory exhausted", 0); 201: return result; 202: }