xref: /csrg-svn/usr.bin/at/atrun/atrun.c (revision 64038)
148235Sbostic /*-
2*64038Sbostic  * Copyright (c) 1983, 1993
3*64038Sbostic  *	The Regents of the University of California.  All rights reserved.
448235Sbostic  *
548235Sbostic  * %sccs.include.proprietary.c%
622449Sdist  */
722449Sdist 
813708Ssam #ifndef lint
9*64038Sbostic static char copyright[] =
10*64038Sbostic "@(#) Copyright (c) 1983, 1993\n\
11*64038Sbostic 	The Regents of the University of California.  All rights reserved.\n";
1248235Sbostic #endif /* not lint */
1322449Sdist 
1422449Sdist #ifndef lint
15*64038Sbostic static char sccsid[] = "@(#)atrun.c	8.1 (Berkeley) 07/26/93";
1648235Sbostic #endif /* not lint */
1722449Sdist 
181187Sbill /*
1916827Smckusick  *	Synopsis: atrun
2016823Swall  *
2116823Swall  *
2216827Smckusick  *	Run jobs created by at(1)
2316823Swall  *
2416823Swall  *
2516827Smckusick  *	Modifications by:	Steve Wall
2616827Smckusick  *				Computer Systems Research Group
2716827Smckusick  *				University of California @ Berkeley
2816823Swall  *
291187Sbill  */
3016823Swall # include <stdio.h>
3130197Sbostic # include <sys/param.h>
3216823Swall # include <sys/dir.h>
3316823Swall # include <sys/file.h>
3416823Swall # include <sys/time.h>
3528871Smckusick #ifdef notdef
3622447Skjd # include <sys/quota.h>
3728871Smckusick #endif
3816823Swall # include <sys/stat.h>
3916823Swall # include <pwd.h>
4037962Sbostic # include "pathnames.h"
411187Sbill 
4216827Smckusick # define NORMAL		0			/* job exited normally */
4316827Smckusick # define ABNORMAL	1			/* job exited abnormally */
441187Sbill 
4516827Smckusick char nowtime[11];			/* time it is right now (yy.ddd.hhmm) */
4616827Smckusick char errfile[25];			/* file where we redirect errors to */
4716823Swall 
4816823Swall 
main(argc,argv)491187Sbill main(argc, argv)
501187Sbill char **argv;
511187Sbill {
521187Sbill 
5316827Smckusick 	int i;				/* for loop index */
5416827Smckusick 	int numjobs;			/* number of jobs to be run */
5516827Smckusick 	int should_be_run();		/* should a job be run? */
5616827Smckusick 	struct direct **jobqueue;	/* queue of jobs to be run */
5716823Swall 
5816823Swall 
5916827Smckusick 	/*
6016827Smckusick 	 * Move to the spooling area.
6116827Smckusick 	 */
6237962Sbostic 	chdir(_PATH_ATDIR);
6316823Swall 
6416827Smckusick 	/*
6516827Smckusick 	 * Create a filename that represents the time it is now. This is used
6616827Smckusick 	 * to determine if the execution time for a job has arrived.
6716827Smckusick 	 */
6816827Smckusick 	makenowtime(nowtime);
6916823Swall 
7016827Smckusick 	/*
7116827Smckusick 	 * Create a queue of the jobs that should be run.
7216827Smckusick 	 */
7316827Smckusick 	if ((numjobs = scandir(".",&jobqueue,should_be_run, 0)) < 0) {
7437962Sbostic 		perror(_PATH_ATDIR);
7516827Smckusick 		exit(1);
7616827Smckusick 	}
7716823Swall 
7816827Smckusick 	/*
7916827Smckusick 	 * If there are jobs to be run, run them.
8016827Smckusick 	 */
8116827Smckusick 	if (numjobs > 0) {
8216827Smckusick 		for (i = 0; i < numjobs; ++i) {
8316827Smckusick 			run(jobqueue[i]->d_name);
8416827Smckusick 		}
8516827Smckusick 	}
8616823Swall 
8716827Smckusick 	/*
8816827Smckusick 	 * Record the last update time.
8916827Smckusick 	 */
9016827Smckusick 	updatetime();
9116823Swall 
921187Sbill }
931187Sbill 
9416823Swall /*
9516823Swall  * Create a string with the syntax yy.ddd.hhmm that represents the
9616823Swall  * time it is right now. This string is used to determine whether a
9716823Swall  * job should be run.
9816823Swall  */
makenowtime(nowtime)9916823Swall makenowtime(nowtime)
10016823Swall char *nowtime;
1011187Sbill {
10216827Smckusick 	struct tm *now;			/* broken down representation of the
10316827Smckusick 					   time it is right now */
10416827Smckusick 	struct timeval time;		/* number of seconds since 1/1/70 */
10516827Smckusick 	struct timezone zone;		/* time zone we're in (NOT USED) */
1061187Sbill 
10716827Smckusick 	/*
10816827Smckusick 	 * Get the time of day.
10916827Smckusick 	 */
11016827Smckusick 	if (gettimeofday(&time,&zone) < 0) {
11116827Smckusick 		perror("gettimeofday");
11216827Smckusick 		exit(1);
11316827Smckusick 	}
11416823Swall 
11516827Smckusick 	/*
11616827Smckusick 	 * Get a broken down representation of the time it is right now.
11716827Smckusick 	 */
11816827Smckusick 	now = localtime(&time.tv_sec);
11916823Swall 
12016827Smckusick 	/*
12116827Smckusick 	 * Create a string to be used in determining whether or not a job
12216827Smckusick 	 * should be run. The syntax is yy.ddd.hhmm .
12316827Smckusick 	 */
12416827Smckusick 	sprintf(nowtime,"%d.%03d.%02d%02d",now->tm_year,
12516827Smckusick 					   now->tm_yday,
12616827Smckusick 					   now->tm_hour,
12716827Smckusick 					   now->tm_min);
12816827Smckusick 	return;
1291187Sbill }
1301187Sbill 
13116823Swall /*
13216823Swall  * Run a job.
13316823Swall  */
run(spoolfile)13416823Swall run(spoolfile)
13516823Swall char *spoolfile;
1361187Sbill {
13716827Smckusick 	int i;				/* scratch variable */
13816827Smckusick 	int pid;			/* process id of forked shell */
13916827Smckusick 	int exitstatus;			/* exit status of the job */
14016827Smckusick 	int notifybymail;		/* should we notify the owner of the
14116827Smckusick 					   job after the job is run? */
14216827Smckusick 	char shell[4];			/* shell to run the job under */
14316827Smckusick 	char *getname();		/* get a uname from using a uid */
14416827Smckusick 	char mailvar[4];		/* send mail variable ("yes" or "no") */
14516827Smckusick 	char runfile[100];		/* file sent to forked shell for exec-
14616827Smckusick 					   ution */
14728871Smckusick 	char owner[128];		/* owner of job we're going to run */
14828871Smckusick 	char jobname[128];		/* name of job we're going to run */
14916827Smckusick 	char whichshell[100];		/* which shell should we fork off? */
15016867Swall 	struct passwd *pwdbuf;		/* password info of the owner of job */
15116827Smckusick 	struct stat errbuf;		/* stats on error file */
15216827Smckusick 	struct stat jobbuf;		/* stats on job file */
15316827Smckusick 	FILE *infile;			/* I/O stream to spoolfile */
1541187Sbill 
15516823Swall 
15616827Smckusick 	/*
15716827Smckusick 	 * First we fork a child so that the main can run other jobs.
15816827Smckusick 	 */
15916827Smckusick 	if (pid = fork())
16016827Smckusick 		return;
16116823Swall 
16216827Smckusick 	/*
16316827Smckusick 	 * Open the spoolfile.
16416827Smckusick 	 */
16516827Smckusick 	if ((infile = fopen(spoolfile,"r")) == NULL) {
16616827Smckusick 		perror(spoolfile);
16737349Sedward 		(void) unlink(spoolfile);
16816827Smckusick 		exit(1);
16916827Smckusick 	}
17016823Swall 
17116827Smckusick 	/*
17228871Smckusick 	 * Grab the 4-line header out of the spoolfile.
17316827Smckusick 	 */
17428871Smckusick 	if (
17564037Sbostic 	    (fscanf(infile,"# owner: %127s\n",owner) != 1) ||
17664037Sbostic 	    (fscanf(infile,"# jobname: %127s\n",jobname) != 1) ||
17764037Sbostic 	    (fscanf(infile,"# shell: %3s\n",shell) != 1) ||
17864037Sbostic 	    (fscanf(infile,"# notify by mail: %3s\n",mailvar) != 1)
17928871Smckusick 	    ) {
18028871Smckusick 		fprintf(stderr, "%s: bad spool header\n", spoolfile);
18137349Sedward 		(void) unlink(spoolfile);
18228871Smckusick 		exit(1);
18328871Smckusick 	}
18416823Swall 
18516827Smckusick 	/*
18616827Smckusick 	 * Check to see if we should send mail to the owner.
18716827Smckusick 	 */
18816827Smckusick 	notifybymail = (strcmp(mailvar, "yes") == 0);
18916827Smckusick 	fclose(infile);
19016823Swall 
19116827Smckusick 	/*
19216867Swall 	 * Change the ownership of the spoolfile from "daemon" to the owner
19316867Swall 	 * of the job.
19416867Swall 	 */
19516867Swall 	pwdbuf = getpwnam(owner);
19628871Smckusick 	if (pwdbuf == NULL) {
19728871Smckusick 		fprintf(stderr, "%s: could not find owner in passwd file\n",
19828871Smckusick 		    spoolfile);
19937349Sedward 		(void) unlink(spoolfile);
20028871Smckusick 		exit(1);
20128871Smckusick 	}
20216867Swall 	if (chown(spoolfile,pwdbuf->pw_uid,pwdbuf->pw_gid) == -1) {
20316867Swall 		perror(spoolfile);
20437349Sedward 		(void) unlink(spoolfile);
20516867Swall 		exit(1);
20616867Swall 	}
20716867Swall 
20816867Swall 	/*
20916827Smckusick 	 * Move the spoolfile to the directory where jobs are run from and
21016827Smckusick 	 * then move into that directory.
21116827Smckusick 	 */
21237962Sbostic 	sprintf(runfile,"%s/%s",_PATH_PAST,spoolfile);
21316827Smckusick 	rename(spoolfile, runfile);
21437962Sbostic 	chdir(_PATH_PAST);
21516823Swall 
21616827Smckusick 	/*
21716827Smckusick 	 * Create a temporary file where we will redirect errors to.
21816827Smckusick 	 * Just to make sure we've got a unique file, we'll run an "access"
21916827Smckusick 	 * check on the file.
22016827Smckusick 	 */
22116827Smckusick 	for (i = 0; i <= 1000; i += 2) {
22237962Sbostic 		sprintf(errfile,"%s/at.err%d",_PATH_TMP,(getpid() + i));
22316823Swall 
22416827Smckusick 		if (access(errfile, F_OK))
22516827Smckusick 			break;
22616823Swall 
22716827Smckusick 		if (i == 1000) {
22816827Smckusick 			fprintf(stderr, "couldn't create errorfile.\n");
22916827Smckusick 			exit(1);
23016827Smckusick 		}
23116827Smckusick 	}
23216823Swall 
23316827Smckusick 	/*
23416827Smckusick 	 * Get the stats of the job being run.
23516827Smckusick 	 */
23616827Smckusick 	if (stat(runfile, &jobbuf) == -1) {
23716827Smckusick 		perror(runfile);
23816827Smckusick 		exit(1);
23916827Smckusick 	}
24016823Swall 
24116827Smckusick 	/*
24216827Smckusick 	 * Fork another child that will run the job.
24316827Smckusick 	 */
24416827Smckusick 	if (pid = fork()) {
24516823Swall 
24616827Smckusick 		/*
24716827Smckusick 		 * If the child fails, save the job so that it gets
24816827Smckusick 		 * rerun the next time "atrun" is executed and then exit.
24916827Smckusick 		 */
25016827Smckusick 		if (pid == -1) {
25137962Sbostic 			chdir(_PATH_ATDIR);
25216827Smckusick 			rename(runfile, spoolfile);
25316827Smckusick 			exit(1);
25416827Smckusick 		}
25516823Swall 
25616827Smckusick 		/*
25716827Smckusick 		 * Wait for the child to terminate.
25816827Smckusick 		 */
25916827Smckusick 		wait((int *)0);
26016823Swall 
26116827Smckusick 		/*
26216827Smckusick 		 * Get the stats of the error file and determine the exit
26316827Smckusick 		 * status of the child. We assume that if there is anything
26416827Smckusick 		 * in the error file then the job ran into some errors.
26516827Smckusick 		 */
26616827Smckusick 		if (stat(errfile,&errbuf) != 0) {
26716827Smckusick 			perror(errfile);
26816827Smckusick 			exit(1);
26916827Smckusick 		}
27016827Smckusick 		exitstatus = ((errbuf.st_size == 0) ? NORMAL : ABNORMAL);
27116823Swall 
27228868Sbloom 		/* If errors occurred, then we send mail to the owner
27316827Smckusick 		 * telling him/her that we ran into trouble.
27416827Smckusick 		 *
27516827Smckusick 		 * (NOTE: this could easily be modified so that if any
27628868Sbloom 		 * errors occurred while running a job, mail is sent regard-
27716827Smckusick 		 * less of whether the -m flag was set or not.
27816827Smckusick 		 *
27916827Smckusick 		 * i.e. rather than:
28016827Smckusick 		 *
28116827Smckusick 		 *	"if (notifybymail)" use
28216827Smckusick 		 * use:
28316827Smckusick 		 *
28416827Smckusick 		 *	"if ((exitstatus == ABNORMAL) || (notifybymail))"
28516827Smckusick 		 *
28616827Smckusick 		 * It's up to you if you want to implement this.
28716827Smckusick 		 *
28816827Smckusick 		 */
28924912Sserge 		if (exitstatus == ABNORMAL || notifybymail)
29016827Smckusick 			sendmailto(getname(jobbuf.st_uid),jobname,exitstatus);
29116823Swall 
29216827Smckusick 		/*
29316827Smckusick 		 * Remove the errorfile and the jobfile.
29416827Smckusick 		 */
29516827Smckusick 		if (unlink(errfile) == -1)
29616827Smckusick 			perror(errfile);
29716827Smckusick 		if (unlink(runfile) == -1)
29816827Smckusick 			perror(runfile);
29916823Swall 
30016827Smckusick 		exit(0);
30116827Smckusick 	}
30216823Swall 
30316827Smckusick 	/*
30416827Smckusick 	 * HERE'S WHERE WE SET UP AND FORK THE SHELL.
30516827Smckusick 	 */
30616823Swall 
30716827Smckusick 	/*
30816827Smckusick 	 * Run the job as the owner of the jobfile
30916827Smckusick 	 */
31028871Smckusick #ifdef notdef
31128871Smckusick 	/* This is no longer needed with the new, stripped-down quota system */
31222447Skjd 	quota(Q_SETUID,jobbuf.st_uid,0,0);
31328871Smckusick #endif
31416827Smckusick 	setgid(jobbuf.st_gid);
31522447Skjd 	initgroups(getname(jobbuf.st_uid),jobbuf.st_gid);
31616827Smckusick 	setuid(jobbuf.st_uid);
31716823Swall 
31816827Smckusick 	/*
31916827Smckusick 	 * Close all open files so that we can reopen a temporary file
32016827Smckusick 	 * for stdout and sterr.
32116827Smckusick 	 */
32222447Skjd 	for (i = getdtablesize(); --i >= 0;)
32316827Smckusick 		close(i);
32416823Swall 
32516827Smckusick 	/*
32616827Smckusick 	 * Reposition stdin, stdout, and stderr.
32716827Smckusick 	 *
32816827Smckusick 	 *	stdin  = /dev/null
32916827Smckusick 	 *	stout  = /dev/null
33016827Smckusick 	 *	stderr = /tmp/at.err{pid}
33116827Smckusick 	 *
33216827Smckusick 	 */
33337962Sbostic 	open(_PATH_DEVNULL, 0);
33437962Sbostic 	open(_PATH_DEVNULL, 1);
33516827Smckusick 	open(errfile,O_CREAT|O_WRONLY,00644);
33616823Swall 
33716827Smckusick 	/*
33816827Smckusick 	 * Now we fork the shell.
33916827Smckusick 	 *
34016827Smckusick 	 * See if the shell is in /bin
34116827Smckusick 	 */
34216827Smckusick 	sprintf(whichshell,"/bin/%s",shell);
34316827Smckusick 	execl(whichshell,shell,runfile, 0);
34416823Swall 
34516827Smckusick 	/*
34616827Smckusick 	 * If we don't succeed by now, we're really having troubles,
34716827Smckusick 	 * so we'll send the owner some mail.
34816827Smckusick 	 */
34916827Smckusick 	fprintf(stderr, "%s: Can't execl shell\n",shell);
35022447Skjd 	exit(1);
3511187Sbill }
3521187Sbill 
35316823Swall /*
35416823Swall  * Send mail to the owner of the job.
35516823Swall  */
sendmailto(user,jobname,exitstatus)35616823Swall sendmailto(user,jobname,exitstatus)
35716823Swall char *user;
35816823Swall char *jobname;
35916823Swall int exitstatus;
3601187Sbill {
36130197Sbostic 	int ch;				/* scratch variable */
36216827Smckusick 	char mailtouser[100];		/* the process we use to send mail */
36316827Smckusick 	FILE *mailptr;			/* I/O stream to the mail process */
36416827Smckusick 	FILE *errptr;			/* I/O stream to file containing error
36516827Smckusick 					   messages */
36616827Smckusick 	FILE *popen();			/* initiate I/O to a process */
3671187Sbill 
36816823Swall 
36916827Smckusick 	/*
37016827Smckusick 	 * Create the full name for the mail process.
37116827Smckusick 	 */
37237962Sbostic 	sprintf(mailtouser,"%s %s", _PATH_MAIL, user);
37316823Swall 
37416827Smckusick 	/*
37516827Smckusick 	 * Open a stream to the mail process.
37616827Smckusick 	 */
37716827Smckusick 	if ((mailptr = popen(mailtouser,"w")) == NULL) {
37837962Sbostic 		perror(_PATH_MAIL);
37916827Smckusick 		exit(1);
38016827Smckusick 	}
38116823Swall 
38216827Smckusick 	/*
38316827Smckusick 	 * Send the letter. If the job exited normally, just send a
38416827Smckusick 	 * quick letter notifying the owner that everthing went ok.
38516827Smckusick 	 */
38616827Smckusick 	if (exitstatus == NORMAL) {
38716827Smckusick 		fprintf(mailptr,"Your job \"%s\" was run without ",jobname);
38816827Smckusick 		fprintf(mailptr,"any errors.\n");
38916827Smckusick 	}
39016823Swall 
39116827Smckusick 	/*
39216827Smckusick 	 * If the job exited abnormally, send a letter notifying the user
39316827Smckusick 	 * that the job didn't run proberly. Also, send a copy of the errors
39428868Sbloom 	 * that occurred to the user.
39516827Smckusick 	 */
39616827Smckusick 	else {
39716827Smckusick 		if (exitstatus == ABNORMAL) {
39816823Swall 
39916827Smckusick 			/*
40016827Smckusick 			 * Write the intro to the letter.
40116827Smckusick 			 */
40216827Smckusick 			fprintf(mailptr,"\n\nThe job you submitted to at, ");
40316827Smckusick 			fprintf(mailptr,"\"%s\", ",jobname);
40416827Smckusick 			fprintf(mailptr,"exited abnormally.\nA list of the ");
40528868Sbloom 			fprintf(mailptr," errors that occurred follows:\n\n\n");
40616823Swall 
40716827Smckusick 			/*
40816827Smckusick 			 * Open the file containing a log of the errors that
40928868Sbloom 			 * occurred.
41016827Smckusick 			 */
41116827Smckusick 			if ((errptr = fopen(errfile,"r")) == NULL) {
41216827Smckusick 				perror(errfile);
41316827Smckusick 				exit(1);
41416827Smckusick 			}
41516823Swall 
41616827Smckusick 			/*
41716827Smckusick 			 * Send the copy of the errors to the owner.
41816827Smckusick 			 */
41916827Smckusick 			fputc('\t',mailptr);
42016827Smckusick 			while ((ch = fgetc(errptr)) != EOF) {
42116827Smckusick 				fputc(ch,mailptr);
42230197Sbostic 				if (ch == (int)'\n')
42316827Smckusick 					fputc('\t',mailptr);
42416827Smckusick 			}
42516827Smckusick 			fclose(errptr);
42616827Smckusick 		}
42716827Smckusick 	}
42816823Swall 
42916827Smckusick 	/*
43016827Smckusick 	 * Sign the letter.
43116827Smckusick 	 */
43216827Smckusick 	fprintf(mailptr,"\n\n-----------------\n");
43316827Smckusick 	fprintf(mailptr,"The Atrun Program\n");
43416823Swall 
43516827Smckusick 	/*
43616827Smckusick 	 * Close the stream to the mail process.
43716827Smckusick 	 */
43816827Smckusick 	pclose(mailptr);
43916827Smckusick 	return;
4401187Sbill }
44116823Swall 
44216823Swall /*
44316823Swall  * Do we want to include a file in the job queue? (used by "scandir")
44416823Swall  * We are looking for files whose "value" (its name) is less than or
44516823Swall  * equal to the time it is right now (represented by "nowtime").
44616823Swall  * We'll only consider files with three dots in their name since these
44716823Swall  * are the only files that represent jobs to be run.
44816823Swall  */
44916823Swall should_be_run(direntry)
45016823Swall struct direct *direntry;
45116823Swall {
45216827Smckusick 	int numdot = 0;			/* number of dots found in a filename */
45316827Smckusick 	char *filename;			/* pointer for scanning a filename */
45416823Swall 
45516823Swall 
45616827Smckusick 	filename = direntry->d_name;
45716823Swall 
45816827Smckusick 	/*
45916827Smckusick 	 * Count the number of dots found in the directory entry.
46016827Smckusick 	 */
46116827Smckusick 	while (*filename)
46216827Smckusick 		numdot += (*(filename++) == '.');
46316823Swall 
46416827Smckusick 	/*
46516827Smckusick 	 * If the directory entry doesn't represent a job, just return a 0.
46616827Smckusick 	 */
46716827Smckusick 	if (numdot != 3)
46816827Smckusick 		return(0);
46916823Swall 
47016827Smckusick 	/*
47116827Smckusick 	 * If a directory entry represents a job, determine if it's time to
47216827Smckusick 	 * run it.
47316827Smckusick 	 */
47416827Smckusick 	return(strncmp(direntry->d_name, nowtime,11) <= 0);
47516823Swall }
47616823Swall 
47716823Swall /*
47816823Swall  * Record the last time that "atrun" was run.
47916823Swall  */
updatetime()48016823Swall updatetime()
48116823Swall {
48216823Swall 
48316827Smckusick 	struct timeval time;		/* number of seconds since 1/1/70 */
48416827Smckusick 	struct timezone zone;		/* time zone we're in (NOT USED) */
48516827Smckusick 	FILE *lastimefile;		/* file where recored is kept */
48616823Swall 
48716827Smckusick 	/*
48816827Smckusick 	 * Get the time of day.
48916827Smckusick 	 */
49016827Smckusick 	if (gettimeofday(&time,&zone) < 0) {
49116827Smckusick 		perror("gettimeofday");
49216827Smckusick 		exit(1);
49316827Smckusick 	}
49416823Swall 
49516827Smckusick 	/*
49616827Smckusick 	 * Open the record file.
49716827Smckusick 	 */
49837962Sbostic 	if ((lastimefile = fopen(_PATH_LASTFILE, "w")) == NULL) {
49916827Smckusick 		fprintf(stderr, "can't update lastfile: ");
50037962Sbostic 		perror(_PATH_LASTFILE);
50116827Smckusick 		exit(1);
50216827Smckusick 	}
50316823Swall 
50416827Smckusick 	/*
50516827Smckusick 	 * Record the last update time (in seconds since 1/1/70).
50616827Smckusick 	 */
50716827Smckusick 	fprintf(lastimefile, "%d\n", (u_long) time.tv_sec);
50816823Swall 
50916827Smckusick 	/*
51016827Smckusick 	 * Close the record file.
51116827Smckusick 	 */
51216827Smckusick 	fclose(lastimefile);
51316823Swall }
51416823Swall 
51516823Swall /*
51616823Swall  * Get the full login name of a person using his/her user id.
51716823Swall  */
51816823Swall char *
getname(uid)51916823Swall getname(uid)
52046818Sbostic 	int uid;
52116823Swall {
52216827Smckusick 	struct passwd *pwdinfo;			/* password info structure */
52316827Smckusick 
52416827Smckusick 	if ((pwdinfo = getpwuid(uid)) == 0) {
52546818Sbostic 		(void)fprintf(stderr, "atrun: %d: no such user uid\n");
52616827Smckusick 		exit(1);
52716827Smckusick 	}
52816827Smckusick 	return(pwdinfo->pw_name);
52916823Swall }
530