8999 SMBIOS: cleanup 32-bit specific code
[unleashed.git] / usr / src / cmd / cron / atq.c
blob34cfb9e98ebdd1cd8661d461dc902d25c3d62ace
1 /*
2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 * Copyright (c) 2016 by Delphix. All rights reserved.
5 */
7 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
8 /* All Rights Reserved */
12 * Copyright (c) 1983 Regents of the University of California.
13 * All rights reserved. The Berkeley software License Agreement
14 * specifies the terms and conditions for redistribution.
19 * Synopsis: atq [ -c ] [ -n ] [ name ... ]
22 * Print the queue of files waiting to be executed. These files
23 * were created by using the "at" command and are located in the
24 * directory defined by ATDIR.
27 #include <stdio.h>
28 #include <sys/types.h>
29 #include <sys/file.h>
30 #include <dirent.h>
31 #include <sys/stat.h>
32 #include <time.h>
33 #include <pwd.h>
34 #include <ctype.h>
35 #include <unistd.h>
36 #include <locale.h>
37 #include <errno.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include "cron.h"
42 extern char *errmsg();
43 extern char *strchr();
46 * Months of the year
48 static char *mthnames[12] = {
49 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
50 "Aug", "Sep", "Oct", "Nov", "Dec",
53 int numentries; /* number of entries in spooling area */
54 int namewanted = 0; /* print jobs for a certain person */
55 struct dirent **queue; /* the queue itself */
57 #define INVALIDUSER "you are not a valid user (no entry in /etc/passwd)"
58 #define NOTALLOWED "you are not authorized to use at. Sorry."
60 static void atabortperror(char *msg);
61 static void atabort(char *msg);
62 static void aterror(char *msg);
63 static void atperror(char *msg);
64 static void usage(void);
65 static void printjobname(char *file);
66 static void printdate(char *filename);
67 static void printrank(int n);
68 static void printqueue(uid_t *uidlist, int nuids);
70 int
71 main(int argc, char **argv)
74 struct passwd *pp; /* password file entry pointer */
75 struct passwd pr;
76 int i;
77 int cflag = 0; /* print in order of creation time */
78 int nflag = 0; /* just print the number of jobs in */
79 /* queue */
80 extern int creation(); /* sort jobs by date of creation */
81 extern int execution(); /* sort jobs by date of execution */
82 int filewanted(); /* should file be included in queue? */
83 int countfiles(); /* count the number of files in queue */
84 /* for a given person */
85 uid_t *uidlist = NULL; /* array of spec. owner ID(s) requ. */
86 int argnum = 0; /* number of names passed as arg't */
87 int badarg = 0;
88 char *c;
91 --argc, ++argv;
93 (void) setlocale(LC_ALL, "");
94 pp = getpwuid(getuid());
95 pr.pw_uid = pp->pw_uid;
96 pr.pw_name = pp->pw_name;
98 if (pp == NULL)
99 atabort(INVALIDUSER);
100 if (!allowed(pp->pw_name, ATALLOW, ATDENY))
101 atabort(NOTALLOWED);
104 * Interpret command line flags if they exist.
106 while (argc > 0 && **argv == '-') {
107 (*argv)++;
108 while (**argv) {
109 switch (*(*argv)++) {
111 case 'c' : cflag++;
112 break;
114 case 'n' : nflag++;
115 break;
117 default : usage();
121 --argc, ++argv;
125 * If a certain name (or names) is requested, set a pointer to the
126 * beginning of the list.
128 if (argc > 0) {
129 ++namewanted;
130 uidlist = (uid_t *)malloc(argc * sizeof (uid_t));
131 if (uidlist == NULL)
132 atabortperror("can't allocate list of users");
133 for (i = 0; i < argc; i++) {
134 if (cron_admin(pr.pw_name) ||
135 strcmp(pr.pw_name, argv[i]) == 0) {
136 if ((pp = getpwnam(argv[i])) == NULL) {
137 (void) fprintf(stderr,
138 "atq: No such user %s\n", argv[i]);
139 exit(1);
141 uidlist[argnum] = pp->pw_uid;
142 argnum++;
144 else
145 badarg++;
147 if (badarg)
148 if (argnum)
149 printf("Printing queue information only "
150 "for %s:\n", pr.pw_name);
151 else {
152 printf("atq: Non-priviledged user cannot "
153 "request information regarding other "
154 "users\n");
155 exit(1);
157 } else if (!cron_admin(pr.pw_name)) {
158 /* no argument specified and the invoker is not root */
159 ++namewanted;
160 argnum = 1;
161 if ((uidlist = (uid_t *)malloc(sizeof (uid_t))) == NULL)
162 atabortperror("can't allocate list of users");
163 *uidlist = pr.pw_uid;
167 * Move to the spooling area and scan the directory, placing the
168 * files in the queue structure. The queue comes back sorted by
169 * execution time or creation time.
171 if (chdir(ATDIR) == -1)
172 atabortperror(ATDIR);
173 if ((numentries = scandir(".", &queue, filewanted,
174 (cflag) ? creation : execution)) < 0)
175 atabortperror(ATDIR);
179 * Either print a message stating:
181 * 1) that the spooling area is empty.
182 * 2) the number of jobs in the spooling area.
183 * 3) the number of jobs in the spooling area belonging to
184 * a certain person.
185 * 4) that the person requested doesn't have any files in the
186 * spooling area.
188 * or send the queue off to "printqueue" for printing.
190 * This whole process might seem a bit elaborate, but it's worthwhile
191 * to print some informative messages for the user.
194 if ((numentries == 0) && (!nflag)) {
195 printf("no files in queue.\n");
196 exit(0);
198 if (nflag) {
199 printf("%d\n", (namewanted) ?
200 countfiles(uidlist, argnum) : numentries);
201 exit(0);
203 if ((namewanted) && (countfiles(uidlist, argnum) == 0)) {
204 if (argnum == 1)
205 if (argnum != argc) c = pr.pw_name;
206 else c = *argv;
207 printf("no files for %s.\n", (argnum == 1) ?
208 c : "specified users");
209 exit(0);
211 printqueue(uidlist, argnum);
212 return (0);
216 * Count the number of jobs in the spooling area owned by a certain person(s).
219 countfiles(uid_t *uidlist, int nuids)
221 int i, j; /* for loop indices */
222 int entryfound; /* found file owned by users */
223 int numfiles = 0; /* number of files owned by a */
224 /* certain person(s) */
225 uid_t *ptr; /* scratch pointer */
226 struct stat stbuf; /* buffer for file stats */
230 * For each file in the queue, see if the user(s) own the file. We
231 * have to use "entryfound" (rather than simply incrementing "numfiles")
232 * so that if a person's name appears twice on the command line we
233 * don't double the number of files owned by that user.
235 for (i = 0; i < numentries; i++) {
236 if ((stat(queue[i]->d_name, &stbuf)) < 0) {
237 continue;
239 ptr = uidlist;
240 entryfound = 0;
242 for (j = 0; j < nuids; j++) {
243 if (*ptr == stbuf.st_uid)
244 ++entryfound;
245 ++ptr;
247 if (entryfound)
248 ++numfiles;
250 return (numfiles);
254 * Print the queue. If only jobs belonging to a certain person(s) are requested,
255 * only print jobs that belong to that person(s).
257 static void
258 printqueue(uid_t *uidlist, int nuids)
260 int i, j; /* for loop indices */
261 int rank; /* rank of a job */
262 int entryfound; /* found file owned by users */
263 char *getname();
264 uid_t *ptr; /* scratch pointer */
265 struct stat stbuf; /* buffer for file stats */
266 char curqueue; /* queue of current job */
267 char lastqueue; /* queue of previous job */
270 * Print the header for the queue.
272 printf(" Rank Execution Date Owner Job "
273 "Queue Job Name\n");
276 * Print the queue. If a certain name(s) was requested, print only jobs
277 * belonging to that person(s), otherwise print the entire queue.
278 * Once again, we have to use "entryfound" (rather than simply
279 * comparing each command line argument) so that if a person's name
280 * appears twice we don't print each of their files twice.
283 * "printrank", "printdate", and "printjobname" all take existing
284 * data and display it in a friendly manner.
287 lastqueue = '\0';
288 for (i = 0; i < numentries; i++) {
289 if ((stat(queue[i]->d_name, &stbuf)) < 0) {
290 continue;
292 curqueue = *(strchr(queue[i]->d_name, '.') + 1);
293 if (curqueue != lastqueue) {
294 rank = 1;
295 lastqueue = curqueue;
297 if (namewanted) {
298 ptr = uidlist;
299 entryfound = 0;
301 for (j = 0; j < nuids; j++) {
302 if (*ptr == stbuf.st_uid)
303 ++entryfound;
304 ++ptr;
306 if (!entryfound)
307 continue;
309 printrank(rank++);
310 printdate(queue[i]->d_name);
311 printf("%-10s ", getname(stbuf.st_uid));
312 printf("%-14s ", queue[i]->d_name);
313 printf(" %c", curqueue);
314 printjobname(queue[i]->d_name);
316 ++ptr;
320 * Get the uid of a person using their login name. Return -1 if no
321 * such account name exists.
323 uid_t
324 getid(char *name)
327 struct passwd *pwdinfo; /* password info structure */
330 if ((pwdinfo = getpwnam(name)) == 0)
331 return ((uid_t)-1);
333 return (pwdinfo->pw_uid);
337 * Get the full login name of a person using their user id.
339 char *
340 getname(uid_t uid)
342 struct passwd *pwdinfo; /* password info structure */
345 if ((pwdinfo = getpwuid(uid)) == 0)
346 return ("???");
347 return (pwdinfo->pw_name);
351 * Print the rank of a job. (I've got to admit it, I stole it from "lpq")
353 static void
354 printrank(int n)
356 static char *r[] = {
357 "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
360 if ((n/10) == 1)
361 printf("%3d%-5s", n, "th");
362 else
363 printf("%3d%-5s", n, r[n%10]);
367 * Print the date that a job is to be executed. This takes some manipulation
368 * of the file name.
370 static void
371 printdate(char *filename)
373 time_t jobdate;
374 struct tm *unpackeddate;
375 char date[18]; /* reformatted execution date */
378 * Convert the file name to a date.
380 jobdate = num(&filename);
381 unpackeddate = localtime(&jobdate);
383 /* years since 1900 + base century 1900 */
384 unpackeddate->tm_year += 1900;
386 * Format the execution date of a job.
388 sprintf(date, "%3s %2d, %4d %02d:%02d", mthnames[unpackeddate->tm_mon],
389 unpackeddate->tm_mday, unpackeddate->tm_year,
390 unpackeddate->tm_hour, unpackeddate->tm_min);
393 * Print the date the job will be executed.
395 printf("%-21.18s", date);
399 * Print a job name. If the old "at" has been used to create the spoolfile,
400 * the three line header that the new version of "at" puts in the spoolfile.
401 * Thus, we just print "???".
403 static void
404 printjobname(char *file)
406 char *ptr; /* scratch pointer */
407 char jobname[28]; /* the job name */
408 FILE *filename; /* job file in spooling area */
411 * Open the job file and grab the third line.
413 printf(" ");
415 if ((filename = fopen(file, "r")) == NULL) {
416 printf("%.27s\n", "???");
417 (void) fprintf(stderr, "atq: Can't open job file %s: %s\n",
418 file, errmsg(errno));
419 return;
422 * Skip over the first and second lines.
424 fscanf(filename, "%*[^\n]\n");
427 * Now get the job name.
429 if (fscanf(filename, ": jobname: %27s%*[^\n]\n", jobname) != 1) {
430 printf("%.27s\n", "???");
431 fclose(filename);
432 return;
434 fclose(filename);
437 * Put a pointer at the begining of the line and remove the basename
438 * from the job file.
440 ptr = jobname;
441 if ((ptr = (char *)strrchr(jobname, '/')) != 0)
442 ++ptr;
443 else
444 ptr = jobname;
446 if (strlen(ptr) > 23)
447 printf("%.23s ...\n", ptr);
448 else
449 printf("%.27s\n", ptr);
455 * Sort files by queue, time of creation, and sequence. (used by "scandir")
458 creation(struct dirent **d1, struct dirent **d2)
460 char *p1, *p2;
461 int i;
462 struct stat stbuf1, stbuf2;
463 int seq1, seq2;
465 if ((p1 = strchr((*d1)->d_name, '.')) == NULL)
466 return (0);
467 if ((p2 = strchr((*d2)->d_name, '.')) == NULL)
468 return (0);
469 p1++;
470 p2++;
471 if ((i = *p1++ - *p2++) != 0)
472 return (i);
474 if (stat((*d1)->d_name, &stbuf1) < 0)
475 return (0);
477 if (stat((*d2)->d_name, &stbuf2) < 0)
478 return (0);
480 if (stbuf1.st_ctime < stbuf2.st_ctime)
481 return (-1);
482 else if (stbuf1.st_ctime > stbuf2.st_ctime)
483 return (1);
484 p1++;
485 p2++;
486 seq1 = atoi(p1);
487 seq2 = atoi(p2);
488 return (seq1 - seq2);
492 * Sort files by queue, time of execution, and sequence. (used by "scandir")
495 execution(struct dirent **d1, struct dirent **d2)
497 char *p1, *p2;
498 int i;
499 char *name1, *name2;
500 time_t time1, time2;
501 int seq1, seq2;
503 name1 = (*d1)->d_name;
504 name2 = (*d2)->d_name;
505 if ((p1 = strchr(name1, '.')) == NULL)
506 return (1);
507 if ((p2 = strchr(name2, '.')) == NULL)
508 return (1);
509 p1++;
510 p2++;
511 if ((i = *p1++ - *p2++) != 0)
512 return (i);
514 time1 = num(&name1);
515 time2 = num(&name2);
517 if (time1 < time2)
518 return (-1);
519 else if (time1 > time2)
520 return (1);
521 p1++;
522 p2++;
523 seq1 = atoi(p1);
524 seq2 = atoi(p2);
525 return (seq1 - seq2);
530 * Print usage info and exit.
532 static void
533 usage(void)
535 fprintf(stderr, "usage: atq [-c] [-n] [name ...]\n");
536 exit(1);
539 static void
540 aterror(char *msg)
542 fprintf(stderr, "atq: %s\n", msg);
545 static void
546 atperror(char *msg)
548 fprintf(stderr, "atq: %s: %s\n", msg, errmsg(errno));
551 static void
552 atabort(char *msg)
554 aterror(msg);
555 exit(1);
558 static void
559 atabortperror(char *msg)
561 atperror(msg);
562 exit(1);