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 + -
显示快捷键?