xref: /onnv-gate/usr/src/cmd/cron/atq.c (revision 11115:bcfb2bb98fca)
1523Sbasabi /*
2*11115SNobutomo.Nakano@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
3523Sbasabi  * Use is subject to license terms.
4523Sbasabi  */
5523Sbasabi 
60Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
70Sstevel@tonic-gate /*	  All Rights Reserved  	*/
80Sstevel@tonic-gate 
90Sstevel@tonic-gate 
100Sstevel@tonic-gate /*
110Sstevel@tonic-gate  * Copyright (c) 1983 Regents of the University of California.
120Sstevel@tonic-gate  * All rights reserved.  The Berkeley software License Agreement
130Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
140Sstevel@tonic-gate  */
150Sstevel@tonic-gate 
160Sstevel@tonic-gate /*
170Sstevel@tonic-gate  *
180Sstevel@tonic-gate  *	Synopsis:  atq [ -c ] [ -n ] [ name ... ]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  *
210Sstevel@tonic-gate  *	Print the queue of files waiting to be executed. These files
220Sstevel@tonic-gate  *	were created by using the "at" command and are located in the
230Sstevel@tonic-gate  *	directory defined by ATDIR.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <stdio.h>
270Sstevel@tonic-gate #include <sys/types.h>
280Sstevel@tonic-gate #include <sys/file.h>
290Sstevel@tonic-gate #include <dirent.h>
300Sstevel@tonic-gate #include <sys/stat.h>
310Sstevel@tonic-gate #include <time.h>
320Sstevel@tonic-gate #include <pwd.h>
330Sstevel@tonic-gate #include <ctype.h>
340Sstevel@tonic-gate #include <unistd.h>
350Sstevel@tonic-gate #include <locale.h>
360Sstevel@tonic-gate #include <errno.h>
374774Sas145665 #include <stdlib.h>
384774Sas145665 #include <string.h>
390Sstevel@tonic-gate #include "cron.h"
400Sstevel@tonic-gate 
410Sstevel@tonic-gate extern char	*errmsg();
420Sstevel@tonic-gate extern char	*strchr();
430Sstevel@tonic-gate 
440Sstevel@tonic-gate /*
450Sstevel@tonic-gate  * Months of the year
460Sstevel@tonic-gate  */
470Sstevel@tonic-gate static char *mthnames[12] = {
480Sstevel@tonic-gate 	"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
490Sstevel@tonic-gate 	"Aug", "Sep", "Oct", "Nov", "Dec",
500Sstevel@tonic-gate };
510Sstevel@tonic-gate 
520Sstevel@tonic-gate int numentries;				/* number of entries in spooling area */
530Sstevel@tonic-gate int namewanted = 0;			/* print jobs for a certain person */
540Sstevel@tonic-gate struct dirent **queue;			/* the queue itself */
550Sstevel@tonic-gate 
560Sstevel@tonic-gate #define	INVALIDUSER	"you are not a valid user (no entry in /etc/passwd)"
570Sstevel@tonic-gate #define	NOTALLOWED	"you are not authorized to use at.  Sorry."
580Sstevel@tonic-gate 
59523Sbasabi static void atabortperror(char *msg);
60523Sbasabi static void atabort(char *msg);
61523Sbasabi static void aterror(char *msg);
62523Sbasabi static void atperror(char *msg);
63523Sbasabi static void usage(void);
64523Sbasabi static void printjobname(char *file);
65523Sbasabi static void printdate(char *filename);
66523Sbasabi static void printrank(int n);
67523Sbasabi static void printqueue(uid_t *uidlist, int nuids);
680Sstevel@tonic-gate 
69523Sbasabi int
main(int argc,char ** argv)70523Sbasabi main(int argc, char **argv)
710Sstevel@tonic-gate {
720Sstevel@tonic-gate 
73523Sbasabi 	struct passwd *pp;	/* password file entry pointer */
740Sstevel@tonic-gate 	struct passwd pr;
75523Sbasabi 	int i;
760Sstevel@tonic-gate 	int cflag = 0;			/* print in order of creation time */
770Sstevel@tonic-gate 	int nflag = 0;			/* just print the number of jobs in */
780Sstevel@tonic-gate 					/* queue */
790Sstevel@tonic-gate 	extern int creation();		/* sort jobs by date of creation */
800Sstevel@tonic-gate 	extern int execution();		/* sort jobs by date of execution */
810Sstevel@tonic-gate 	int filewanted();		/* should file be included in queue? */
820Sstevel@tonic-gate 	int countfiles();		/* count the number of files in queue */
830Sstevel@tonic-gate 					/* for a given person */
840Sstevel@tonic-gate 	uid_t *uidlist = NULL;		/* array of spec. owner ID(s) requ. */
850Sstevel@tonic-gate 	int argnum = 0;			/* number of names passed as arg't */
860Sstevel@tonic-gate 	int badarg = 0;
870Sstevel@tonic-gate 	char *c;
880Sstevel@tonic-gate 
890Sstevel@tonic-gate 
900Sstevel@tonic-gate 	--argc, ++argv;
910Sstevel@tonic-gate 
920Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
930Sstevel@tonic-gate 	pp = getpwuid(getuid());
940Sstevel@tonic-gate 	pr.pw_uid = pp->pw_uid;
950Sstevel@tonic-gate 	pr.pw_name = pp->pw_name;
960Sstevel@tonic-gate 
970Sstevel@tonic-gate 	if (pp == NULL)
980Sstevel@tonic-gate 		atabort(INVALIDUSER);
990Sstevel@tonic-gate 	if (!allowed(pp->pw_name, ATALLOW, ATDENY))
1000Sstevel@tonic-gate 		atabort(NOTALLOWED);
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate 	/*
1030Sstevel@tonic-gate 	 * Interpret command line flags if they exist.
1040Sstevel@tonic-gate 	 */
1050Sstevel@tonic-gate 	while (argc > 0 && **argv == '-') {
1060Sstevel@tonic-gate 		(*argv)++;
1070Sstevel@tonic-gate 		while (**argv) {
1080Sstevel@tonic-gate 			switch (*(*argv)++) {
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate 			case 'c' :	cflag++;
1110Sstevel@tonic-gate 					break;
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate 			case 'n' :	nflag++;
1140Sstevel@tonic-gate 					break;
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate 			default	 :	usage();
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate 			}
1190Sstevel@tonic-gate 		}
1200Sstevel@tonic-gate 		--argc, ++argv;
1210Sstevel@tonic-gate 	}
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate 	/*
1240Sstevel@tonic-gate 	 * If a certain name (or names) is requested, set a pointer to the
1250Sstevel@tonic-gate 	 * beginning of the list.
1260Sstevel@tonic-gate 	 */
1270Sstevel@tonic-gate 	if (argc > 0) {
1280Sstevel@tonic-gate 		++namewanted;
1290Sstevel@tonic-gate 		uidlist = (uid_t *)malloc(argc * sizeof (uid_t));
1300Sstevel@tonic-gate 		if (uidlist == NULL)
1310Sstevel@tonic-gate 			atabortperror("can't allocate list of users");
1320Sstevel@tonic-gate 		for (i = 0; i < argc; i++) {
133*11115SNobutomo.Nakano@Sun.COM 			if (cron_admin(pr.pw_name) ||
1344774Sas145665 			    strcmp(pr.pw_name, argv[i]) == 0) {
1350Sstevel@tonic-gate 				if ((pp = getpwnam(argv[i])) == NULL) {
1360Sstevel@tonic-gate 					(void) fprintf(stderr,
1370Sstevel@tonic-gate 					    "atq: No such user %s\n", argv[i]);
1380Sstevel@tonic-gate 					exit(1);
1390Sstevel@tonic-gate 				}
1400Sstevel@tonic-gate 				uidlist[argnum] = pp->pw_uid;
1410Sstevel@tonic-gate 				argnum++;
1420Sstevel@tonic-gate 			}
1430Sstevel@tonic-gate 			else
1440Sstevel@tonic-gate 				badarg++;
1450Sstevel@tonic-gate 		}
1460Sstevel@tonic-gate 		if (badarg)
1470Sstevel@tonic-gate 			if (argnum)
1480Sstevel@tonic-gate 				printf("Printing queue information only "
1490Sstevel@tonic-gate 				    "for %s:\n", pr.pw_name);
1500Sstevel@tonic-gate 			else {
1510Sstevel@tonic-gate 				printf("atq: Non-priviledged user cannot "
1520Sstevel@tonic-gate 				    "request information regarding other "
1530Sstevel@tonic-gate 				    "users\n");
1540Sstevel@tonic-gate 				exit(1);
1550Sstevel@tonic-gate 			}
156*11115SNobutomo.Nakano@Sun.COM 	} else if (!cron_admin(pr.pw_name)) {
1570Sstevel@tonic-gate 		/* no argument specified and the invoker is not root */
1580Sstevel@tonic-gate 		++namewanted;
1590Sstevel@tonic-gate 		argnum = 1;
1600Sstevel@tonic-gate 		if ((uidlist = (uid_t *)malloc(sizeof (uid_t))) == NULL)
1610Sstevel@tonic-gate 			atabortperror("can't allocate list of users");
1620Sstevel@tonic-gate 		*uidlist = pr.pw_uid;
1630Sstevel@tonic-gate 	}
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 	/*
1660Sstevel@tonic-gate 	 * Move to the spooling area and scan the directory, placing the
1670Sstevel@tonic-gate 	 * files in the queue structure. The queue comes back sorted by
1680Sstevel@tonic-gate 	 * execution time or creation time.
1690Sstevel@tonic-gate 	 */
1700Sstevel@tonic-gate 	if (chdir(ATDIR) == -1)
1710Sstevel@tonic-gate 		atabortperror(ATDIR);
1726628Sjk217608 	if ((numentries = scandir(".", &queue, filewanted,
1730Sstevel@tonic-gate 	    (cflag) ? creation : execution)) < 0)
1740Sstevel@tonic-gate 		atabortperror(ATDIR);
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate 	/*
1780Sstevel@tonic-gate 	 * Either print a message stating:
1790Sstevel@tonic-gate 	 *
1800Sstevel@tonic-gate 	 *	1) that the spooling area is empty.
1810Sstevel@tonic-gate 	 *	2) the number of jobs in the spooling area.
1820Sstevel@tonic-gate 	 *	3) the number of jobs in the spooling area belonging to
1830Sstevel@tonic-gate 	 *	   a certain person.
1840Sstevel@tonic-gate 	 *	4) that the person requested doesn't have any files in the
1850Sstevel@tonic-gate 	 *	   spooling area.
1860Sstevel@tonic-gate 	 *
1870Sstevel@tonic-gate 	 * or send the queue off to "printqueue" for printing.
1880Sstevel@tonic-gate 	 *
1890Sstevel@tonic-gate 	 * This whole process might seem a bit elaborate, but it's worthwhile
1900Sstevel@tonic-gate 	 * to print some informative messages for the user.
1910Sstevel@tonic-gate 	 *
1920Sstevel@tonic-gate 	 */
1930Sstevel@tonic-gate 	if ((numentries == 0) && (!nflag)) {
1940Sstevel@tonic-gate 		printf("no files in queue.\n");
1950Sstevel@tonic-gate 		exit(0);
1960Sstevel@tonic-gate 	}
1970Sstevel@tonic-gate 	if (nflag) {
1980Sstevel@tonic-gate 		printf("%d\n", (namewanted) ?
1990Sstevel@tonic-gate 		    countfiles(uidlist, argnum) : numentries);
2000Sstevel@tonic-gate 		exit(0);
2010Sstevel@tonic-gate 	}
2020Sstevel@tonic-gate 	if ((namewanted) && (countfiles(uidlist, argnum) == 0)) {
2030Sstevel@tonic-gate 		if (argnum == 1)
2040Sstevel@tonic-gate 			if (argnum != argc) c = pr.pw_name;
2050Sstevel@tonic-gate 			else c = *argv;
2060Sstevel@tonic-gate 		printf("no files for %s.\n", (argnum == 1) ?
2074774Sas145665 		    c : "specified users");
2080Sstevel@tonic-gate 		exit(0);
2090Sstevel@tonic-gate 	}
2100Sstevel@tonic-gate 	printqueue(uidlist, argnum);
211523Sbasabi 	return (0);
2120Sstevel@tonic-gate }
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate /*
2150Sstevel@tonic-gate  * Count the number of jobs in the spooling area owned by a certain person(s).
2160Sstevel@tonic-gate  */
217523Sbasabi int
countfiles(uid_t * uidlist,int nuids)218523Sbasabi countfiles(uid_t *uidlist, int nuids)
2190Sstevel@tonic-gate {
220523Sbasabi 	int i, j;			/* for loop indices */
2210Sstevel@tonic-gate 	int entryfound;				/* found file owned by users */
2220Sstevel@tonic-gate 	int numfiles = 0;			/* number of files owned by a */
2230Sstevel@tonic-gate 						/* certain person(s) */
224523Sbasabi 	uid_t *ptr;			/* scratch pointer */
2250Sstevel@tonic-gate 	struct stat stbuf;			/* buffer for file stats */
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 	/*
2290Sstevel@tonic-gate 	 * For each file in the queue, see if the user(s) own the file. We
2300Sstevel@tonic-gate 	 * have to use "entryfound" (rather than simply incrementing "numfiles")
2310Sstevel@tonic-gate 	 * so that if a person's name appears twice on the command line we
2320Sstevel@tonic-gate 	 * don't double the number of files owned by him/her.
2330Sstevel@tonic-gate 	 */
2340Sstevel@tonic-gate 	for (i = 0; i < numentries; i++) {
2350Sstevel@tonic-gate 		if ((stat(queue[i]->d_name, &stbuf)) < 0) {
2360Sstevel@tonic-gate 			continue;
2370Sstevel@tonic-gate 		}
2380Sstevel@tonic-gate 		ptr = uidlist;
2390Sstevel@tonic-gate 		entryfound = 0;
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate 		for (j = 0; j < nuids; j++) {
2420Sstevel@tonic-gate 			if (*ptr == stbuf.st_uid)
2430Sstevel@tonic-gate 				++entryfound;
2440Sstevel@tonic-gate 			++ptr;
2450Sstevel@tonic-gate 		}
2460Sstevel@tonic-gate 		if (entryfound)
2470Sstevel@tonic-gate 			++numfiles;
2480Sstevel@tonic-gate 	}
2490Sstevel@tonic-gate 	return (numfiles);
2500Sstevel@tonic-gate }
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate /*
2530Sstevel@tonic-gate  * Print the queue. If only jobs belonging to a certain person(s) are requested,
2540Sstevel@tonic-gate  * only print jobs that belong to that person(s).
2550Sstevel@tonic-gate  */
256523Sbasabi static void
printqueue(uid_t * uidlist,int nuids)257523Sbasabi printqueue(uid_t *uidlist, int nuids)
2580Sstevel@tonic-gate {
259523Sbasabi 	int i, j;			/* for loop indices */
2600Sstevel@tonic-gate 	int rank;				/* rank of a job */
2610Sstevel@tonic-gate 	int entryfound;				/* found file owned by users */
2620Sstevel@tonic-gate 	char *getname();
263523Sbasabi 	uid_t *ptr;			/* scratch pointer */
2640Sstevel@tonic-gate 	struct stat stbuf;			/* buffer for file stats */
2650Sstevel@tonic-gate 	char curqueue;				/* queue of current job */
2660Sstevel@tonic-gate 	char lastqueue;				/* queue of previous job */
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 	/*
2690Sstevel@tonic-gate 	 * Print the header for the queue.
2700Sstevel@tonic-gate 	 */
2710Sstevel@tonic-gate 	printf(" Rank	  Execution Date     Owner      Job            "
2720Sstevel@tonic-gate 	    "Queue   Job Name\n");
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 	/*
2750Sstevel@tonic-gate 	 * Print the queue. If a certain name(s) was requested, print only jobs
2760Sstevel@tonic-gate 	 * belonging to that person(s), otherwise print the entire queue.
2770Sstevel@tonic-gate 	 * Once again, we have to use "entryfound" (rather than simply
2780Sstevel@tonic-gate 	 * comparing each command line argument) so that if a person's name
2790Sstevel@tonic-gate 	 * appears twice we don't print each file owned by him/her twice.
2800Sstevel@tonic-gate 	 *
2810Sstevel@tonic-gate 	 *
2820Sstevel@tonic-gate 	 * "printrank", "printdate", and "printjobname" all take existing
2830Sstevel@tonic-gate 	 * data and display it in a friendly manner.
2840Sstevel@tonic-gate 	 *
2850Sstevel@tonic-gate 	 */
2860Sstevel@tonic-gate 	lastqueue = '\0';
2870Sstevel@tonic-gate 	for (i = 0; i < numentries; i++) {
2880Sstevel@tonic-gate 		if ((stat(queue[i]->d_name, &stbuf)) < 0) {
2890Sstevel@tonic-gate 			continue;
2900Sstevel@tonic-gate 		}
2910Sstevel@tonic-gate 		curqueue = *(strchr(queue[i]->d_name, '.') + 1);
2920Sstevel@tonic-gate 		if (curqueue != lastqueue) {
2930Sstevel@tonic-gate 			rank = 1;
2940Sstevel@tonic-gate 			lastqueue = curqueue;
2950Sstevel@tonic-gate 		}
2960Sstevel@tonic-gate 		if (namewanted) {
2970Sstevel@tonic-gate 			ptr = uidlist;
2980Sstevel@tonic-gate 			entryfound = 0;
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate 			for (j = 0; j < nuids; j++) {
3010Sstevel@tonic-gate 				if (*ptr == stbuf.st_uid)
3020Sstevel@tonic-gate 					++entryfound;
3030Sstevel@tonic-gate 				++ptr;
3040Sstevel@tonic-gate 			}
3050Sstevel@tonic-gate 			if (!entryfound)
3060Sstevel@tonic-gate 				continue;
3070Sstevel@tonic-gate 		}
3080Sstevel@tonic-gate 		printrank(rank++);
3090Sstevel@tonic-gate 		printdate(queue[i]->d_name);
3100Sstevel@tonic-gate 		printf("%-10s ", getname(stbuf.st_uid));
3110Sstevel@tonic-gate 		printf("%-14s ", queue[i]->d_name);
3120Sstevel@tonic-gate 		printf("  %c", curqueue);
3130Sstevel@tonic-gate 		printjobname(queue[i]->d_name);
3140Sstevel@tonic-gate 	}
3150Sstevel@tonic-gate 	++ptr;
3160Sstevel@tonic-gate }
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate /*
3190Sstevel@tonic-gate  * Get the uid of a person using his/her login name. Return -1 if no
3200Sstevel@tonic-gate  * such account name exists.
3210Sstevel@tonic-gate  */
3220Sstevel@tonic-gate uid_t
getid(char * name)323523Sbasabi getid(char *name)
3240Sstevel@tonic-gate {
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 	struct passwd *pwdinfo;			/* password info structure */
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate 	if ((pwdinfo = getpwnam(name)) == 0)
3300Sstevel@tonic-gate 		return ((uid_t)-1);
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 	return (pwdinfo->pw_uid);
3330Sstevel@tonic-gate }
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate /*
3360Sstevel@tonic-gate  * Get the full login name of a person using his/her user id.
3370Sstevel@tonic-gate  */
3380Sstevel@tonic-gate char *
getname(uid_t uid)339523Sbasabi getname(uid_t uid)
3400Sstevel@tonic-gate {
341523Sbasabi 	struct passwd *pwdinfo;	/* password info structure */
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 	if ((pwdinfo = getpwuid(uid)) == 0)
3450Sstevel@tonic-gate 		return ("???");
3460Sstevel@tonic-gate 	return (pwdinfo->pw_name);
3470Sstevel@tonic-gate }
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate /*
3500Sstevel@tonic-gate  * Print the rank of a job. (I've got to admit it, I stole it from "lpq")
3510Sstevel@tonic-gate  */
352523Sbasabi static void
printrank(int n)353523Sbasabi printrank(int n)
3540Sstevel@tonic-gate {
3550Sstevel@tonic-gate 	static char *r[] = {
3560Sstevel@tonic-gate 		"th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
3570Sstevel@tonic-gate 	};
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 	if ((n/10) == 1)
3600Sstevel@tonic-gate 		printf("%3d%-5s", n, "th");
3610Sstevel@tonic-gate 	else
3620Sstevel@tonic-gate 		printf("%3d%-5s", n, r[n%10]);
3630Sstevel@tonic-gate }
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate /*
3660Sstevel@tonic-gate  * Print the date that a job is to be executed. This takes some manipulation
3670Sstevel@tonic-gate  * of the file name.
3680Sstevel@tonic-gate  */
369523Sbasabi static void
printdate(char * filename)370523Sbasabi printdate(char *filename)
3710Sstevel@tonic-gate {
3720Sstevel@tonic-gate 	time_t	jobdate;
373523Sbasabi 	struct tm *unpackeddate;
3740Sstevel@tonic-gate 	char date[18];				/* reformatted execution date */
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 	/*
3770Sstevel@tonic-gate 	 * Convert the file name to a date.
3780Sstevel@tonic-gate 	 */
3790Sstevel@tonic-gate 	jobdate = num(&filename);
3800Sstevel@tonic-gate 	unpackeddate = localtime(&jobdate);
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 	/* years since 1900 + base century 1900 */
3830Sstevel@tonic-gate 	unpackeddate->tm_year += 1900;
3840Sstevel@tonic-gate 	/*
3850Sstevel@tonic-gate 	 * Format the execution date of a job.
3860Sstevel@tonic-gate 	 */
3870Sstevel@tonic-gate 	sprintf(date, "%3s %2d, %4d %02d:%02d", mthnames[unpackeddate->tm_mon],
3880Sstevel@tonic-gate 	    unpackeddate->tm_mday, unpackeddate->tm_year,
3890Sstevel@tonic-gate 	    unpackeddate->tm_hour, unpackeddate->tm_min);
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate 	/*
3920Sstevel@tonic-gate 	 * Print the date the job will be executed.
3930Sstevel@tonic-gate 	 */
3940Sstevel@tonic-gate 	printf("%-21.18s", date);
3950Sstevel@tonic-gate }
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate /*
3980Sstevel@tonic-gate  * Print a job name. If the old "at" has been used to create the spoolfile,
3990Sstevel@tonic-gate  * the three line header that the new version of "at" puts in the spoolfile.
4000Sstevel@tonic-gate  * Thus, we just print "???".
4010Sstevel@tonic-gate  */
402523Sbasabi static void
printjobname(char * file)403523Sbasabi printjobname(char *file)
4040Sstevel@tonic-gate {
4050Sstevel@tonic-gate 	char *ptr;				/* scratch pointer */
4060Sstevel@tonic-gate 	char jobname[28];			/* the job name */
4070Sstevel@tonic-gate 	FILE *filename;				/* job file in spooling area */
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 	/*
4100Sstevel@tonic-gate 	 * Open the job file and grab the third line.
4110Sstevel@tonic-gate 	 */
4120Sstevel@tonic-gate 	printf("     ");
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	if ((filename = fopen(file, "r")) == NULL) {
4150Sstevel@tonic-gate 		printf("%.27s\n", "???");
4160Sstevel@tonic-gate 		(void) fprintf(stderr, "atq: Can't open job file %s: %s\n",
4170Sstevel@tonic-gate 		    file, errmsg(errno));
4180Sstevel@tonic-gate 		return;
4190Sstevel@tonic-gate 	}
4200Sstevel@tonic-gate 	/*
4210Sstevel@tonic-gate 	 * Skip over the first and second lines.
4220Sstevel@tonic-gate 	 */
4230Sstevel@tonic-gate 	fscanf(filename, "%*[^\n]\n");
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 	/*
4260Sstevel@tonic-gate 	 * Now get the job name.
4270Sstevel@tonic-gate 	 */
4280Sstevel@tonic-gate 	if (fscanf(filename, ": jobname: %27s%*[^\n]\n", jobname) != 1) {
4290Sstevel@tonic-gate 		printf("%.27s\n", "???");
4300Sstevel@tonic-gate 		fclose(filename);
4310Sstevel@tonic-gate 		return;
4320Sstevel@tonic-gate 	}
4330Sstevel@tonic-gate 	fclose(filename);
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 	/*
4360Sstevel@tonic-gate 	 * Put a pointer at the begining of the line and remove the basename
4370Sstevel@tonic-gate 	 * from the job file.
4380Sstevel@tonic-gate 	 */
4390Sstevel@tonic-gate 	ptr = jobname;
4400Sstevel@tonic-gate 	if ((ptr = (char *)strrchr(jobname, '/')) != 0)
4410Sstevel@tonic-gate 		++ptr;
4420Sstevel@tonic-gate 	else
4430Sstevel@tonic-gate 		ptr = jobname;
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 	if (strlen(ptr) > 23)
4460Sstevel@tonic-gate 		printf("%.23s ...\n", ptr);
4470Sstevel@tonic-gate 	else
4480Sstevel@tonic-gate 		printf("%.27s\n", ptr);
4490Sstevel@tonic-gate }
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate /*
4546628Sjk217608  * Sort files by queue, time of creation, and sequence. (used by "scandir")
4550Sstevel@tonic-gate  */
456523Sbasabi int
creation(struct dirent ** d1,struct dirent ** d2)457523Sbasabi creation(struct dirent **d1, struct dirent **d2)
4580Sstevel@tonic-gate {
459523Sbasabi 	char *p1, *p2;
460523Sbasabi 	int i;
4610Sstevel@tonic-gate 	struct stat stbuf1, stbuf2;
462523Sbasabi 	int seq1, seq2;
4630Sstevel@tonic-gate 
4640Sstevel@tonic-gate 	if ((p1 = strchr((*d1)->d_name, '.')) == NULL)
4650Sstevel@tonic-gate 		return (0);
4660Sstevel@tonic-gate 	if ((p2 = strchr((*d2)->d_name, '.')) == NULL)
4670Sstevel@tonic-gate 		return (0);
4680Sstevel@tonic-gate 	p1++;
4690Sstevel@tonic-gate 	p2++;
4700Sstevel@tonic-gate 	if ((i = *p1++ - *p2++) != 0)
4710Sstevel@tonic-gate 		return (i);
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 	if (stat((*d1)->d_name, &stbuf1) < 0)
4740Sstevel@tonic-gate 		return (0);
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate 	if (stat((*d2)->d_name, &stbuf2) < 0)
4770Sstevel@tonic-gate 		return (0);
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 	if (stbuf1.st_ctime < stbuf2.st_ctime)
4800Sstevel@tonic-gate 		return (-1);
4810Sstevel@tonic-gate 	else if (stbuf1.st_ctime > stbuf2.st_ctime)
4820Sstevel@tonic-gate 		return (1);
4830Sstevel@tonic-gate 	p1++;
4840Sstevel@tonic-gate 	p2++;
4850Sstevel@tonic-gate 	seq1 = atoi(p1);
4860Sstevel@tonic-gate 	seq2 = atoi(p2);
4870Sstevel@tonic-gate 	return (seq1 - seq2);
4880Sstevel@tonic-gate }
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate /*
4916628Sjk217608  * Sort files by queue, time of execution, and sequence. (used by "scandir")
4920Sstevel@tonic-gate  */
493523Sbasabi int
execution(struct dirent ** d1,struct dirent ** d2)494523Sbasabi execution(struct dirent **d1, struct dirent **d2)
4950Sstevel@tonic-gate {
496523Sbasabi 	char *p1, *p2;
497523Sbasabi 	int i;
4980Sstevel@tonic-gate 	char *name1, *name2;
499523Sbasabi 	time_t time1, time2;
500523Sbasabi 	int seq1, seq2;
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 	name1 = (*d1)->d_name;
5030Sstevel@tonic-gate 	name2 = (*d2)->d_name;
5040Sstevel@tonic-gate 	if ((p1 = strchr(name1, '.')) == NULL)
5050Sstevel@tonic-gate 		return (1);
5060Sstevel@tonic-gate 	if ((p2 = strchr(name2, '.')) == NULL)
5070Sstevel@tonic-gate 		return (1);
5080Sstevel@tonic-gate 	p1++;
5090Sstevel@tonic-gate 	p2++;
5100Sstevel@tonic-gate 	if ((i = *p1++ - *p2++) != 0)
5110Sstevel@tonic-gate 		return (i);
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 	time1 = num(&name1);
5140Sstevel@tonic-gate 	time2 = num(&name2);
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 	if (time1 < time2)
5170Sstevel@tonic-gate 		return (-1);
5180Sstevel@tonic-gate 	else if (time1 > time2)
5190Sstevel@tonic-gate 		return (1);
5200Sstevel@tonic-gate 	p1++;
5210Sstevel@tonic-gate 	p2++;
5220Sstevel@tonic-gate 	seq1 = atoi(p1);
5230Sstevel@tonic-gate 	seq2 = atoi(p2);
5240Sstevel@tonic-gate 	return (seq1 - seq2);
5250Sstevel@tonic-gate }
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate /*
5290Sstevel@tonic-gate  * Print usage info and exit.
5300Sstevel@tonic-gate  */
531523Sbasabi static void
usage(void)532523Sbasabi usage(void)
5330Sstevel@tonic-gate {
5340Sstevel@tonic-gate 	fprintf(stderr, "usage:	atq [-c] [-n] [name ...]\n");
5350Sstevel@tonic-gate 	exit(1);
5360Sstevel@tonic-gate }
5370Sstevel@tonic-gate 
538523Sbasabi static void
aterror(char * msg)539523Sbasabi aterror(char *msg)
5400Sstevel@tonic-gate {
5410Sstevel@tonic-gate 	fprintf(stderr, "atq: %s\n", msg);
5420Sstevel@tonic-gate }
5430Sstevel@tonic-gate 
544523Sbasabi static void
atperror(char * msg)545523Sbasabi atperror(char *msg)
5460Sstevel@tonic-gate {
5470Sstevel@tonic-gate 	fprintf(stderr, "atq: %s: %s\n", msg, errmsg(errno));
5480Sstevel@tonic-gate }
5490Sstevel@tonic-gate 
550523Sbasabi static void
atabort(char * msg)551523Sbasabi atabort(char *msg)
5520Sstevel@tonic-gate {
5530Sstevel@tonic-gate 	aterror(msg);
5540Sstevel@tonic-gate 	exit(1);
5550Sstevel@tonic-gate }
5560Sstevel@tonic-gate 
557523Sbasabi static void
atabortperror(char * msg)558523Sbasabi atabortperror(char *msg)
5590Sstevel@tonic-gate {
5600Sstevel@tonic-gate 	atperror(msg);
5610Sstevel@tonic-gate 	exit(1);
5620Sstevel@tonic-gate }
563