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