mail.c
来自「<B>Digital的Unix操作系统VAX 4.2源码</B>」· C语言 代码 · 共 1,321 行 · 第 1/2 页
C
1,321 行
case 'd': break; default: fprintf(stderr, "Unknown flag\n"); usage(); done(); } } if (argc <= 1) { usage(); done(); } if (gaver == 0) strcpy(truename, my_name); /* if (argc > 4 && strcmp(argv[1], "-r") == 0) { strcpy(truename, argv[2]); argc -= 2; argv += 2; fgets(line, LSIZE, stdin); if (strcmpn("From", line, 4) == 0) line[0] = '\0'; } else strcpy(truename, my_name); */ time(&iop); fprintf(tmpf, "%s%s %s", from, truename, ctime(&iop)); iop = ftell(tmpf); flgf = 1; for (first = 1;; first = 0) { if (first && line[0] == '\0' && fgets(line, LSIZE, stdin) == NULL) break; if (!first && fgets(line, LSIZE, stdin) == NULL) break; if (line[0] == '.' && line[1] == '\n' && isatty(fileno(stdin))) break; if (isfrom(line))/* PJS: Signal an output error. */ if (fputs(">", tmpf) < 0) { perror("mail"); return; }/* PJS: Signal an output error. */ if (fputs(line, tmpf) < 0) { perror("mail"); return; } flgf = 0; }/* PJS: Signal an output error. */ if (fputs("\n", tmpf) < 0) { perror("mail"); return; } nlet = 1; let[0].adr = 0; let[1].adr = ftell(tmpf);/* PJS: Signal an output error. */ if (fclose(tmpf) == EOF) { perror("mail"); return; } if (flgf) return; tmpf = fopen(lettmp, "r"); if (tmpf == NULL) { fprintf(stderr, "mail: cannot reopen %s for reading\n", lettmp); return; } while (--argc > 0) { if (!sendmail(0, *++argv, truename)) error++; } if (error && (mald = safefile(dead,-1)) >= 0) { setuid(getuid()); malf = fdopen(mald, "w"); if (malf == NULL) { fprintf(stdout, "mail: cannot open %s\n", dead); fclose(tmpf); return; } copylet(0, malf, ZAP);/* PJS: signal an error on fclosing. */ if (fclose(malf) == EOF) { perror("mail"); return; } fprintf(stdout, "Mail saved in %s\n", dead); } fclose(tmpf);}sendrmt(n, name, rcmd)char *name;char *rcmd;{ FILE *rmf, *popen(); register char *p; char rsys[64], cmd[64]; register local, pid; int sts; local = 0; if (index(name, '^')) { while (p = index(name, '^')) *p = '!'; if (strncmp(name, "researc", 7)) { strcpy(rsys, "research"); if (*name != '!') --name; goto skip; } } if (*name=='!') name++; for(p=rsys; *name!='!'; *p++ = *name++) { if (p - rsys > sizeof(rsys)) { printf("remote system name too long\n"); return(0); } if (*name=='\0') { local++; break; } } *p = '\0'; if ((!local && *name=='\0') || (local && *rsys=='\0')) { fprintf(stdout, "null name\n"); return(0); }skip: if ((pid = fork()) == -1) { fprintf(stderr, "mail: can't create proc for remote\n"); return(0); } if (pid) { while (wait(&sts) != pid) { if (wait(&sts)==-1) return(0); } return(!sts); } setuid(getuid()); if (local) sprintf(cmd, "%s %s", rcmd, rsys); else { if (index(name+1, '!')) sprintf(cmd, "uux - %s!rmail \\(%s\\)", rsys, name+1); else sprintf(cmd, "uux - %s!rmail %s", rsys, name+1); } if ((rmf=popen(cmd, "w")) == NULL) exit(1); copylet(n, rmf, local ? !strcmp(rcmd, "/bin/mail") ? FORWARD : ORDINARY : REMOTE); exit(pclose(rmf) != 0);}usage(){ error = EX_USAGE; /* I can't believe they forgot this */ fprintf(stderr, "Usage: mail [ -f ] people . . .\n");}#include <sys/socket.h>#include <netinet/in.h>#include <netdb.h>struct sockaddr_in biffaddr;sendmail(n, name, fromaddr)int n;char *name;char *fromaddr;{ char file[100]; register char *p; register mask; struct passwd *pw, *getpwnam(); struct stat statb; char buf[128]; int realuser; int f; int fd; struct hostent *hp = NULL; struct servent *sp = NULL; int mald; /* 'Safe' file descriptor for mail spool file. */ for(p=name; *p!='!'&&*p!='^' &&*p!='\0'; p++) ; if (*p == '!'|| *p=='^') return(sendrmt(n, name, 0)); if ((pw = getpwnam(name)) == NULL) { fprintf(stdout, "mail: can't send to %s\n", name); return(0); } cat(file, maildir, name); if (stat(file, &statb) >= 0 && (statb.st_mode & S_IFMT) == S_IFDIR) { strcat(file, "/"); strcat(file, name); } realuser = getuid(); setreuid(0,pw->pw_uid); if ((mald = safefile(file, pw->pw_uid)) < 0) { setuid (0); setreuid (realuser, 0); return(0); } lock(file); malf = fdopen(mald, "A"); if (malf == NULL) { unlock(); fprintf(stdout, "mail: cannot append to %s\n", file); setuid(0); setreuid(realuser,0); return(0); } /* Notify interersted parties via biff */ { char hostbuf[256]; gethostname(hostbuf, sizeof (hostbuf)); hp = gethostbyname(hostbuf); sp = getservbyname("biff", "udp"); if (hp && sp) { f = socket(AF_INET, SOCK_DGRAM, 0, 0); sprintf(buf, "%s@%d\n", name, ftell(malf)); } } copylet(n, malf, ORDINARY);/* PJS: Signal an error on failing to fclose. */ if (fclose(malf) == EOF) { perror("mail"); return(0); } setreuid(0,pw->pw_uid); if (hp && sp) { biffaddr.sin_family = hp->h_addrtype; bcopy(hp->h_addr, &biffaddr.sin_addr, hp->h_length); biffaddr.sin_port = sp->s_port; sendto(f, buf, strlen(buf)+1, 0, &biffaddr, sizeof (biffaddr)); close(f); } unlock(); setuid(0); setreuid(realuser,0); return(1);}voiddelete(i){ setsig(i, delete); fprintf(stderr, "\n"); if(delflg) longjmp(sjbuf, 1); done();}/* * Lock the specified mail file by creating the file name.lock * (where `name' is a user login name string). * We must, of course, be careful to unlink the lock file by a call * to unlock before we stop. The algorithm used here is to see if * the lock exists, and if it does we wait LOCKSLEEP time and look * again. If we still see the lock file, we will wait again. This loop * runs for approximately: * * seconds = (LOCKSLEEP + peak ) * (LOCKSLEEPS + peak) * * time and then we forcefully unlink the lock file. "peak" is the * peak load average seen in getla(); The minimum time on an unloaded * system (loadave =< 1) would be about 200 seconds with LOCKSLEEP = 9 * and OLOCKSLEEPS = 19. At loadave = 8, it would work out about - * * 9 + 8 = 17 seconds between sleeps * 19 + 8 = 27 make 27 sleeps * 27 x 17 = 459 seconds (7 minutes 39 seconds) * * However: * * If the mail file is actually changing size, we will wait until we see * no change for the above amount of time in the users' mailbox * before we forcefully remove the existing lock file (if any) and * proceed. * * If we MUST forcefully remove a lock file, a syslog entry is made to * back trace munged mail problems. */char *maillock = ".lock"; /* Lock suffix for mailname */char *lockname = "/usr/spool/mail/tmXXXXXX";char locktmp[30]; /* Usable lock temporary */char curlock[50]; /* Last used name of lock */int locked; /* To note that we locked it */lock(file)char *file;{ register int f; struct stat sbuf; struct stat original; long curtime; int statfailed; register int n; off_t osize; off_t nsize; struct stat mbox; if (locked || flgf) return(0); strcpy(curlock, file); strcat(curlock, maillock); strcpy(locktmp, lockname); mktemp(locktmp); unlink(locktmp); statfailed = 0;top:/* */ /* Get the original size of the users' mail box * and save it to check for changes to the mail box whilst * we are sleeping on a lock file (if any). */ if (stat(file,&mbox) < 0) osize = 0; else osize = mbox.st_size; /* Get original mod time of possible lock file to test * for creation of new lock file while we were sleeping. */ if (stat(curlock, &original) < 0) { original.st_ctime = 0; } /* Make number of sleep cycles. */ LOCKSLEEPS = OLOCKSLEEPS + getla(); for (n=0; n < LOCKSLEEPS; n++) { f = lock1(locktmp, curlock); if (f == 0) { if (OVERRIDE) { /* * At this point, we would have waited * a long time for the lock file to go * away. If it didn't, log a complaint. */ openlog("/bin/mail",1); syslog(LOG_ERR,"Overriding mail lock file for %s (peak load ave = %d)",file,peak); closelog(); } /* We have locked the file, return to caller. */ locked = 1; OVERRIDE = 0; return(0); } if (stat(curlock, &sbuf) < 0) { if (statfailed++ > 5) return(-1); sleep(LOCKSLEEP+peak); /* Take a new reading on the load. */ getla(); continue; } statfailed = 0; /* A lock file exists. Sleep for awhile and look again. */ if (FIRSTSLEEP) { FIRSTSLEEP = 0; openlog("/bin/mail",1); syslog(LOG_ERR,"Waiting on mail lock file %s (peak load ave = %d)",curlock,peak); closelog(); } sleep(LOCKSLEEP + peak); /* Take a new reading on the load. */ getla(); /* While we were sleeping, the mail box may have grown, * shrunk, -or- disappeared.... * Get a new size to compare to the original. */ if (stat(file,&mbox) < 0) { osize = nsize = 0; } else nsize = mbox.st_size; if ((nsize != osize) || (original.st_ctime != sbuf.st_ctime)) { /* If the users' mail box changed size, reset * to new size and restart the entire wait * cycle over. ie. We have to see the mail box * not change size for the required amount of * time if there was a lock file present * in the first place before we think about * removing the existing lock file. */ original.st_ctime = sbuf.st_ctime; n = 0; osize = nsize; LOCKSLEEPS = OLOCKSLEEPS + peak; } continue; } /* If we get here, the mail lock file (name.lock) has existed * for the required amount of time & we didn't see the * users' mail box change size. -or- If we saw it change size, * we reset our counters and rewound the clock for another * time and then waited the respectable interval before * resorting to removing the lock file by force. * * After our last sleep, make one final attempt to gracefully * create a lock file. */ f = lock1(locktmp, curlock); if (f == 0) { /* * We got lucky and were able to create the lock file. */ locked = 1; return(0); } /* Make one last ck to see if a new lock file has * been made whilst we were asleep. */ stat(curlock, &sbuf); if (original.st_ctime != sbuf.st_ctime) { OVERRIDE = 0; goto top; } /* We have to remove the lock file by force. */ f = unlink(curlock); if (f < 0) { /* If we can't remove the lock file, send the mail * back and record our complaint. */ if (errno != ENOENT) { openlog("/bin/mail",1); syslog(LOG_ERR,"Cannot override mail lock file %s",curlock); closelog(); error = EX_UNAVAILABLE; done(); } } OVERRIDE = 1; goto top; /* Rewind */}/* * Remove the mail lock, and note that we no longer * have it locked. */unlock(){ unlink(curlock); locked = 0;}/* * Attempt to set the lock by creating the temporary file, * then doing a link/unlink. If it fails, return -1 else 0 */lock1(tempfile, name) char tempfile[], name[];{ register int fd; fd = creat(tempfile, 0); if (fd < 0) return(-1); close(fd); if (link(tempfile, name) < 0) { unlink(tempfile); return(-1); } unlink(tempfile); return(0);}done(){ if(locked) unlock(); unlink(lettmp); unlink(locktmp); exit(error);}cat(to, from1, from2)char *to, *from1, *from2;{ int i, j; j = 0; for (i=0; from1[i]; i++) to[j++] = from1[i]; for (i=0; from2[i]; i++) to[j++] = from2[i]; to[j] = 0;}char *getarg(s, p) /* copy p... into s, update p */register char *s, *p;{ while (*p == ' ' || *p == '\t') p++; if (*p == '\n' || *p == '\0') return(NULL); while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') *s++ = *p++; *s = '\0'; return(p);}/* JCH/PJS: * safefile() now returns a file descriptor, so as to try to avoid race * conditions: the file may acquire links (h/s) between checking for these * and actually creating the file. */intsafefile(f, uid)char *f; /* File name to be opened. */int uid; /* To check ownership of the file. */{int fd;struct stat statb;/* We now try to create the file for writing to, but ensuring that this * will only succeed if the filename does not exist at the time. */ if ((fd = open(f, O_WRONLY | O_CREAT | O_EXCL, MAILMODE)) >= 0) return(fd); if (errno != EEXIST) { /* Something 'fatal' happened! */ fprintf(stderr,"mail: Creating %s",f); perror(" -"); return(-1); }/* The file name must already exist, as the 'open' with O_EXCL failed. * So, we can try to open it simply for O_WRONLY. * The file is supposed to exist at this stage, so if the open fails * then we may only return a FAILed status. */ if ((fd = open(f, O_WRONLY, MAILMODE)) < 0) { fprintf(stderr,"mail: Opening %s",f); perror(" -"); return(-1); }/* As a last precaution, we may check the filename for certain states: * - the link count must not be more than one as it is a (potential) * security hole. * - the file has not become a symbolic link. * - the file is owned by the 'uid' argument. * It is possible for the file to have been removed between the open() * and the lstat(). In this case, we don't need to test the above states: * closing the file will recreate the file. */ if (lstat(f, &statb) < 0) { if (errno != ENOENT) { fprintf(stderr,"mail: Stating %s",f); perror(" -"); return(-1); } } else { if (statb.st_nlink != 1 || (statb.st_mode & S_IFMT) == S_IFLNK) { fprintf(stderr,"mail: %s has more than one link or is a symbolic link\n",f); return(-1); } if (uid > 0 && statb.st_uid != uid) { fprintf(stderr,"mail: %s is not owned by you\n",f); return(-1); } }/* We have an open file that does not appear to: * - have multiple hard links, * - be a symbolic link, * - be owned by someone else other than the expected owner. * Therefore, we may safely return the file descriptor. */ return (fd);}/*** GETLA -- get the current load average**** This code stolen from la.c.**** Parameters:** none.**** Returns:** The current load average as an integer.**** Side Effects:** none.*/getla(){ static int kmem = -1; double avenrun[3]; extern off_t lseek(); if (kmem < 0) { kmem = open("/dev/kmem", 0, 0); if (kmem < 0) exit (-1); (void) ioctl(kmem, (int) FIOCLEX, (char *) 0); nlist("/vmunix", Nl); if (Nl[0].n_type == 0) return (9); } if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 || read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun)) { return(9); } load = (int) (avenrun[0] + 0.5); if (load == 0) load = 1; if (load != oload) { oload = load; if (oload > peak) peak = oload; } return(peak);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?