mail.c

Go to the documentation of this file.
00001 /*  mail - send/receive mail             Author: Peter S. Housel */
00002 /* Version 0.2 of September 1990: added -e, -t, * options - cwr */
00003 
00004 /* 2003-07-18: added -s option - ASW */
00005 
00006 #include <sys/types.h>
00007 #include <sys/stat.h>
00008 #include <errno.h>
00009 #undef EOF                      /* temporary hack */
00010 #include <signal.h>
00011 #include <pwd.h>
00012 #include <time.h>
00013 #include <setjmp.h>
00014 #include <string.h>
00015 #include <stdlib.h>
00016 #include <fcntl.h>
00017 #include <unistd.h>
00018 #include <sys/wait.h>
00019 #include <stdio.h>
00020 
00021 #ifdef DEBUG
00022 #define D(Q) (Q)
00023 #else
00024 #define D(Q)
00025 #endif
00026 
00027 #define SHELL           "/bin/sh"
00028 
00029 #define DROPNAME        "/usr/spool/mail/%s"
00030 #define LOCKNAME        "/usr/spool/mail/%s.lock"
00031 #define LOCKWAIT        5       /* seconds to wait after collision */
00032 #define LOCKTRIES       4       /* maximum number of collisions */
00033 
00034 #define MBOX            "mbox"
00035 
00036 #define HELPFILE        "/usr/lib/mail.help"
00037 #define PROMPT          "? "
00038 #define PATHLEN         80
00039 #define MAXRCPT         100     /* maximum number of recipients */
00040 #define LINELEN         512
00041 
00042 /* #define MAILER               "/usr/bin/smail"        */ /* smart mailer */
00043 #define MAILERARGS              /* (unused) */
00044 
00045 #define UNREAD          1       /* 'not read yet' status */
00046 #define DELETED         2       /* 'deleted' status */
00047 #define READ            3       /* 'has been read' status */
00048 
00049 struct letter {
00050   struct letter *prev, *next;   /* linked letter list */
00051   int status;                   /* letter status */
00052   off_t location;               /* location within mailbox file */
00053 };
00054 
00055 struct letter *firstlet, *lastlet;
00056 
00057 int usemailer = 1;              /* use MAILER to deliver (if any) */
00058 int printmode = 0;              /* print-and-exit mode */
00059 int quitmode = 0;               /* take interrupts */
00060 int reversemode = 0;            /* print mailbox in reverse order */
00061 int usedrop = 1;                /* read the maildrop (no -f given) */
00062 int verbose = 0;                /* pass "-v" flag on to mailer */
00063 int needupdate = 0;             /* need to update mailbox */
00064 int msgstatus = 0;              /* return the mail status */
00065 int distlist = 0;               /* include distribution list */
00066 char mailbox[PATHLEN];          /* user's mailbox/maildrop */
00067 char tempname[PATHLEN] = "/tmp/mailXXXXXX";     /* temporary file */
00068 char *subject = NULL;
00069 FILE *boxfp = NULL;             /* mailbox file */
00070 jmp_buf printjump;              /* for quitting out of letters */
00071 unsigned oldmask;               /* saved umask() */
00072 
00073 extern int optind;
00074 extern char *optarg;
00075 
00076 _PROTOTYPE(int main, (int argc, char **argv));
00077 _PROTOTYPE(int deliver, (int count, char *vec []));
00078 _PROTOTYPE(FILE *makerewindable, (void));
00079 _PROTOTYPE(int copy, (FILE *fromfp, FILE *tofp));
00080 _PROTOTYPE(void readbox, (void));
00081 _PROTOTYPE(void printall, (void));
00082 _PROTOTYPE(void interact, (void));
00083 _PROTOTYPE(void onint, (int dummy));
00084 _PROTOTYPE(void savelet, (struct letter *let, char *savefile));
00085 _PROTOTYPE(void updatebox, (void));
00086 _PROTOTYPE(void printlet, (struct letter *let, FILE *tofp));
00087 _PROTOTYPE(void doshell, (char *command));
00088 _PROTOTYPE(void usage, (void));
00089 _PROTOTYPE(char *basename, (char *name));
00090 _PROTOTYPE(char *whoami, (void));
00091 _PROTOTYPE(void dohelp, (void));
00092 _PROTOTYPE(int filesize, (char *name));
00093 
00094 int main(argc, argv)
00095 int argc;
00096 char *argv[];
00097 {
00098   int c;
00099 
00100   if ('l' == (basename(argv[0]))[0])    /* 'lmail' link? */
00101         usemailer = 0;          /* yes, let's deliver it */
00102 
00103   (void) mktemp(tempname);      /* name the temp file */
00104 
00105   oldmask = umask(022);         /* change umask for security */
00106 
00107   while (EOF != (c = getopt(argc, argv, "epqrf:tdvs:"))) switch (c) {
00108             case 'e':   ++msgstatus;    break;  
00109 
00110             case 't':   ++distlist;     break;
00111 
00112             case 'p':   ++printmode;    break;
00113 
00114             case 'q':   ++quitmode;     break;
00115 
00116             case 'r':   ++reversemode;  break;
00117 
00118             case 'f':
00119                 setuid(getuid());       /* won't need to lock */
00120                 usedrop = 0;
00121                 strncpy(mailbox, optarg, (size_t)(PATHLEN - 1));
00122                 break;
00123 
00124             case 'd':   usemailer = 0;  break;
00125 
00126             case 'v':   ++verbose;      break;
00127 
00128             case 's':   subject = optarg; break;
00129 
00130             default:
00131                 usage();
00132                 exit(1);
00133         }
00134 
00135   if (optind < argc) {
00136         if (deliver(argc - optind, argv + optind) < 0)
00137                 exit(1);
00138         else
00139                 exit(0);
00140   }
00141   if (usedrop) sprintf(mailbox, DROPNAME, whoami());
00142 
00143   D(printf("mailbox=%s\n", mailbox));
00144 
00145   if (msgstatus) {
00146         if (filesize(mailbox))
00147                 exit(0);
00148         else
00149                 exit(1);
00150   }
00151 
00152   readbox();
00153 
00154   if (printmode)
00155         printall();
00156   else
00157         interact();
00158 
00159   if (needupdate) updatebox();
00160 
00161   return(0);
00162 }
00163 
00164 int deliver(count, vec)
00165 int count;
00166 char *vec[];
00167 {
00168   int i, j;
00169   int errs = 0;                 /* count of errors */
00170   int dropfd;                   /* file descriptor for user's drop */
00171   int created = 0;              /* true if we created the maildrop */
00172   FILE *mailfp;                 /* fp for mail */
00173   struct stat stb;              /* for checking drop modes, owners */
00174 #ifdef __STDC__
00175   void (*sigint)(int), (*sighup)(int), (*sigquit)(int);/* saving signal state */
00176 #else
00177   void (*sigint) (), (*sighup) (), (*sigquit) ();      /* saving signal state */
00178 #endif
00179   time_t now;                   /* for datestamping the postmark */
00180   char sender[32];              /* sender's login name */
00181   char lockname[PATHLEN];       /* maildrop lock */
00182   int locktries;                /* tries when box is locked */
00183   struct passwd *pw;            /* sender and recipent */
00184   int to_console;               /* deliver to console if everything fails */
00185 
00186   if (count > MAXRCPT) {
00187         fprintf(stderr, "mail: too many recipients\n");
00188         return -1;
00189   }
00190 #ifdef MAILER
00191   if (usemailer) {
00192         char *argvec[MAXRCPT + 3];
00193         char **argp;
00194 
00195         setuid(getuid());
00196 
00197         argp = argvec;
00198         *argp++ = "send-mail";
00199         if (verbose) *argp++ = "-v";
00200 
00201         for (i = 0; i < count; ++i) *argp++ = vec[i];
00202 
00203         *argp = NULL;
00204         execv(MAILER, argvec);
00205         fprintf(stderr, "mail: couldn't exec %s\n", MAILER);
00206         return -1;
00207   }
00208 #endif /* MAILER */
00209 
00210   if (NULL == (pw = getpwuid(getuid()))) {
00211         fprintf(stderr, "mail: unknown sender\n");
00212         return -1;
00213   }
00214   strcpy(sender, pw->pw_name);
00215 
00216   /* If we need to rewind stdin and it isn't rewindable, make a copy */
00217   if (isatty(0) || (count > 1 && lseek(0, 0L, 0) == (off_t) -1)) {
00218         mailfp = makerewindable();
00219   } else
00220         mailfp = stdin;
00221 
00222   /* Shut off signals during the delivery */
00223   sigint = signal(SIGINT, SIG_IGN);
00224   sighup = signal(SIGHUP, SIG_IGN);
00225   sigquit = signal(SIGQUIT, SIG_IGN);
00226 
00227   for (i = 0; i < count; ++i) {
00228         if (count > 1) rewind(mailfp);
00229 
00230         D(printf("deliver to %s\n", vec[i]));
00231 
00232         if (NULL == (pw = getpwnam(vec[i]))) {
00233                 fprintf(stderr, "mail: user %s not known\n", vec[i]);
00234                 ++errs;
00235                 continue;
00236         }
00237         sprintf(mailbox, DROPNAME, pw->pw_name);
00238         sprintf(lockname, LOCKNAME, pw->pw_name);
00239 
00240         D(printf("maildrop='%s', lock='%s'\n", mailbox, lockname));
00241 
00242         /* Lock the maildrop while we're messing with it. Races are
00243          * possible (though not very likely) when we have to create
00244          * the maildrop, but not otherwise. If the box is already
00245          * locked, wait awhile and try again. */
00246         locktries = created = to_console = 0;
00247 trylock:
00248         if (link(mailbox, lockname) != 0) {
00249                 if (ENOENT == errno) {  /* user doesn't have a drop yet */
00250                         dropfd = creat(mailbox, 0600);
00251                         if (dropfd < 0 && errno == ENOENT) {
00252                                 /* Probably missing spool dir; to console. */
00253                                 boxfp = fopen("/dev/console", "w");
00254                                 if (boxfp != NULL) {
00255                                         to_console = 1;
00256                                         goto nobox;
00257                                 }
00258                         }
00259                         if (dropfd < 0) {
00260                                 fprintf(stderr, "mail: couln't create a maildrop for user %s\n",
00261                                         vec[i]);
00262                                 ++errs;
00263                                 continue;
00264                         }
00265                         ++created;
00266                         goto trylock;
00267                 } else {        /* somebody else has it locked, it seems -
00268                          * wait */
00269                         if (++locktries >= LOCKTRIES) {
00270                                 fprintf(stderr, "mail: couldn't lock maildrop for user %s\n",
00271                                         vec[i]);
00272                                 ++errs;
00273                                 continue;
00274                         }
00275                         sleep(LOCKWAIT);
00276                         goto trylock;
00277                 }
00278         }
00279         if (created) {
00280                 (void) chown(mailbox, pw->pw_uid, pw->pw_gid);
00281                 boxfp = fdopen(dropfd, "a");
00282         } else
00283                 boxfp = fopen(mailbox, "a");
00284 
00285         if (NULL == boxfp || stat(mailbox, &stb) < 0) {
00286                 fprintf(stderr, "mail: serious maildrop problems for %s\n", vec[i]);
00287                 unlink(lockname);
00288                 ++errs;
00289                 continue;
00290         }
00291         if (stb.st_uid != pw->pw_uid || (stb.st_mode & S_IFMT) != S_IFREG) {
00292                 fprintf(stderr, "mail: mailbox for user %s is illegal\n", vec[i]);
00293                 unlink(lockname);
00294                 ++errs;
00295                 continue;
00296         }
00297 nobox:
00298         if (to_console) {
00299                 fprintf(boxfp,
00300                         "-------------\n| Mail from %s to %s\n-------------\n",
00301                         sender, vec[i]);
00302         } else {
00303                 (void) time(&now);
00304                 fprintf(boxfp, "From %s %24.24s\n", sender, ctime(&now));
00305         }
00306 
00307         /* Add the To: header line */
00308         fprintf(boxfp, "To: %s\n", vec[i]);
00309 
00310         if (distlist) {
00311                 fprintf(boxfp, "Dist: ");
00312                 for (j = 0; j < count; ++j)
00313                         if (getpwnam(vec[j]) != NULL && j != i)
00314                                 fprintf(boxfp, "%s ", vec[j]) ;
00315                 fprintf(boxfp, "\n");
00316         }
00317 
00318         /* Add the Subject: header line */
00319         if (subject != NULL) fprintf(boxfp, "Subject: %s\n", subject);
00320 
00321         fprintf(boxfp, "\n");
00322  
00323         if ((copy(mailfp, boxfp) < 0) || (fclose(boxfp) != 0)) {
00324                 fprintf(stderr, "mail: error delivering to user %s", vec[i]);
00325                 perror(" ");
00326                 ++errs;
00327         }
00328         unlink(lockname);
00329   }
00330 
00331   fclose(mailfp);
00332 
00333   /* Put signals back the way they were */
00334   signal(SIGINT, sigint);
00335   signal(SIGHUP, sighup);
00336   signal(SIGQUIT, sigquit);
00337 
00338   return(0 == errs) ? 0 : -1;
00339 }
00340 
00341 /* 'stdin' isn't rewindable. Make a temp file that is.
00342  * Note that if one wanted to catch SIGINT and write a '~/dead.letter'
00343  * for interactive mails, this might be the place to do it (though the
00344  * case where a MAILER is being used would also need to be handled).
00345  */
00346 FILE *makerewindable()
00347 {
00348   FILE *tempfp;                 /* temp file used for copy */
00349   int c;                        /* character being copied */
00350   int state;                    /* ".\n" detection state */
00351 
00352   if (NULL == (tempfp = fopen(tempname, "w"))) {
00353         fprintf(stderr, "mail: can't create temporary file\n");
00354         return NULL;
00355   }
00356 
00357   /* Here we copy until we reach the end of the letter (end of file or
00358    * a line containing only a '.'), painstakingly avoiding setting a
00359    * line length limit. */
00360   state = '\n';
00361   while (EOF != (c = getc(stdin))) switch (state) {
00362             case '\n':
00363                 if ('.' == c)
00364                         state = '.';
00365                 else {
00366                         if ('\n' != c) state = '\0';
00367                         putc(c, tempfp);
00368                 }
00369                 break;
00370             case '.':
00371                 if ('\n' == c) goto done;
00372                 state = '\0';
00373                 putc('.', tempfp);
00374                 putc(c, tempfp);
00375                 break;
00376             default:
00377                 state = ('\n' == c) ? '\n' : '\0';
00378                 putc(c, tempfp);
00379         }
00380 done:
00381   if (ferror(tempfp) || fclose(tempfp)) {
00382         fprintf(stderr, "mail: couldn't copy letter to temporary file\n");
00383         return NULL;
00384   }
00385   tempfp = freopen(tempname, "r", stdin);
00386   unlink(tempname);             /* unlink name; file lingers on in limbo */
00387   return tempfp;
00388 }
00389 
00390 int copy(fromfp, tofp)
00391 FILE *fromfp, *tofp;
00392 {
00393   int c;                        /* character being copied */
00394   int state;                    /* ".\n" and postmark detection state */
00395   int blankline = 0;            /* was most recent line completely blank? */
00396   static char postmark[] = "From ";
00397   char *p, *q;
00398 
00399   /* Here we copy until we reach the end of the letter (end of file or
00400    * a line containing only a '.'). Postmarks (lines beginning with
00401    * "From ") are copied with a ">" prepended. Here we also complicate
00402    * things by not setting a line limit. */
00403   state = '\n';
00404   p = postmark;
00405   while (EOF != (c = getc(fromfp))) {
00406         switch (state) {
00407             case '\n':
00408                 if ('.' == c)   /* '.' at BOL */
00409                         state = '.';
00410                 else if (*p == c) {     /* start of postmark */
00411                         ++p;
00412                         state = 'P';
00413                 } else {        /* anything else */
00414                         if ('\n' == c)
00415                                 blankline = 1;
00416                         else {
00417                                 state = '\0';
00418                                 blankline = 0;
00419                         }
00420                         putc(c, tofp);
00421                 }
00422                 break;
00423             case '.':
00424                 if ('\n' == c) goto done;
00425                 state = '\0';
00426                 putc('.', tofp);
00427                 putc(c, tofp);
00428                 break;
00429             case 'P':
00430                 if (*p == c) {
00431                         if (*++p == '\0') {     /* successfully reached end */
00432                                 p = postmark;
00433                                 putc('>', tofp);
00434                                 fputs(postmark, tofp);
00435                                 state = '\0';
00436                                 break;
00437                         }
00438                         break;  /* not there yet */
00439                 }
00440                 state = ('\n' == c) ? '\n' : '\0';
00441                 for (q = postmark; q < p; ++q) putc(*q, tofp);
00442                 putc(c, tofp);
00443                 blankline = 0;
00444                 p = postmark;
00445                 break;
00446             default:
00447                 state = ('\n' == c) ? '\n' : '\0';
00448                 putc(c, tofp);
00449         }
00450   }
00451   if ('\n' != state) putc('\n', tofp);
00452 done:
00453   if (!blankline) putc('\n', tofp);
00454   if (ferror(tofp)) return -1;
00455   return 0;
00456 }
00457 
00458 void readbox()
00459 {
00460   char linebuf[512];
00461   struct letter *let;
00462   off_t current;
00463 
00464   firstlet = lastlet = NULL;
00465 
00466   if (access(mailbox, 4) < 0 || NULL == (boxfp = fopen(mailbox, "r"))) {
00467         if (usedrop && ENOENT == errno) return;
00468         fprintf(stderr, "can't access mailbox ");
00469         perror(mailbox);
00470         exit(1);
00471   }
00472   current = 0L;
00473   while (1) {
00474         if (NULL == fgets(linebuf, sizeof linebuf, boxfp)) break;
00475 
00476         if (!strncmp(linebuf, "From ", (size_t)5)) {
00477                 if (NULL == (let = (struct letter *) malloc(sizeof(struct letter)))) {
00478                         fprintf(stderr, "Out of memory.\n");
00479                         exit(1);
00480                 }
00481                 if (NULL == lastlet) {
00482                         firstlet = let;
00483                         let->prev = NULL;
00484                 } else {
00485                         let->prev = lastlet;
00486                         lastlet->next = let;
00487                 }
00488                 lastlet = let;
00489                 let->next = NULL;
00490 
00491                 let->status = UNREAD;
00492                 let->location = current;
00493                 D(printf("letter at %ld\n", current));
00494         }
00495         current += strlen(linebuf);
00496   }
00497 }
00498 
00499 void printall()
00500 {
00501   struct letter *let;
00502 
00503   let = reversemode ? firstlet : lastlet;
00504 
00505   if (NULL == let) {
00506         printf("No mail.\n");
00507         return;
00508   }
00509   while (NULL != let) {
00510         printlet(let, stdout);
00511         let = reversemode ? let->next : let->prev;
00512   }
00513 }
00514 
00515 void interact()
00516 {
00517   char linebuf[512];            /* user input line */
00518   struct letter *let, *next;    /* current and next letter */
00519   int interrupted = 0;          /* SIGINT hit during letter print */
00520   int needprint = 1;            /* need to print this letter */
00521   char *savefile;               /* filename to save into */
00522 
00523   if (NULL == firstlet) {
00524         printf("No mail.\n");
00525         return;
00526   }
00527   let = reversemode ? firstlet : lastlet;
00528 
00529   while (1) {
00530         next = reversemode ? let->next : let->prev;
00531         if (NULL == next) next = let;
00532 
00533         if (!quitmode) {
00534                 interrupted = setjmp(printjump);
00535                 signal(SIGINT, onint);
00536         }
00537         if (!interrupted && needprint) {
00538                 if (DELETED != let->status) let->status = READ;
00539                 printlet(let, stdout);
00540         }
00541         if (interrupted) putchar('\n');
00542         needprint = 0;
00543         fputs(PROMPT, stdout);
00544         fflush(stdout);
00545 
00546         if (fgets(linebuf, sizeof linebuf, stdin) == NULL) break;
00547 
00548         if (!quitmode) signal(SIGINT, SIG_IGN);
00549 
00550         switch (linebuf[0]) {
00551             case '\n':
00552                 let = next;
00553                 needprint = 1;
00554                 continue;
00555             case 'd':
00556                 let->status = DELETED;
00557                 if (next != let)/* look into this */
00558                         needprint = 1;
00559                 needupdate = 1;
00560                 let = next;
00561                 continue;
00562             case 'p':
00563                 needprint = 1;
00564                 continue;
00565             case '-':
00566                 next = reversemode ? let->prev : let->next;
00567                 if (NULL == next) next = let;
00568                 let = next;
00569                 needprint = 1;
00570                 continue;
00571             case 's':
00572                 for (savefile = strtok(linebuf + 1, " \t\n");
00573                      savefile != NULL;
00574                      savefile = strtok((char *) NULL, " \t\n")) {
00575                         savelet(let, savefile);
00576                 }
00577                 continue;
00578             case '!':
00579                 doshell(linebuf + 1);
00580                 continue;
00581             case '*':
00582                 dohelp();
00583                 continue;
00584             case 'q':
00585                 return;
00586             case 'x':
00587                 exit(0);
00588             default:
00589                 fprintf(stderr, "Illegal command\n");
00590                 continue;
00591         }
00592   }
00593 }
00594 
00595 void onint(dummy)
00596 int dummy;      /* to satisfy ANSI compilers */
00597 {
00598   longjmp(printjump, 1);
00599 }
00600 
00601 void savelet(let, savefile)
00602 struct letter *let;
00603 char *savefile;
00604 {
00605   int waitstat, pid;
00606   FILE *savefp;
00607 
00608   if ((pid = fork()) < 0) {
00609         perror("mail: couldn't fork");
00610         return;
00611   } else if (pid != 0) {        /* parent */
00612         wait(&waitstat);
00613         return;
00614   }
00615 
00616   /* Child */
00617   setgid(getgid());
00618   setuid(getuid());
00619   if ((savefp = fopen(savefile, "a")) == NULL) {
00620         perror(savefile);
00621         exit(0);
00622   }
00623   printlet(let, savefp);
00624   if ((ferror(savefp) != 0) | (fclose(savefp) != 0)) {
00625         fprintf(stderr, "savefile write error:");
00626         perror(savefile);
00627   }
00628   exit(0);
00629 }
00630 
00631 void updatebox()
00632 {
00633   FILE *tempfp;                 /* fp for tempfile */
00634   char lockname[PATHLEN];       /* maildrop lock */
00635   int locktries = 0;            /* tries when box is locked */
00636   struct letter *let;           /* current letter */
00637   int c;
00638 
00639   sprintf(lockname, LOCKNAME, whoami());
00640 
00641   if (NULL == (tempfp = fopen(tempname, "w"))) {
00642         perror("mail: can't create temporary file");
00643         return;
00644   }
00645   for (let = firstlet; let != NULL; let = let->next) {
00646         if (let->status != DELETED) {
00647                 printlet(let, tempfp);
00648                 D(printf("printed letter at %ld\n", let->location));
00649         }
00650   }
00651 
00652   if (ferror(tempfp) || NULL == (tempfp = freopen(tempname, "r", tempfp))) {
00653         perror("mail: temporary file write error");
00654         unlink(tempname);
00655         return;
00656   }
00657 
00658   /* Shut off signals during the update */
00659   signal(SIGINT, SIG_IGN);
00660   signal(SIGHUP, SIG_IGN);
00661   signal(SIGQUIT, SIG_IGN);
00662 
00663   if (usedrop) while (link(mailbox, lockname) != 0) {
00664                 if (++locktries >= LOCKTRIES) {
00665                         fprintf(stderr, "mail: couldn't lock maildrop for update\n");
00666                         return;
00667                 }
00668                 sleep(LOCKWAIT);
00669         }
00670 
00671   if (NULL == (boxfp = freopen(mailbox, "w", boxfp))) {
00672         perror("mail: couldn't reopen maildrop");
00673         fprintf(stderr, "mail may have been lost; look in %s\n", tempname);
00674         if (usedrop) unlink(lockname);
00675         return;
00676   }
00677   unlink(tempname);
00678 
00679   while ((c = getc(tempfp)) != EOF) putc(c, boxfp);
00680 
00681   fclose(boxfp);
00682 
00683   if (usedrop) unlink(lockname);
00684 }
00685 
00686 void printlet(let, tofp)
00687 struct letter *let;
00688 FILE *tofp;
00689 {
00690   off_t current, limit;
00691   int c;
00692 
00693   fseek(boxfp, (current = let->location), 0);
00694   limit = (NULL != let->next) ? let->next->location : -1;
00695 
00696   while (current != limit && (c = getc(boxfp)) != EOF) {
00697         putc(c, tofp);
00698         ++current;
00699   }
00700 }
00701 
00702 void doshell(command)
00703 char *command;
00704 {
00705   int waitstat, pid;
00706   char *shell;
00707 
00708   if (NULL == (shell = getenv("SHELL"))) shell = SHELL;
00709 
00710   if ((pid = fork()) < 0) {
00711         perror("mail: couldn't fork");
00712         return;
00713   } else if (pid != 0) {        /* parent */
00714         wait(&waitstat);
00715         return;
00716   }
00717 
00718   /* Child */
00719   setgid(getgid());
00720   setuid(getuid());
00721   umask(oldmask);
00722 
00723   execl(shell, shell, "-c", command, (char *) NULL);
00724   fprintf(stderr, "can't exec shell\n");
00725   exit(127);
00726 }
00727 
00728 void usage()
00729 {
00730   fprintf(stderr, "usage: mail [-epqr] [-f file]\n");
00731   fprintf(stderr, "       mail [-dtv] [-s subject] user [...]\n");
00732 }
00733 
00734 char *basename(name)
00735 char *name;
00736 {
00737   char *p;
00738 
00739   if (NULL == (p = rindex(name, '/')))
00740         return name;
00741   else
00742         return p + 1;
00743 }
00744 
00745 char *whoami()
00746 {
00747   struct passwd *pw;
00748 
00749   if (NULL != (pw = getpwuid(getuid())))
00750         return pw->pw_name;
00751   else
00752         return "nobody";
00753 }
00754 
00755 void dohelp()
00756 {
00757   FILE *fp;
00758   char buffer[80];
00759 
00760   if ( (fp = fopen(HELPFILE, "r")) == NULL)
00761         fprintf(stdout, "can't open helpfile %s\n", HELPFILE);
00762   else
00763         while (fgets(buffer, 80, fp))
00764                 fputs(buffer, stdout);
00765 }
00766 
00767 int filesize(name)
00768 char *name ;
00769 {
00770   struct stat buf;
00771  
00772   if (stat(name, &buf) == -1)
00773         buf.st_size = 0L;
00774 
00775   return (buf.st_size ? 1 : 0);
00776 }

Generated on Fri Apr 14 22:56:40 2006 for minix by  doxygen 1.4.6