|
|
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.1 (Berkeley) 6/6/85";
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:
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; /* 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 (**argv) {
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[30]; /* 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: %s\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[80]; /* 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: return;
298: }
299:
300: if (fscanf(infile,"# owner: %s",owner) != 1) {
301: printf("%-10.9s","???");
302: fclose(infile);
303: return;
304: }
305:
306: fclose(infile);
307: printf("%-10.9s",owner);
308:
309: }
310:
311:
312: /*
313: * Get the uid of a person using his/her login name. Return -1 if no
314: * such account name exists.
315: */
316: getid(name)
317: char *name;
318: {
319:
320: struct passwd *pwdinfo; /* password info structure */
321:
322:
323: if ((pwdinfo = getpwnam(name)) == 0)
324: return(-1);
325:
326: return(pwdinfo->pw_uid);
327: }
328:
329: /*
330: * Print the time the spooling area was updated.
331: */
332: plastrun()
333: {
334: struct timeval now; /* time it is right now */
335: struct timezone zone; /* NOT USED */
336: struct tm *loc; /* detail of time it is right */
337: u_long lasttime; /* last update time in seconds
338: since 1/1/70 */
339: FILE *last; /* file where last update hour
340: is stored */
341:
342:
343: /*
344: * Open the file where the last update time is stored, and grab the
345: * last update hour. The update time is measured in seconds since
346: * 1/1/70.
347: */
348: if ((last = fopen(LASTFILE,"r")) == NULL) {
349: perror(LASTFILE);
350: exit(1);
351: }
352: fscanf(last,"%d",(u_long) &lasttime);
353: fclose(last);
354:
355: /*
356: * Get a broken down representation of the last update time.
357: */
358: loc = localtime(&lasttime);
359:
360: /*
361: * Print the time that the spooling area was last updated.
362: */
363: printf("\n LAST EXECUTION TIME: %s ",mthnames[loc->tm_mon]);
364: printf("%d, 19%d ",loc->tm_mday,loc->tm_year);
365: printf("at %d:%02d\n\n",loc->tm_hour,loc->tm_min);
366: }
367:
368: /*
369: * Print the rank of a job. (I've got to admit it, I stole it from "lpq")
370: */
371: static
372: printrank(n)
373: {
374: static char *r[] = {
375: "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
376: };
377:
378: if ((n/10) == 1)
379: printf("%3d%-5s", n,"th");
380: else
381: printf("%3d%-5s", n, r[n%10]);
382: }
383:
384: /*
385: * Print the date that a job is to be executed. This takes some manipulation
386: * of the file name.
387: */
388: printdate(filename)
389: char *filename;
390: {
391: int yday = 0; /* day of year file will be
392: executed */
393: int min = 0; /* min. file will be executed */
394: int hour = 0; /* hour file will be executed */
395: int day = 0; /* day file will be executed */
396: int month = 0; /* month file will be executed*/
397: int year = 0; /* year file will be executed */
398: int get_mth_day(); /* convert a day of year to a
399: month and day of month */
400: char date[18]; /* reformatted execution date */
401:
402: /*
403: * Pick off the necessary info from the file name and convert the day
404: * of year to a month and day of month.
405: */
406: sscanf(filename,"%2d.%3d.%2d%2d",&year,&yday,&hour,&min);
407: get_mth_day(year,yday,&month,&day);
408:
409: /*
410: * Format the execution date of a job.
411: */
412: sprintf(date,"%3s %2d, 19%2d %02d:%02d",mthnames[month],
413: day, year,hour,min);
414:
415: /*
416: * Print the date the job will be executed.
417: */
418: printf("%-21.18s",date);
419: }
420:
421: /*
422: * Given a day of the year, calculate the month and day of month.
423: */
424: get_mth_day(year,dayofyear,month,day)
425: int year, dayofyear, *month, *day;
426:
427: {
428:
429: int i = 1; /* for loop index */
430: int leap; /* are we dealing with a leap
431: year? */
432: /* Table of the number of days
433: in each month of the year.
434:
435: dofy_tab[1] -- regular year
436: dofy_tab[2] -- leap year
437: */
438:
439: static int dofy_tab[2][13] = {
440: { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
441: { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
442: };
443:
444: /*
445: * Are we dealing with a leap year?
446: */
447: leap = ((year%4 == 0 && year%100 != 0) || year%100 == 0);
448:
449: /*
450: * Calculate the month of the year and day of the month.
451: */
452: while (dayofyear >= dofy_tab[leap][i]) {
453: dayofyear -= dofy_tab[leap][i++];
454: ++(*month);
455: }
456: *day = (dayofyear + 1);
457: }
458:
459: /*
460: * Print a job name. If the old "at" has been used to create the spoolfile,
461: * the three line header that the new version of "at" puts in the spoolfile.
462: * Thus, we just print "???".
463: */
464: printjobname(file)
465: char *file;
466: {
467: char *ptr; /* scratch pointer */
468: char jobname[80]; /* the job name */
469: FILE *filename; /* job file in spooling area */
470:
471: /*
472: * Open the job file and grab the second line.
473: */
474: printf(" ");
475:
476: if ((filename = fopen(file,"r")) == NULL) {
477: printf("%.27s\n", "???");
478: return;
479: }
480: /*
481: * We'll yank the first line into the buffer temporarily.
482: */
483: fgets(jobname,80,filename);
484:
485: /*
486: * Now get the job name.
487: */
488: if (fscanf(filename,"# jobname: %s",jobname) != 1) {
489: printf("%.27s\n", "???");
490: fclose(filename);
491: return;
492: }
493: fclose(filename);
494:
495: /*
496: * Put a pointer at the begining of the line and remove the basename
497: * from the job file.
498: */
499: ptr = jobname;
500: if ((ptr = (char *)rindex(jobname,'/')) != 0)
501: ++ptr;
502: else
503: ptr = jobname;
504:
505: if (strlen(ptr) > 23)
506: printf("%.23s ...\n",ptr);
507: else
508: printf("%.27s\n",ptr);
509: }
510:
511: /*
512: * Do we want to include a file in the queue? (used by "scandir") We are looking
513: * for files with following syntax: yy.ddd.hhhh. so the test is made to see if
514: * the file name has three dots in it. This test will suffice since the only
515: * other files in /usr/spool/at don't have any dots in their name.
516: */
517: filewanted(direntry)
518: struct direct *direntry;
519: {
520: int numdot = 0;
521: char *filename;
522:
523: filename = direntry->d_name;
524: while (*filename)
525: numdot += (*(filename++) == '.');
526: return(numdot == 3);
527: }
528:
529: /*
530: * Sort files by time of creation. (used by "scandir")
531: */
532: creation(d1, d2)
533: struct direct **d1, **d2;
534: {
535: struct stat stbuf1, stbuf2;
536:
537: if (stat((*d1)->d_name,&stbuf1) < 0)
538: return(1);
539:
540: if (stat((*d2)->d_name,&stbuf2) < 0)
541: return(1);
542:
543: return(stbuf1.st_ctime < stbuf2.st_ctime);
544: }
545:
546: /*
547: * Print usage info and exit.
548: */
549: usage()
550: {
551: fprintf(stderr,"usage: atq [-c] [-n] [name ...]\n");
552: exit(1);
553: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.