|
|
1.1 root 1: /*
2: * Copyright (c) 1983 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: */
6:
7: #ifndef lint
8: char copyright[] =
9: "@(#) Copyright (c) 1983 Regents of the University of California.\n\
10: All rights reserved.\n";
11: #endif not lint
12:
13: #ifndef lint
14: static char sccsid[] = "@(#)atq.c 5.2 (Berkeley) 5/28/86";
15: #endif not lint
16:
17: /*
18: *
19: * Synopsis: atq [ -c ] [ -n ] [ name ... ]
20: *
21: *
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 "/usr/spool/at".
25: *
26: *
27: * Author: Steve Wall
28: * Computer Systems Research Group
29: * University of California @ Berkeley
30: *
31: */
32:
33: # include <stdio.h>
34: # include <sys/types.h>
35: # include <sys/file.h>
36: # include <sys/dir.h>
37: # include <sys/stat.h>
38: # include <sys/time.h>
39: # include <pwd.h>
40: # include <ctype.h>
41:
42: # define ATDIR "/usr/spool/at" /* spooling area */
43: # define LASTFILE "/usr/spool/at/lasttimedone" /* update time record
44: file */
45:
46: /*
47: * Months of the year
48: */
49: static char *mthnames[12] = {
50: "Jan","Feb","Mar","Apr","May","Jun","Jul",
51: "Aug","Sep","Oct","Nov","Dec",
52: };
53:
54: char *nullentry = NULL; /* avoid 'namelist' NULL ptr problems */
55: int numentries; /* number of entries in spooling area */
56: int namewanted = 0; /* only print jobs belonging to a
57: certain person */
58: struct direct **queue; /* the queue itself */
59:
60:
61: main(argc,argv)
62: int argc;
63: char **argv;
64: {
65:
66: int cflag = 0; /* print in order of creation time */
67: int nflag = 0; /* just print the number of jobs in
68: queue */
69: int usage(); /* print usage info and exit */
70: int creation(); /* sort jobs by date of creation */
71: int alphasort(); /* sort jobs by date of execution */
72: int filewanted(); /* should a file be included in queue?*/
73: int printqueue(); /* print the queue */
74: int countfiles(); /* count the number of files in queue
75: for a given person */
76: char **namelist = &nullentry; /* array of specific name(s) requested*/
77:
78:
79: --argc, ++argv;
80:
81: /*
82: * Interpret command line flags if they exist.
83: */
84: while (argc > 0 && **argv == '-') {
85: (*argv)++;
86: while (**argv) switch (*(*argv)++) {
87:
88: case 'c' : cflag++;
89: break;
90:
91: case 'n' : nflag++;
92: break;
93:
94: default : usage();
95:
96: }
97: --argc, ++argv;
98: }
99:
100: /*
101: * If a certain name (or names) is requested, set a pointer to the
102: * beginning of the list.
103: */
104: if (argc > 0) {
105: ++namewanted;
106: namelist = argv;
107: }
108:
109: /*
110: * Move to the spooling area and scan the directory, placing the
111: * files in the queue structure. The queue comes back sorted by
112: * execution time or creation time.
113: */
114: if (chdir(ATDIR) == -1) {
115: perror(ATDIR);
116: exit(1);
117: }
118: if ((numentries = scandir(".",&queue,filewanted, (cflag) ? creation :
119: alphasort)) < 0) {
120: perror(ATDIR);
121: exit(1);
122: }
123:
124: /*
125: * Either print a message stating:
126: *
127: * 1) that the spooling area is empty.
128: * 2) the number of jobs in the spooling area.
129: * 3) the number of jobs in the spooling area belonging to
130: * a certain person.
131: * 4) that the person requested doesn't have any files in the
132: * spooling area.
133: *
134: * or send the queue off to "printqueue" for printing.
135: *
136: * This whole process might seem a bit elaborate, but it's worthwhile
137: * to print some informative messages for the user.
138: *
139: */
140: if ((numentries == 0) && (!nflag)) {
141: printf("no files in queue.\n");
142: exit(0);
143: }
144: if (nflag) {
145: printf("%d\n",(namewanted) ? countfiles(namelist) : numentries);
146: exit(0);
147: }
148: if ((namewanted) && (countfiles(namelist) == 0)) {
149: printf("no files for %s.\n", (argc == 1) ?
150: *argv : "specified users");
151: exit(0);
152: }
153: printqueue(namelist);
154: exit(0);
155: }
156:
157: /*
158: * Count the number of jobs in the spooling area owned by a certain person(s).
159: */
160: countfiles(namelist)
161: char **namelist;
162: {
163: int i; /* for loop index */
164: int entryfound; /* found file owned by user(s)*/
165: int numfiles = 0; /* number of files owned by a
166: certain person(s) */
167: char **ptr; /* scratch pointer */
168:
169:
170: /*
171: * For each file in the queue, see if the user(s) own the file. We
172: * have to use "entryfound" (rather than simply incrementing "numfiles")
173: * so that if a person's name appears twice on the command line we
174: * don't double the number of files owned by him/her.
175: */
176: for (i = 0; i < numentries ; i++) {
177: ptr = namelist;
178: entryfound = 0;
179:
180: while (*ptr) {
181: if (isowner(*ptr,queue[i]->d_name))
182: ++entryfound;
183: ++ptr;
184: }
185: if (entryfound)
186: ++numfiles;
187: }
188: return(numfiles);
189: }
190:
191: /*
192: * Print the queue. If only jobs belonging to a certain person(s) are requested,
193: * only print jobs that belong to that person(s).
194: */
195: printqueue(namelist)
196: char **namelist;
197: {
198: int i; /* for loop index */
199: int rank = 1; /* rank of a job */
200: int entryfound; /* found file owned by user(s)*/
201: int printrank(); /* print the rank of a job */
202: int plastrun(); /* print the last time the
203: spooling area was updated */
204: int powner(); /* print the name of the owner
205: of the job */
206: int getid(); /* get uid of a person */
207: char **ptr; /* scratch pointer */
208: struct stat stbuf; /* buffer for file stats */
209:
210:
211: /*
212: * Print the time the spooling area was last modified and the header
213: * for the queue.
214: */
215: plastrun();
216: printf(" Rank Execution Date Owner Job # Job Name\n");
217:
218: /*
219: * Print the queue. If a certain name(s) was requested, print only jobs
220: * belonging to that person(s), otherwise print the entire queue.
221: * Once again, we have to use "entryfound" (rather than simply
222: * comparing each command line argument) so that if a person's name
223: * appears twice we don't print each file owned by him/her twice.
224: *
225: *
226: * "printrank", "printdate", and "printjobname" all take existing
227: * data and display it in a friendly manner.
228: *
229: */
230: for (i = 0; i < numentries; i++) {
231: if ((stat(queue[i]->d_name, &stbuf)) < 0) {
232: continue;
233: }
234: if (namewanted) {
235: ptr = namelist;
236: entryfound = 0;
237:
238: while (*ptr) {
239: if (isowner(*ptr,queue[i]->d_name))
240: ++entryfound;
241: ++ptr;
242: }
243: if (!entryfound)
244: continue;
245: }
246: printrank(rank++);
247: printdate(queue[i]->d_name);
248: powner(queue[i]->d_name);
249: printf("%5d",stbuf.st_ino);
250: printjobname(queue[i]->d_name);
251: }
252: ++ptr;
253: }
254:
255: /*
256: * See if "name" owns "job".
257: */
258: isowner(name,job)
259: char *name;
260: char *job;
261: {
262: char buf[128]; /* buffer for 1st line of spoolfile
263: header */
264: FILE *infile; /* I/O stream to spoolfile */
265:
266: if ((infile = fopen(job,"r")) == NULL) {
267: fprintf(stderr,"Couldn't open spoolfile ");
268: perror(job);
269: return(0);
270: }
271:
272: if (fscanf(infile,"# owner: %127s%*[^\n]\n",buf) != 1) {
273: fclose(infile);
274: return(0);
275: }
276:
277: fclose(infile);
278: return((strcmp(name,buf) == 0) ? 1 : 0);
279: }
280:
281: /*
282: * Print the owner of the job. This is stored on the first line of the
283: * spoolfile. If we run into trouble getting the name, we'll just print "???".
284: */
285: powner(file)
286: char *file;
287: {
288: char owner[10]; /* the owner */
289: FILE *infile; /* I/O stream to spoolfile */
290:
291: /*
292: * Open the job file and grab the first line.
293: */
294:
295: if ((infile = fopen(file,"r")) == NULL) {
296: printf("%-10.9s","???");
297: perror(file);
298: return;
299: }
300:
301: if (fscanf(infile,"# owner: %9s%*[^\n]\n",owner) != 1) {
302: printf("%-10.9s","???");
303: fclose(infile);
304: return;
305: }
306:
307: fclose(infile);
308: printf("%-10.9s",owner);
309:
310: }
311:
312:
313: /*
314: * Get the uid of a person using his/her login name. Return -1 if no
315: * such account name exists.
316: */
317: getid(name)
318: char *name;
319: {
320:
321: struct passwd *pwdinfo; /* password info structure */
322:
323:
324: if ((pwdinfo = getpwnam(name)) == 0)
325: return(-1);
326:
327: return(pwdinfo->pw_uid);
328: }
329:
330: /*
331: * Print the time the spooling area was updated.
332: */
333: plastrun()
334: {
335: struct timeval now; /* time it is right now */
336: struct timezone zone; /* NOT USED */
337: struct tm *loc; /* detail of time it is right */
338: u_long lasttime; /* last update time in seconds
339: since 1/1/70 */
340: FILE *last; /* file where last update hour
341: is stored */
342:
343:
344: /*
345: * Open the file where the last update time is stored, and grab the
346: * last update hour. The update time is measured in seconds since
347: * 1/1/70.
348: */
349: if ((last = fopen(LASTFILE,"r")) == NULL) {
350: perror(LASTFILE);
351: exit(1);
352: }
353: fscanf(last,"%d",(u_long) &lasttime);
354: fclose(last);
355:
356: /*
357: * Get a broken down representation of the last update time.
358: */
359: loc = localtime(&lasttime);
360:
361: /*
362: * Print the time that the spooling area was last updated.
363: */
364: printf("\n LAST EXECUTION TIME: %s ",mthnames[loc->tm_mon]);
365: printf("%d, 19%d ",loc->tm_mday,loc->tm_year);
366: printf("at %d:%02d\n\n",loc->tm_hour,loc->tm_min);
367: }
368:
369: /*
370: * Print the rank of a job. (I've got to admit it, I stole it from "lpq")
371: */
372: static
373: printrank(n)
374: {
375: static char *r[] = {
376: "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
377: };
378:
379: if ((n/10) == 1)
380: printf("%3d%-5s", n,"th");
381: else
382: printf("%3d%-5s", n, r[n%10]);
383: }
384:
385: /*
386: * Print the date that a job is to be executed. This takes some manipulation
387: * of the file name.
388: */
389: printdate(filename)
390: char *filename;
391: {
392: int yday = 0; /* day of year file will be
393: executed */
394: int min = 0; /* min. file will be executed */
395: int hour = 0; /* hour file will be executed */
396: int day = 0; /* day file will be executed */
397: int month = 0; /* month file will be executed*/
398: int year = 0; /* year file will be executed */
399: int get_mth_day(); /* convert a day of year to a
400: month and day of month */
401: char date[18]; /* reformatted execution date */
402:
403: /*
404: * Pick off the necessary info from the file name and convert the day
405: * of year to a month and day of month.
406: */
407: sscanf(filename,"%2d.%3d.%2d%2d",&year,&yday,&hour,&min);
408: get_mth_day(year,yday,&month,&day);
409:
410: /*
411: * Format the execution date of a job.
412: */
413: sprintf(date,"%3s %2d, 19%2d %02d:%02d",mthnames[month],
414: day, year,hour,min);
415:
416: /*
417: * Print the date the job will be executed.
418: */
419: printf("%-21.18s",date);
420: }
421:
422: /*
423: * Given a day of the year, calculate the month and day of month.
424: */
425: get_mth_day(year,dayofyear,month,day)
426: int year, dayofyear, *month, *day;
427:
428: {
429:
430: int i = 1; /* for loop index */
431: int leap; /* are we dealing with a leap
432: year? */
433: /* Table of the number of days
434: in each month of the year.
435:
436: dofy_tab[1] -- regular year
437: dofy_tab[2] -- leap year
438: */
439:
440: static int dofy_tab[2][13] = {
441: { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
442: { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
443: };
444:
445: /*
446: * Are we dealing with a leap year?
447: */
448: leap = ((year%4 == 0 && year%100 != 0) || year%100 == 0);
449:
450: /*
451: * Calculate the month of the year and day of the month.
452: */
453: while (dayofyear >= dofy_tab[leap][i]) {
454: dayofyear -= dofy_tab[leap][i++];
455: ++(*month);
456: }
457: *day = (dayofyear + 1);
458: }
459:
460: /*
461: * Print a job name. If the old "at" has been used to create the spoolfile,
462: * the three line header that the new version of "at" puts in the spoolfile.
463: * Thus, we just print "???".
464: */
465: printjobname(file)
466: char *file;
467: {
468: char *ptr; /* scratch pointer */
469: char jobname[28]; /* the job name */
470: FILE *filename; /* job file in spooling area */
471:
472: /*
473: * Open the job file and grab the second line.
474: */
475: printf(" ");
476:
477: if ((filename = fopen(file,"r")) == NULL) {
478: printf("%.27s\n", "???");
479: perror(file);
480: return;
481: }
482: /*
483: * Skip over the first line.
484: */
485: fscanf(filename,"%*[^\n]\n");
486:
487: /*
488: * Now get the job name.
489: */
490: if (fscanf(filename,"# jobname: %27s%*[^\n]\n",jobname) != 1) {
491: printf("%.27s\n", "???");
492: fclose(filename);
493: return;
494: }
495: fclose(filename);
496:
497: /*
498: * Put a pointer at the begining of the line and remove the basename
499: * from the job file.
500: */
501: ptr = jobname;
502: if ((ptr = (char *)rindex(jobname,'/')) != 0)
503: ++ptr;
504: else
505: ptr = jobname;
506:
507: if (strlen(ptr) > 23)
508: printf("%.23s ...\n",ptr);
509: else
510: printf("%.27s\n",ptr);
511: }
512:
513: /*
514: * Do we want to include a file in the queue? (used by "scandir") We are looking
515: * for files with following syntax: yy.ddd.hhhh. so the test is made to see if
516: * the file name has three dots in it. This test will suffice since the only
517: * other files in /usr/spool/at don't have any dots in their name.
518: */
519: filewanted(direntry)
520: struct direct *direntry;
521: {
522: int numdot = 0;
523: char *filename;
524:
525: filename = direntry->d_name;
526: while (*filename)
527: numdot += (*(filename++) == '.');
528: return(numdot == 3);
529: }
530:
531: /*
532: * Sort files by time of creation. (used by "scandir")
533: */
534: creation(d1, d2)
535: struct direct **d1, **d2;
536: {
537: struct stat stbuf1, stbuf2;
538:
539: if (stat((*d1)->d_name,&stbuf1) < 0)
540: return(1);
541:
542: if (stat((*d2)->d_name,&stbuf2) < 0)
543: return(1);
544:
545: return(stbuf1.st_ctime < stbuf2.st_ctime);
546: }
547:
548: /*
549: * Print usage info and exit.
550: */
551: usage()
552: {
553: fprintf(stderr,"usage: atq [-c] [-n] [name ...]\n");
554: exit(1);
555: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.