xref: /titanic_50/usr/src/cmd/cron/atrm.c (revision 032624d56c174c5c55126582b32e314a6af15522)
1*032624d5Sbasabi /*
2*032624d5Sbasabi  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
3*032624d5Sbasabi  * Use is subject to license terms.
4*032624d5Sbasabi  */
5*032624d5Sbasabi 
67c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
77c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
87c478bd9Sstevel@tonic-gate 
97c478bd9Sstevel@tonic-gate 
107c478bd9Sstevel@tonic-gate /*
117c478bd9Sstevel@tonic-gate  * Copyright (c) 1983 Regents of the University of California.
127c478bd9Sstevel@tonic-gate  * All rights reserved.  The Berkeley software License Agreement
137c478bd9Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
147c478bd9Sstevel@tonic-gate  */
157c478bd9Sstevel@tonic-gate 
16*032624d5Sbasabi #pragma ident	"%Z%%M%	%I%	%E% SMI"
177c478bd9Sstevel@tonic-gate 
187c478bd9Sstevel@tonic-gate /*
197c478bd9Sstevel@tonic-gate  *	synopsis: atrm [-f] [-i] [-a] [[job #] [user] ...]
207c478bd9Sstevel@tonic-gate  *
217c478bd9Sstevel@tonic-gate  *
227c478bd9Sstevel@tonic-gate  *	Remove "at" jobs.
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate #include <stdio.h>
267c478bd9Sstevel@tonic-gate #include <pwd.h>
277c478bd9Sstevel@tonic-gate #include <ctype.h>
287c478bd9Sstevel@tonic-gate #include <sys/types.h>
297c478bd9Sstevel@tonic-gate #include <dirent.h>
307c478bd9Sstevel@tonic-gate #include <sys/file.h>
317c478bd9Sstevel@tonic-gate #include <sys/stat.h>
327c478bd9Sstevel@tonic-gate #include <errno.h>
337c478bd9Sstevel@tonic-gate #include <unistd.h>
347c478bd9Sstevel@tonic-gate #include <locale.h>
35*032624d5Sbasabi #include <strings.h>
367c478bd9Sstevel@tonic-gate #include "cron.h"
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate extern time_t	num();
397c478bd9Sstevel@tonic-gate extern char	*errmsg();
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate extern void audit_at_delete(char *, char *, int);
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate #define	SUPERUSER	0			/* is user super-user? */
447c478bd9Sstevel@tonic-gate #define	CANTCD		"can't change directory to the at directory"
457c478bd9Sstevel@tonic-gate #define	NOREADDIR	"can't read the at directory"
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate uid_t user;					/* person requesting removal */
487c478bd9Sstevel@tonic-gate int fflag = 0;					/* suppress announcements? */
497c478bd9Sstevel@tonic-gate int iflag = 0;					/* run interactively? */
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate char login[UNAMESIZE];
527c478bd9Sstevel@tonic-gate char login_authchk[UNAMESIZE]; /* used for authorization checks */
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate #define	INVALIDUSER	"you are not a valid user (no entry in /etc/passwd)"
557c478bd9Sstevel@tonic-gate #define	NOTALLOWED	"you are not authorized to use at.  Sorry."
567c478bd9Sstevel@tonic-gate #define	NAMETOOLONG	"login name too long"
577c478bd9Sstevel@tonic-gate 
58*032624d5Sbasabi static void usage(void);
59*032624d5Sbasabi static void atabortperror(char *msg);
60*032624d5Sbasabi static void atabort(char *msg);
61*032624d5Sbasabi static void atperror(char *msg);
62*032624d5Sbasabi static void atperror2(char *msg, char *name);
63*032624d5Sbasabi static void aterror(char *msg);
64*032624d5Sbasabi static void powner(char *file);
657c478bd9Sstevel@tonic-gate 
66*032624d5Sbasabi int
67*032624d5Sbasabi main(int argc, char **argv)
687c478bd9Sstevel@tonic-gate {
697c478bd9Sstevel@tonic-gate 	int i;				/* for loop index */
707c478bd9Sstevel@tonic-gate 	int numjobs;			/* # of jobs in spooling area */
717c478bd9Sstevel@tonic-gate 	int allflag = 0;		/* remove all jobs belonging to user? */
727c478bd9Sstevel@tonic-gate 	int jobexists;			/* does a requested job exist? */
737c478bd9Sstevel@tonic-gate 	char *pp;
747c478bd9Sstevel@tonic-gate 	char *getuser();
757c478bd9Sstevel@tonic-gate 	struct dirent **namelist;	/* names of jobs in spooling area */
767c478bd9Sstevel@tonic-gate 	struct stat **statlist;
777c478bd9Sstevel@tonic-gate 	struct passwd *pwd;
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate 	/*
807c478bd9Sstevel@tonic-gate 	 * If job number, user name, or "-" is not specified, just print
817c478bd9Sstevel@tonic-gate 	 * usage info and exit.
827c478bd9Sstevel@tonic-gate 	 */
837c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
847c478bd9Sstevel@tonic-gate 	if (argc < 2)
857c478bd9Sstevel@tonic-gate 		usage();
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate 	--argc; ++argv;
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate 	pp = getuser((user = getuid()));
907c478bd9Sstevel@tonic-gate 	if (pp == NULL)
917c478bd9Sstevel@tonic-gate 		atabort(INVALIDUSER);
927c478bd9Sstevel@tonic-gate 	if (strlcpy(login, pp, sizeof (login)) >= sizeof (login))
937c478bd9Sstevel@tonic-gate 		atabort(NAMETOOLONG);
947c478bd9Sstevel@tonic-gate 	if (strlcpy(login_authchk, pp, sizeof (login_authchk))
957c478bd9Sstevel@tonic-gate 	    >= sizeof (NAMETOOLONG))
967c478bd9Sstevel@tonic-gate 		atabort(INVALIDUSER);
977c478bd9Sstevel@tonic-gate 	if (!allowed(login, ATALLOW, ATDENY))
987c478bd9Sstevel@tonic-gate 		atabort(NOTALLOWED);
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate 	/*
1017c478bd9Sstevel@tonic-gate 	 * Process command line flags.
1027c478bd9Sstevel@tonic-gate 	 * Special case the "-" option so that others may be grouped.
1037c478bd9Sstevel@tonic-gate 	 */
1047c478bd9Sstevel@tonic-gate 	while (argc > 0 && **argv == '-') {
1057c478bd9Sstevel@tonic-gate 		*(*argv)++;
106*032624d5Sbasabi 		while (**argv) {
107*032624d5Sbasabi 			switch (*(*argv)++) {
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate 			case 'a':	++allflag;
1107c478bd9Sstevel@tonic-gate 					break;
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate 			case 'f':	++fflag;
1137c478bd9Sstevel@tonic-gate 					break;
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate 			case 'i':	++iflag;
1167c478bd9Sstevel@tonic-gate 					break;
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate 			default:	usage();
1197c478bd9Sstevel@tonic-gate 			}
120*032624d5Sbasabi 		}
1217c478bd9Sstevel@tonic-gate 		++argv; --argc;
1227c478bd9Sstevel@tonic-gate 	}
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 	/*
1257c478bd9Sstevel@tonic-gate 	 * If all jobs are to be removed and extra command line arguments
1267c478bd9Sstevel@tonic-gate 	 * are given, print usage info and exit.
1277c478bd9Sstevel@tonic-gate 	 */
1287c478bd9Sstevel@tonic-gate 	if (allflag && argc)
1297c478bd9Sstevel@tonic-gate 		usage();
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate 	/*
1327c478bd9Sstevel@tonic-gate 	 * If only certain jobs are to be removed and no job #'s or user
1337c478bd9Sstevel@tonic-gate 	 * names are specified, print usage info and exit.
1347c478bd9Sstevel@tonic-gate 	 */
1357c478bd9Sstevel@tonic-gate 	if (!allflag && !argc)
1367c478bd9Sstevel@tonic-gate 		usage();
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 	/*
1397c478bd9Sstevel@tonic-gate 	 * If interactive removal and quiet removal are requested, override
1407c478bd9Sstevel@tonic-gate 	 * quiet removal and run interactively.
1417c478bd9Sstevel@tonic-gate 	 */
1427c478bd9Sstevel@tonic-gate 	if (iflag && fflag)
1437c478bd9Sstevel@tonic-gate 		fflag = 0;
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 	/*
1477c478bd9Sstevel@tonic-gate 	 * Move to spooling directory and get a list of the files in the
1487c478bd9Sstevel@tonic-gate 	 * spooling area.
1497c478bd9Sstevel@tonic-gate 	 */
1507c478bd9Sstevel@tonic-gate 	numjobs = getjoblist(&namelist, &statlist, strcmp);
1517c478bd9Sstevel@tonic-gate 	/*
1527c478bd9Sstevel@tonic-gate 	 * If all jobs belonging to the user are to be removed, compare
1537c478bd9Sstevel@tonic-gate 	 * the user's id to the owner of the file. If they match, remove
1547c478bd9Sstevel@tonic-gate 	 * the file. If the user is the super-user, don't bother comparing
1557c478bd9Sstevel@tonic-gate 	 * the id's. After all files are removed, exit (status 0).
1567c478bd9Sstevel@tonic-gate 	 */
1577c478bd9Sstevel@tonic-gate 	if (allflag) {
1587c478bd9Sstevel@tonic-gate 		for (i = 0; i < numjobs; ++i) {
1597c478bd9Sstevel@tonic-gate 			if (chkauthattr(CRONADMIN_AUTH, login_authchk) ||
1607c478bd9Sstevel@tonic-gate 			    user == statlist[i]->st_uid)
1617c478bd9Sstevel@tonic-gate 				(void) removentry(namelist[i]->d_name,
1627c478bd9Sstevel@tonic-gate 				    statlist[i], user);
1637c478bd9Sstevel@tonic-gate 		}
1647c478bd9Sstevel@tonic-gate 		exit(0);
1657c478bd9Sstevel@tonic-gate 	}
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 	/*
1687c478bd9Sstevel@tonic-gate 	 * If only certain jobs are to be removed, interpret each command
1697c478bd9Sstevel@tonic-gate 	 * line argument. A check is done to see if it is a user's name or
1707c478bd9Sstevel@tonic-gate 	 * a job number (inode #). If it's a user's name, compare the argument
1717c478bd9Sstevel@tonic-gate 	 * to the files owner. If it's a job number, compare the argument to
1727c478bd9Sstevel@tonic-gate 	 * the file name. In either case, if a match occurs, try to
1737c478bd9Sstevel@tonic-gate 	 * remove the file.
1747c478bd9Sstevel@tonic-gate 	 */
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	while (argc--) {
1777c478bd9Sstevel@tonic-gate 		jobexists = 0;
1787c478bd9Sstevel@tonic-gate 		for (i = 0; i < numjobs; ++i) {
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 			/* if the inode number is 0, this entry was removed */
1817c478bd9Sstevel@tonic-gate 			if (statlist[i]->st_ino == 0)
1827c478bd9Sstevel@tonic-gate 				continue;
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 			/*
1857c478bd9Sstevel@tonic-gate 			 * if argv is a username, compare his/her uid to
1867c478bd9Sstevel@tonic-gate 			 * the uid of the owner of the file......
1877c478bd9Sstevel@tonic-gate 			 */
1887c478bd9Sstevel@tonic-gate 			if (pwd = getpwnam(*argv)) {
1897c478bd9Sstevel@tonic-gate 				if (statlist[i]->st_uid != pwd->pw_uid)
1907c478bd9Sstevel@tonic-gate 					continue;
1917c478bd9Sstevel@tonic-gate 			/*
1927c478bd9Sstevel@tonic-gate 			 * otherwise, we assume that the argv is a job # and
1937c478bd9Sstevel@tonic-gate 			 * thus compare argv to the file name.
1947c478bd9Sstevel@tonic-gate 			 */
1957c478bd9Sstevel@tonic-gate 			} else {
1967c478bd9Sstevel@tonic-gate 				if (strcmp(namelist[i]->d_name, *argv))
1977c478bd9Sstevel@tonic-gate 					continue;
1987c478bd9Sstevel@tonic-gate 			}
1997c478bd9Sstevel@tonic-gate 			++jobexists;
2007c478bd9Sstevel@tonic-gate 			/*
2017c478bd9Sstevel@tonic-gate 			 * if the entry is ultimately removed, don't
2027c478bd9Sstevel@tonic-gate 			 * try to remove it again later.
2037c478bd9Sstevel@tonic-gate 			 */
204*032624d5Sbasabi 			if (removentry(namelist[i]->d_name, statlist[i],
205*032624d5Sbasabi 			    user)) {
2067c478bd9Sstevel@tonic-gate 				statlist[i]->st_ino = 0;
2077c478bd9Sstevel@tonic-gate 			}
2087c478bd9Sstevel@tonic-gate 		}
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 		/*
2117c478bd9Sstevel@tonic-gate 		 * If a requested argument doesn't exist, print a message.
2127c478bd9Sstevel@tonic-gate 		 */
2137c478bd9Sstevel@tonic-gate 		if (!jobexists && !fflag) {
214*032624d5Sbasabi 			fprintf(stderr, "atrm: %s: no such job number\n",
215*032624d5Sbasabi 			    *argv);
2167c478bd9Sstevel@tonic-gate 		}
2177c478bd9Sstevel@tonic-gate 		++argv;
2187c478bd9Sstevel@tonic-gate 	}
219*032624d5Sbasabi 	return (0);
2207c478bd9Sstevel@tonic-gate }
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate /*
2237c478bd9Sstevel@tonic-gate  * Print usage info and exit.
2247c478bd9Sstevel@tonic-gate  */
225*032624d5Sbasabi static void
226*032624d5Sbasabi usage(void)
2277c478bd9Sstevel@tonic-gate {
2287c478bd9Sstevel@tonic-gate 	fprintf(stderr, "usage: atrm [-f] [-i] [-a] [[job #] [user] ...]\n");
2297c478bd9Sstevel@tonic-gate 	exit(1);
2307c478bd9Sstevel@tonic-gate }
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate /*
2347c478bd9Sstevel@tonic-gate  * Remove an entry from the queue. The access of the file is checked for
2357c478bd9Sstevel@tonic-gate  * write permission (since all jobs are mode 644). If access is granted,
2367c478bd9Sstevel@tonic-gate  * unlink the file. If the fflag (suppress announcements) is not set,
2377c478bd9Sstevel@tonic-gate  * print the job number that we are removing and the result of the access
2387c478bd9Sstevel@tonic-gate  * check (either "permission denied" or "removed"). If we are running
2397c478bd9Sstevel@tonic-gate  * interactively (iflag), prompt the user before we unlink the file. If
2407c478bd9Sstevel@tonic-gate  * the super-user is removing jobs, inform him/her who owns each file before
2417c478bd9Sstevel@tonic-gate  * it is removed.  Return TRUE if file removed, else FALSE.
2427c478bd9Sstevel@tonic-gate  */
2437c478bd9Sstevel@tonic-gate int
244*032624d5Sbasabi removentry(char *filename, struct stat *statptr, uid_t user)
2457c478bd9Sstevel@tonic-gate {
2467c478bd9Sstevel@tonic-gate 	struct passwd *pwd;
2477c478bd9Sstevel@tonic-gate 	char *pp;
2487c478bd9Sstevel@tonic-gate 	char *getuser();
2497c478bd9Sstevel@tonic-gate 	int r;
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 	if (!fflag)
2527c478bd9Sstevel@tonic-gate 		printf("%s: ", filename);
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 	if (user != statptr->st_uid &&
2557c478bd9Sstevel@tonic-gate 	    !chkauthattr(CRONADMIN_AUTH, login_authchk)) {
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 		if (!fflag) {
2587c478bd9Sstevel@tonic-gate 			printf("permission denied\n");
2597c478bd9Sstevel@tonic-gate 		}
2607c478bd9Sstevel@tonic-gate 		return (0);
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 	} else {
2637c478bd9Sstevel@tonic-gate 		if (iflag) {
2647c478bd9Sstevel@tonic-gate 			if (chkauthattr(CRONADMIN_AUTH, login_authchk)) {
2657c478bd9Sstevel@tonic-gate 				printf("\t(owned by ");
2667c478bd9Sstevel@tonic-gate 				powner(filename);
2677c478bd9Sstevel@tonic-gate 				printf(") ");
2687c478bd9Sstevel@tonic-gate 			}
2697c478bd9Sstevel@tonic-gate 			printf("remove it? ");
2707c478bd9Sstevel@tonic-gate 			if (!yes())
2717c478bd9Sstevel@tonic-gate 				return (0);
2727c478bd9Sstevel@tonic-gate 		}
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 		if (chkauthattr(CRONADMIN_AUTH, login_authchk)) {
2757c478bd9Sstevel@tonic-gate 			pp = getuser((uid_t)statptr->st_uid);
2767c478bd9Sstevel@tonic-gate 			if (pp == NULL)
2777c478bd9Sstevel@tonic-gate 				atabort(INVALIDUSER);
2787c478bd9Sstevel@tonic-gate 			if (strlcpy(login, pp, sizeof (login)) >=
2797c478bd9Sstevel@tonic-gate 			    sizeof (login))
2807c478bd9Sstevel@tonic-gate 				atabort(NAMETOOLONG);
2817c478bd9Sstevel@tonic-gate 		}
2827c478bd9Sstevel@tonic-gate 		cron_sendmsg(DELETE, login, filename, AT);
2837c478bd9Sstevel@tonic-gate 		if ((r = unlink(filename)) < 0) {
2847c478bd9Sstevel@tonic-gate 			if (!fflag) {
2857c478bd9Sstevel@tonic-gate 				fputs("could not remove\n", stdout);
2867c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "atrm: %s: %s\n",
2877c478bd9Sstevel@tonic-gate 				    filename, errmsg(errno));
2887c478bd9Sstevel@tonic-gate 			}
2897c478bd9Sstevel@tonic-gate 			audit_at_delete(filename, NULL, r);
2907c478bd9Sstevel@tonic-gate 			return (0);
2917c478bd9Sstevel@tonic-gate 		}
2927c478bd9Sstevel@tonic-gate 		audit_at_delete(filename, NULL, r);
2937c478bd9Sstevel@tonic-gate 		if (!fflag && !iflag)
2947c478bd9Sstevel@tonic-gate 			printf("removed\n");
2957c478bd9Sstevel@tonic-gate 		return (1);
2967c478bd9Sstevel@tonic-gate 	}
2977c478bd9Sstevel@tonic-gate }
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate /*
3007c478bd9Sstevel@tonic-gate  * Print the owner of the job. This is the owner of the spoolfile.
3017c478bd9Sstevel@tonic-gate  * If we run into trouble getting the name, we'll just print "???".
3027c478bd9Sstevel@tonic-gate  */
303*032624d5Sbasabi static void
304*032624d5Sbasabi powner(char *file)
3057c478bd9Sstevel@tonic-gate {
3067c478bd9Sstevel@tonic-gate 	struct stat statb;
3077c478bd9Sstevel@tonic-gate 	char *getname();
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	if (stat(file, &statb) < 0) {
3107c478bd9Sstevel@tonic-gate 		printf("%s", "???");
3117c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "atrm: Couldn't stat spoolfile %s: %s\n",
3127c478bd9Sstevel@tonic-gate 		    file, errmsg(errno));
313*032624d5Sbasabi 		return;
3147c478bd9Sstevel@tonic-gate 	}
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	printf("%s", getname(statb.st_uid));
3177c478bd9Sstevel@tonic-gate }
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate int
321*032624d5Sbasabi getjoblist(struct dirent ***namelistp, struct stat ***statlistp,
322*032624d5Sbasabi     int (*sortfunc)())
3237c478bd9Sstevel@tonic-gate {
324*032624d5Sbasabi 	int numjobs;
325*032624d5Sbasabi 	struct dirent **namelist;
326*032624d5Sbasabi 	int i;
327*032624d5Sbasabi 	struct stat *statptr;	/* pointer to file stat structure */
328*032624d5Sbasabi 	struct stat **statlist;
3297c478bd9Sstevel@tonic-gate 	extern int alphasort();		/* sort jobs by date of execution */
3307c478bd9Sstevel@tonic-gate 	extern int filewanted();	/* should a file be listed in queue? */
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 	if (chdir(ATDIR) < 0)
3337c478bd9Sstevel@tonic-gate 		atabortperror(CANTCD);
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	/*
3367c478bd9Sstevel@tonic-gate 	 * Get a list of the files in the spooling area.
3377c478bd9Sstevel@tonic-gate 	 */
3387c478bd9Sstevel@tonic-gate 	if ((numjobs = ascandir(".", namelistp, filewanted, sortfunc)) < 0)
3397c478bd9Sstevel@tonic-gate 		atabortperror(NOREADDIR);
3407c478bd9Sstevel@tonic-gate 
341*032624d5Sbasabi 	if ((statlist =
342*032624d5Sbasabi 	    (struct stat **)malloc(numjobs * sizeof (struct stat ***)))
343*032624d5Sbasabi 	    == NULL)
3447c478bd9Sstevel@tonic-gate 		atabort("Out of memory");
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	namelist = *namelistp;
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 	/*
3497c478bd9Sstevel@tonic-gate 	 * Build an array of pointers to the file stats for all jobs in
3507c478bd9Sstevel@tonic-gate 	 * the spooling area.
3517c478bd9Sstevel@tonic-gate 	 */
3527c478bd9Sstevel@tonic-gate 	for (i = 0; i < numjobs; ++i) {
3537c478bd9Sstevel@tonic-gate 		statptr = (struct stat *)malloc(sizeof (struct stat));
3547c478bd9Sstevel@tonic-gate 		if (statptr == NULL)
3557c478bd9Sstevel@tonic-gate 			atabort("Out of memory");
3567c478bd9Sstevel@tonic-gate 		if (stat(namelist[i]->d_name, statptr) < 0) {
357*032624d5Sbasabi 			atperror2("Can't stat", namelist[i]->d_name);
3587c478bd9Sstevel@tonic-gate 			continue;
3597c478bd9Sstevel@tonic-gate 		}
3607c478bd9Sstevel@tonic-gate 		statlist[i] = statptr;
3617c478bd9Sstevel@tonic-gate 	}
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	*statlistp = statlist;
3647c478bd9Sstevel@tonic-gate 	return (numjobs);
3657c478bd9Sstevel@tonic-gate }
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate /*
3697c478bd9Sstevel@tonic-gate  * Get answer to interactive prompts, eating all characters beyond the first
3707c478bd9Sstevel@tonic-gate  * one. If a 'y' is typed, return 1.
3717c478bd9Sstevel@tonic-gate  */
372*032624d5Sbasabi int
373*032624d5Sbasabi yes(void)
3747c478bd9Sstevel@tonic-gate {
375*032624d5Sbasabi 	int ch;				/* dummy variable */
376*032624d5Sbasabi 	int ch1;			/* dummy variable */
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate 	ch = ch1 = getchar();
3797c478bd9Sstevel@tonic-gate 	while (ch1 != '\n' && ch1 != EOF)
3807c478bd9Sstevel@tonic-gate 		ch1 = getchar();
3817c478bd9Sstevel@tonic-gate 	if (isupper(ch))
3827c478bd9Sstevel@tonic-gate 		ch = tolower(ch);
3837c478bd9Sstevel@tonic-gate 	return (ch == 'y');
3847c478bd9Sstevel@tonic-gate }
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate /*
3887c478bd9Sstevel@tonic-gate  * Get the full login name of a person using his/her user id.
3897c478bd9Sstevel@tonic-gate  */
3907c478bd9Sstevel@tonic-gate char *
391*032624d5Sbasabi getname(uid_t uid)
3927c478bd9Sstevel@tonic-gate {
393*032624d5Sbasabi 	struct passwd *pwdinfo;		/* password info structure */
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 	if ((pwdinfo = getpwuid(uid)) == 0)
3977c478bd9Sstevel@tonic-gate 		return ("???");
3987c478bd9Sstevel@tonic-gate 	return (pwdinfo->pw_name);
3997c478bd9Sstevel@tonic-gate }
4007c478bd9Sstevel@tonic-gate 
401*032624d5Sbasabi static void
402*032624d5Sbasabi aterror(char *msg)
4037c478bd9Sstevel@tonic-gate {
4047c478bd9Sstevel@tonic-gate 	fprintf(stderr, "atrm: %s\n", msg);
4057c478bd9Sstevel@tonic-gate }
4067c478bd9Sstevel@tonic-gate 
407*032624d5Sbasabi static void
408*032624d5Sbasabi atperror(char *msg)
4097c478bd9Sstevel@tonic-gate {
4107c478bd9Sstevel@tonic-gate 	fprintf(stderr, "atrm: %s: %s\n", msg, errmsg(errno));
4117c478bd9Sstevel@tonic-gate }
4127c478bd9Sstevel@tonic-gate 
413*032624d5Sbasabi static void
414*032624d5Sbasabi atperror2(char *msg, char *name)
415*032624d5Sbasabi {
416*032624d5Sbasabi 	fprintf(stderr, "atrm: %s %s: %s\n", msg, name, errmsg(errno));
417*032624d5Sbasabi }
418*032624d5Sbasabi 
419*032624d5Sbasabi static void
420*032624d5Sbasabi atabort(char *msg)
4217c478bd9Sstevel@tonic-gate {
4227c478bd9Sstevel@tonic-gate 	aterror(msg);
4237c478bd9Sstevel@tonic-gate 	exit(1);
4247c478bd9Sstevel@tonic-gate }
4257c478bd9Sstevel@tonic-gate 
426*032624d5Sbasabi static void
427*032624d5Sbasabi atabortperror(char *msg)
4287c478bd9Sstevel@tonic-gate {
4297c478bd9Sstevel@tonic-gate 	atperror(msg);
4307c478bd9Sstevel@tonic-gate 	exit(1);
4317c478bd9Sstevel@tonic-gate }
432