148233Sbostic /*-
2*61911Sbostic * Copyright (c) 1983, 1993
3*61911Sbostic * The Regents of the University of California. All rights reserved.
448233Sbostic *
548233Sbostic * %sccs.include.proprietary.c%
622419Sdist */
722419Sdist
816818Swall #ifndef lint
9*61911Sbostic static char copyright[] =
10*61911Sbostic "@(#) Copyright (c) 1983, 1993\n\
11*61911Sbostic The Regents of the University of California. All rights reserved.\n";
1248233Sbostic #endif /* not lint */
1316818Swall
1422419Sdist #ifndef lint
15*61911Sbostic static char sccsid[] = "@(#)atq.c 8.1 (Berkeley) 06/06/93";
1648233Sbostic #endif /* not lint */
1722419Sdist
1816818Swall /*
1916818Swall *
2016828Smckusick * Synopsis: atq [ -c ] [ -n ] [ name ... ]
2116818Swall *
2216818Swall *
2316828Smckusick * Print the queue of files waiting to be executed. These files
2416828Smckusick * were created by using the "at" command and are located in the
2516828Smckusick * directory "/usr/spool/at".
2616818Swall *
2716818Swall *
2816828Smckusick * Author: Steve Wall
2916828Smckusick * Computer Systems Research Group
3016828Smckusick * University of California @ Berkeley
3116818Swall *
3216818Swall */
3316818Swall
3416818Swall # include <stdio.h>
3516818Swall # include <sys/types.h>
3616818Swall # include <sys/file.h>
3716818Swall # include <sys/dir.h>
3816818Swall # include <sys/stat.h>
3916818Swall # include <sys/time.h>
4016818Swall # include <pwd.h>
4116818Swall # include <ctype.h>
4237962Sbostic # include "pathnames.h"
4316818Swall
4416818Swall /*
4516818Swall * Months of the year
4616818Swall */
4716818Swall static char *mthnames[12] = {
4816828Smckusick "Jan","Feb","Mar","Apr","May","Jun","Jul",
4916828Smckusick "Aug","Sep","Oct","Nov","Dec",
5016818Swall };
5116818Swall
5228872Smckusick char *nullentry = NULL; /* avoid 'namelist' NULL ptr problems */
5316828Smckusick int numentries; /* number of entries in spooling area */
5416828Smckusick int namewanted = 0; /* only print jobs belonging to a
5516828Smckusick certain person */
5616828Smckusick struct direct **queue; /* the queue itself */
5716818Swall
5816818Swall
main(argc,argv)5916818Swall main(argc,argv)
6016818Swall int argc;
6116818Swall char **argv;
6216818Swall {
6316818Swall
6416828Smckusick int cflag = 0; /* print in order of creation time */
6516828Smckusick int nflag = 0; /* just print the number of jobs in
6616828Smckusick queue */
6716828Smckusick int usage(); /* print usage info and exit */
6816828Smckusick int creation(); /* sort jobs by date of creation */
6916828Smckusick int alphasort(); /* sort jobs by date of execution */
7016828Smckusick int filewanted(); /* should a file be included in queue?*/
7116828Smckusick int printqueue(); /* print the queue */
7216828Smckusick int countfiles(); /* count the number of files in queue
7316828Smckusick for a given person */
7428872Smckusick char **namelist = &nullentry; /* array of specific name(s) requested*/
7516818Swall
7616818Swall
7716828Smckusick --argc, ++argv;
7816818Swall
7916828Smckusick /*
8016828Smckusick * Interpret command line flags if they exist.
8116828Smckusick */
8216828Smckusick while (argc > 0 && **argv == '-') {
8316828Smckusick (*argv)++;
8416828Smckusick while (**argv) switch (*(*argv)++) {
8516818Swall
8616828Smckusick case 'c' : cflag++;
8716828Smckusick break;
8816818Swall
8916828Smckusick case 'n' : nflag++;
9016828Smckusick break;
9116818Swall
9216828Smckusick default : usage();
9316818Swall
9416828Smckusick }
9516828Smckusick --argc, ++argv;
9616828Smckusick }
9716818Swall
9816828Smckusick /*
9916828Smckusick * If a certain name (or names) is requested, set a pointer to the
10016828Smckusick * beginning of the list.
10116828Smckusick */
10228872Smckusick if (argc > 0) {
10316828Smckusick ++namewanted;
10416828Smckusick namelist = argv;
10516828Smckusick }
10616818Swall
10716828Smckusick /*
10816828Smckusick * Move to the spooling area and scan the directory, placing the
10916828Smckusick * files in the queue structure. The queue comes back sorted by
11016828Smckusick * execution time or creation time.
11116828Smckusick */
11237962Sbostic if (chdir(_PATH_ATDIR) == -1) {
11337962Sbostic perror(_PATH_ATDIR);
11416828Smckusick exit(1);
11516828Smckusick }
11616828Smckusick if ((numentries = scandir(".",&queue,filewanted, (cflag) ? creation :
11716828Smckusick alphasort)) < 0) {
11837962Sbostic perror(_PATH_ATDIR);
11916828Smckusick exit(1);
12016828Smckusick }
12116818Swall
12216828Smckusick /*
12316828Smckusick * Either print a message stating:
12416828Smckusick *
12516828Smckusick * 1) that the spooling area is empty.
12616828Smckusick * 2) the number of jobs in the spooling area.
12716828Smckusick * 3) the number of jobs in the spooling area belonging to
12816828Smckusick * a certain person.
12916828Smckusick * 4) that the person requested doesn't have any files in the
13016828Smckusick * spooling area.
13116828Smckusick *
13216828Smckusick * or send the queue off to "printqueue" for printing.
13316828Smckusick *
13416828Smckusick * This whole process might seem a bit elaborate, but it's worthwhile
13516828Smckusick * to print some informative messages for the user.
13616828Smckusick *
13716828Smckusick */
13816828Smckusick if ((numentries == 0) && (!nflag)) {
13916828Smckusick printf("no files in queue.\n");
14016828Smckusick exit(0);
14116828Smckusick }
14216828Smckusick if (nflag) {
14316828Smckusick printf("%d\n",(namewanted) ? countfiles(namelist) : numentries);
14416828Smckusick exit(0);
14516828Smckusick }
14616828Smckusick if ((namewanted) && (countfiles(namelist) == 0)) {
14716828Smckusick printf("no files for %s.\n", (argc == 1) ?
14816828Smckusick *argv : "specified users");
14916828Smckusick exit(0);
15016828Smckusick }
15116828Smckusick printqueue(namelist);
15216828Smckusick exit(0);
15316818Swall }
15416818Swall
15516818Swall /*
15616818Swall * Count the number of jobs in the spooling area owned by a certain person(s).
15716818Swall */
countfiles(namelist)15816818Swall countfiles(namelist)
15916818Swall char **namelist;
16016818Swall {
16116828Smckusick int i; /* for loop index */
16216828Smckusick int entryfound; /* found file owned by user(s)*/
16316828Smckusick int numfiles = 0; /* number of files owned by a
16416828Smckusick certain person(s) */
16516828Smckusick char **ptr; /* scratch pointer */
16616818Swall
16716818Swall
16816828Smckusick /*
16916828Smckusick * For each file in the queue, see if the user(s) own the file. We
17016828Smckusick * have to use "entryfound" (rather than simply incrementing "numfiles")
17116828Smckusick * so that if a person's name appears twice on the command line we
17216828Smckusick * don't double the number of files owned by him/her.
17316828Smckusick */
17416828Smckusick for (i = 0; i < numentries ; i++) {
17516828Smckusick ptr = namelist;
17616828Smckusick entryfound = 0;
17716818Swall
17816828Smckusick while (*ptr) {
17916865Swall if (isowner(*ptr,queue[i]->d_name))
18016828Smckusick ++entryfound;
18116828Smckusick ++ptr;
18216828Smckusick }
18316828Smckusick if (entryfound)
18416828Smckusick ++numfiles;
18516828Smckusick }
18616828Smckusick return(numfiles);
18716818Swall }
18816818Swall
18916818Swall /*
19016818Swall * Print the queue. If only jobs belonging to a certain person(s) are requested,
19116818Swall * only print jobs that belong to that person(s).
19216818Swall */
printqueue(namelist)19316818Swall printqueue(namelist)
19416818Swall char **namelist;
19516818Swall {
19616828Smckusick int i; /* for loop index */
19716828Smckusick int rank = 1; /* rank of a job */
19816828Smckusick int entryfound; /* found file owned by user(s)*/
19946817Sbostic static int printrank(); /* print the rank of a job */
20016828Smckusick int plastrun(); /* print the last time the
20116828Smckusick spooling area was updated */
20216865Swall int powner(); /* print the name of the owner
20316865Swall of the job */
20416828Smckusick char **ptr; /* scratch pointer */
20516828Smckusick struct stat stbuf; /* buffer for file stats */
20616818Swall
20716818Swall
20816828Smckusick /*
20916828Smckusick * Print the time the spooling area was last modified and the header
21016828Smckusick * for the queue.
21116828Smckusick */
21216828Smckusick plastrun();
21316828Smckusick printf(" Rank Execution Date Owner Job # Job Name\n");
21416818Swall
21516828Smckusick /*
21616828Smckusick * Print the queue. If a certain name(s) was requested, print only jobs
21716828Smckusick * belonging to that person(s), otherwise print the entire queue.
21816828Smckusick * Once again, we have to use "entryfound" (rather than simply
21916828Smckusick * comparing each command line argument) so that if a person's name
22016828Smckusick * appears twice we don't print each file owned by him/her twice.
22116828Smckusick *
22216828Smckusick *
22316828Smckusick * "printrank", "printdate", and "printjobname" all take existing
22416828Smckusick * data and display it in a friendly manner.
22516828Smckusick *
22616828Smckusick */
22716828Smckusick for (i = 0; i < numentries; i++) {
22816828Smckusick if ((stat(queue[i]->d_name, &stbuf)) < 0) {
22916828Smckusick continue;
23016828Smckusick }
23116828Smckusick if (namewanted) {
23216828Smckusick ptr = namelist;
23316828Smckusick entryfound = 0;
23416818Swall
23516828Smckusick while (*ptr) {
23616865Swall if (isowner(*ptr,queue[i]->d_name))
23716828Smckusick ++entryfound;
23816828Smckusick ++ptr;
23916828Smckusick }
24016828Smckusick if (!entryfound)
24116828Smckusick continue;
24216828Smckusick }
24316828Smckusick printrank(rank++);
24416828Smckusick printdate(queue[i]->d_name);
24516865Swall powner(queue[i]->d_name);
24616828Smckusick printf("%5d",stbuf.st_ino);
24716828Smckusick printjobname(queue[i]->d_name);
24816828Smckusick }
24916828Smckusick ++ptr;
25016818Swall }
25116818Swall
25216818Swall /*
25316865Swall * See if "name" owns "job".
25416818Swall */
isowner(name,job)25516865Swall isowner(name,job)
25616865Swall char *name;
25716865Swall char *job;
25816818Swall {
25928872Smckusick char buf[128]; /* buffer for 1st line of spoolfile
26016865Swall header */
26116865Swall FILE *infile; /* I/O stream to spoolfile */
26216818Swall
26316865Swall if ((infile = fopen(job,"r")) == NULL) {
26428872Smckusick fprintf(stderr,"Couldn't open spoolfile ");
26516865Swall perror(job);
26616865Swall return(0);
26716828Smckusick }
26816865Swall
26928872Smckusick if (fscanf(infile,"# owner: %127s%*[^\n]\n",buf) != 1) {
27016865Swall fclose(infile);
27116865Swall return(0);
27216865Swall }
27316865Swall
27416865Swall fclose(infile);
27516865Swall return((strcmp(name,buf) == 0) ? 1 : 0);
27616818Swall }
27716865Swall
27816865Swall /*
27916865Swall * Print the owner of the job. This is stored on the first line of the
28016865Swall * spoolfile. If we run into trouble getting the name, we'll just print "???".
28116865Swall */
powner(file)28216865Swall powner(file)
28316865Swall char *file;
28416865Swall {
28528872Smckusick char owner[10]; /* the owner */
28616865Swall FILE *infile; /* I/O stream to spoolfile */
28716865Swall
28816865Swall /*
28916865Swall * Open the job file and grab the first line.
29016865Swall */
29116865Swall
29216865Swall if ((infile = fopen(file,"r")) == NULL) {
29316865Swall printf("%-10.9s","???");
29428872Smckusick perror(file);
29516865Swall return;
29616865Swall }
29716865Swall
29828872Smckusick if (fscanf(infile,"# owner: %9s%*[^\n]\n",owner) != 1) {
29916865Swall printf("%-10.9s","???");
30016865Swall fclose(infile);
30116865Swall return;
30216865Swall }
30316865Swall
30416865Swall fclose(infile);
30516865Swall printf("%-10.9s",owner);
30616865Swall
30716865Swall }
30816828Smckusick
30916818Swall /*
31016818Swall * Print the time the spooling area was updated.
31116818Swall */
plastrun()31216818Swall plastrun()
31316818Swall {
31416828Smckusick struct timeval now; /* time it is right now */
31516828Smckusick struct timezone zone; /* NOT USED */
31616828Smckusick struct tm *loc; /* detail of time it is right */
31746817Sbostic time_t lasttime; /* last update time in seconds
31816828Smckusick since 1/1/70 */
31916828Smckusick FILE *last; /* file where last update hour
32016828Smckusick is stored */
32116818Swall
32216818Swall
32316828Smckusick /*
32416828Smckusick * Open the file where the last update time is stored, and grab the
32516828Smckusick * last update hour. The update time is measured in seconds since
32616828Smckusick * 1/1/70.
32716828Smckusick */
32837962Sbostic if ((last = fopen(_PATH_LASTFILE,"r")) == NULL) {
32937962Sbostic perror(_PATH_LASTFILE);
33016828Smckusick exit(1);
33116828Smckusick }
33230804Sbostic fscanf(last,"%lu",&lasttime);
33316828Smckusick fclose(last);
33416818Swall
33516828Smckusick /*
33616828Smckusick * Get a broken down representation of the last update time.
33716828Smckusick */
33816828Smckusick loc = localtime(&lasttime);
33916818Swall
34016828Smckusick /*
34116828Smckusick * Print the time that the spooling area was last updated.
34216828Smckusick */
34316828Smckusick printf("\n LAST EXECUTION TIME: %s ",mthnames[loc->tm_mon]);
34416828Smckusick printf("%d, 19%d ",loc->tm_mday,loc->tm_year);
34516828Smckusick printf("at %d:%02d\n\n",loc->tm_hour,loc->tm_min);
34616818Swall }
34716818Swall
34816818Swall /*
34916818Swall * Print the rank of a job. (I've got to admit it, I stole it from "lpq")
35016818Swall */
35116818Swall static
printrank(n)35216818Swall printrank(n)
35316818Swall {
35416828Smckusick static char *r[] = {
35516828Smckusick "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
35616828Smckusick };
35716818Swall
35816828Smckusick if ((n/10) == 1)
35916828Smckusick printf("%3d%-5s", n,"th");
36016828Smckusick else
36116828Smckusick printf("%3d%-5s", n, r[n%10]);
36216818Swall }
36316818Swall
36416818Swall /*
36516818Swall * Print the date that a job is to be executed. This takes some manipulation
36616818Swall * of the file name.
36716818Swall */
printdate(filename)36816818Swall printdate(filename)
36916818Swall char *filename;
37016818Swall {
37116828Smckusick int yday = 0; /* day of year file will be
37216828Smckusick executed */
37316828Smckusick int min = 0; /* min. file will be executed */
37416828Smckusick int hour = 0; /* hour file will be executed */
37516828Smckusick int day = 0; /* day file will be executed */
37616828Smckusick int month = 0; /* month file will be executed*/
37716828Smckusick int year = 0; /* year file will be executed */
37816828Smckusick int get_mth_day(); /* convert a day of year to a
37916828Smckusick month and day of month */
38036357Sbostic char date[19]; /* reformatted execution date */
38116818Swall
38216828Smckusick /*
38316828Smckusick * Pick off the necessary info from the file name and convert the day
38416828Smckusick * of year to a month and day of month.
38516828Smckusick */
38616828Smckusick sscanf(filename,"%2d.%3d.%2d%2d",&year,&yday,&hour,&min);
38716828Smckusick get_mth_day(year,yday,&month,&day);
38816818Swall
38916828Smckusick /*
39016828Smckusick * Format the execution date of a job.
39116828Smckusick */
39216828Smckusick sprintf(date,"%3s %2d, 19%2d %02d:%02d",mthnames[month],
39316828Smckusick day, year,hour,min);
39416818Swall
39516828Smckusick /*
39616828Smckusick * Print the date the job will be executed.
39716828Smckusick */
39816828Smckusick printf("%-21.18s",date);
39916818Swall }
40016818Swall
40116818Swall /*
40216818Swall * Given a day of the year, calculate the month and day of month.
40316818Swall */
get_mth_day(year,dayofyear,month,day)40416818Swall get_mth_day(year,dayofyear,month,day)
40516818Swall int year, dayofyear, *month, *day;
40616818Swall
40716818Swall {
40816818Swall
40916828Smckusick int i = 1; /* for loop index */
41016828Smckusick int leap; /* are we dealing with a leap
41116828Smckusick year? */
41216828Smckusick /* Table of the number of days
41316828Smckusick in each month of the year.
41416818Swall
41516828Smckusick dofy_tab[1] -- regular year
41616828Smckusick dofy_tab[2] -- leap year
41716828Smckusick */
41816818Swall
41916828Smckusick static int dofy_tab[2][13] = {
42016828Smckusick { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
42116828Smckusick { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
42216828Smckusick };
42316818Swall
42416828Smckusick /*
42516828Smckusick * Are we dealing with a leap year?
42616828Smckusick */
42716828Smckusick leap = ((year%4 == 0 && year%100 != 0) || year%100 == 0);
42816818Swall
42916828Smckusick /*
43016828Smckusick * Calculate the month of the year and day of the month.
43116828Smckusick */
43216828Smckusick while (dayofyear >= dofy_tab[leap][i]) {
43316828Smckusick dayofyear -= dofy_tab[leap][i++];
43416828Smckusick ++(*month);
43516828Smckusick }
43616828Smckusick *day = (dayofyear + 1);
43716818Swall }
43816828Smckusick
43916818Swall /*
44016818Swall * Print a job name. If the old "at" has been used to create the spoolfile,
44116818Swall * the three line header that the new version of "at" puts in the spoolfile.
44216818Swall * Thus, we just print "???".
44316818Swall */
printjobname(file)44416818Swall printjobname(file)
44516818Swall char *file;
44616818Swall {
44716865Swall char *ptr; /* scratch pointer */
44828872Smckusick char jobname[28]; /* the job name */
44916828Smckusick FILE *filename; /* job file in spooling area */
45016818Swall
45116828Smckusick /*
45216865Swall * Open the job file and grab the second line.
45316828Smckusick */
45416828Smckusick printf(" ");
45516818Swall
45616828Smckusick if ((filename = fopen(file,"r")) == NULL) {
45716828Smckusick printf("%.27s\n", "???");
45828872Smckusick perror(file);
45916828Smckusick return;
46016828Smckusick }
46116865Swall /*
46228872Smckusick * Skip over the first line.
46316865Swall */
46428872Smckusick fscanf(filename,"%*[^\n]\n");
46516865Swall
46616865Swall /*
46716865Swall * Now get the job name.
46816865Swall */
46928872Smckusick if (fscanf(filename,"# jobname: %27s%*[^\n]\n",jobname) != 1) {
47016828Smckusick printf("%.27s\n", "???");
47116828Smckusick fclose(filename);
47216828Smckusick return;
47316828Smckusick }
47416828Smckusick fclose(filename);
47516818Swall
47616828Smckusick /*
47716828Smckusick * Put a pointer at the begining of the line and remove the basename
47816828Smckusick * from the job file.
47916828Smckusick */
48016865Swall ptr = jobname;
48116865Swall if ((ptr = (char *)rindex(jobname,'/')) != 0)
48216865Swall ++ptr;
48316828Smckusick else
48416865Swall ptr = jobname;
48516818Swall
48616865Swall if (strlen(ptr) > 23)
48716865Swall printf("%.23s ...\n",ptr);
48816865Swall else
48916865Swall printf("%.27s\n",ptr);
49016818Swall }
49116818Swall
49216818Swall /*
49316818Swall * Do we want to include a file in the queue? (used by "scandir") We are looking
49416818Swall * for files with following syntax: yy.ddd.hhhh. so the test is made to see if
49516818Swall * the file name has three dots in it. This test will suffice since the only
49616818Swall * other files in /usr/spool/at don't have any dots in their name.
49716818Swall */
49816818Swall filewanted(direntry)
49916818Swall struct direct *direntry;
50016818Swall {
50116828Smckusick int numdot = 0;
50216828Smckusick char *filename;
50316818Swall
50416828Smckusick filename = direntry->d_name;
50516828Smckusick while (*filename)
50616828Smckusick numdot += (*(filename++) == '.');
50716828Smckusick return(numdot == 3);
50816818Swall }
50916818Swall
51016818Swall /*
51116818Swall * Sort files by time of creation. (used by "scandir")
51216818Swall */
51316818Swall creation(d1, d2)
51416818Swall struct direct **d1, **d2;
51516818Swall {
51616828Smckusick struct stat stbuf1, stbuf2;
51716818Swall
51816828Smckusick if (stat((*d1)->d_name,&stbuf1) < 0)
51916828Smckusick return(1);
52016818Swall
52116828Smckusick if (stat((*d2)->d_name,&stbuf2) < 0)
52216828Smckusick return(1);
52316818Swall
52416828Smckusick return(stbuf1.st_ctime < stbuf2.st_ctime);
52516818Swall }
52616828Smckusick
52716818Swall /*
52816818Swall * Print usage info and exit.
52916818Swall */
usage()53016818Swall usage()
53116818Swall {
53216828Smckusick fprintf(stderr,"usage: atq [-c] [-n] [name ...]\n");
53316828Smckusick exit(1);
53416818Swall }
535