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: }

Defined functions

countfiles defined in line 160; used 3 times
creation defined in line 534; used 2 times
filewanted defined in line 519; used 2 times
get_mth_day defined in line 425; used 2 times
getid defined in line 317; used 1 times
isowner defined in line 258; used 2 times
main defined in line 61; never used
plastrun defined in line 333; used 2 times
powner defined in line 285; used 2 times
printdate defined in line 389; used 1 times
printjobname defined in line 465; used 1 times
printqueue defined in line 195; used 2 times
printrank defined in line 372; used 2 times
usage defined in line 551; used 2 times

Defined variables

copyright defined in line 8; never used
mthnames defined in line 49; used 2 times
namewanted defined in line 56; used 4 times
nullentry defined in line 54; used 1 times
  • in line 76
numentries defined in line 55; used 5 times
queue defined in line 58; used 7 times
sccsid defined in line 14; never used

Defined macros

ATDIR defined in line 42; used 3 times
LASTFILE defined in line 43; used 2 times
Last modified: 1986-05-29
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1733
Valid CSS Valid XHTML 1.0 Strict