1*032624d5Sbasabi /* 2*032624d5Sbasabi * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3*032624d5Sbasabi * Use is subject to license terms. 4*032624d5Sbasabi */ 5*032624d5Sbasabi 67c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 77c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 87c478bd9Sstevel@tonic-gate 97c478bd9Sstevel@tonic-gate 107c478bd9Sstevel@tonic-gate /* 117c478bd9Sstevel@tonic-gate * Copyright (c) 1983 Regents of the University of California. 127c478bd9Sstevel@tonic-gate * All rights reserved. The Berkeley software License Agreement 137c478bd9Sstevel@tonic-gate * specifies the terms and conditions for redistribution. 147c478bd9Sstevel@tonic-gate */ 157c478bd9Sstevel@tonic-gate 16*032624d5Sbasabi #pragma ident "%Z%%M% %I% %E% SMI" 177c478bd9Sstevel@tonic-gate 187c478bd9Sstevel@tonic-gate /* 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * Synopsis: atq [ -c ] [ -n ] [ name ... ] 217c478bd9Sstevel@tonic-gate * 227c478bd9Sstevel@tonic-gate * 237c478bd9Sstevel@tonic-gate * Print the queue of files waiting to be executed. These files 247c478bd9Sstevel@tonic-gate * were created by using the "at" command and are located in the 257c478bd9Sstevel@tonic-gate * directory defined by ATDIR. 267c478bd9Sstevel@tonic-gate */ 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #include <stdio.h> 297c478bd9Sstevel@tonic-gate #include <sys/types.h> 307c478bd9Sstevel@tonic-gate #include <sys/file.h> 317c478bd9Sstevel@tonic-gate #include <dirent.h> 327c478bd9Sstevel@tonic-gate #include <sys/stat.h> 337c478bd9Sstevel@tonic-gate #include <time.h> 347c478bd9Sstevel@tonic-gate #include <pwd.h> 357c478bd9Sstevel@tonic-gate #include <ctype.h> 367c478bd9Sstevel@tonic-gate #include <unistd.h> 377c478bd9Sstevel@tonic-gate #include <locale.h> 387c478bd9Sstevel@tonic-gate #include <errno.h> 397c478bd9Sstevel@tonic-gate #include "cron.h" 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate extern char *errmsg(); 427c478bd9Sstevel@tonic-gate extern char *strchr(); 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate /* 457c478bd9Sstevel@tonic-gate * Months of the year 467c478bd9Sstevel@tonic-gate */ 477c478bd9Sstevel@tonic-gate static char *mthnames[12] = { 487c478bd9Sstevel@tonic-gate "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", 497c478bd9Sstevel@tonic-gate "Aug", "Sep", "Oct", "Nov", "Dec", 507c478bd9Sstevel@tonic-gate }; 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate int numentries; /* number of entries in spooling area */ 537c478bd9Sstevel@tonic-gate int namewanted = 0; /* print jobs for a certain person */ 547c478bd9Sstevel@tonic-gate struct dirent **queue; /* the queue itself */ 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate #define INVALIDUSER "you are not a valid user (no entry in /etc/passwd)" 577c478bd9Sstevel@tonic-gate #define NOTALLOWED "you are not authorized to use at. Sorry." 587c478bd9Sstevel@tonic-gate 59*032624d5Sbasabi static void atabortperror(char *msg); 60*032624d5Sbasabi static void atabort(char *msg); 61*032624d5Sbasabi static void aterror(char *msg); 62*032624d5Sbasabi static void atperror(char *msg); 63*032624d5Sbasabi static void usage(void); 64*032624d5Sbasabi static void printjobname(char *file); 65*032624d5Sbasabi static void printdate(char *filename); 66*032624d5Sbasabi static void printrank(int n); 67*032624d5Sbasabi static void printqueue(uid_t *uidlist, int nuids); 687c478bd9Sstevel@tonic-gate 69*032624d5Sbasabi int 70*032624d5Sbasabi main(int argc, char **argv) 717c478bd9Sstevel@tonic-gate { 727c478bd9Sstevel@tonic-gate 73*032624d5Sbasabi struct passwd *pp; /* password file entry pointer */ 747c478bd9Sstevel@tonic-gate struct passwd pr; 75*032624d5Sbasabi int i; 767c478bd9Sstevel@tonic-gate int cflag = 0; /* print in order of creation time */ 777c478bd9Sstevel@tonic-gate int nflag = 0; /* just print the number of jobs in */ 787c478bd9Sstevel@tonic-gate /* queue */ 797c478bd9Sstevel@tonic-gate extern int creation(); /* sort jobs by date of creation */ 807c478bd9Sstevel@tonic-gate extern int execution(); /* sort jobs by date of execution */ 817c478bd9Sstevel@tonic-gate int filewanted(); /* should file be included in queue? */ 827c478bd9Sstevel@tonic-gate int countfiles(); /* count the number of files in queue */ 837c478bd9Sstevel@tonic-gate /* for a given person */ 847c478bd9Sstevel@tonic-gate uid_t *uidlist = NULL; /* array of spec. owner ID(s) requ. */ 857c478bd9Sstevel@tonic-gate int argnum = 0; /* number of names passed as arg't */ 867c478bd9Sstevel@tonic-gate int badarg = 0; 877c478bd9Sstevel@tonic-gate char *c; 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate --argc, ++argv; 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 937c478bd9Sstevel@tonic-gate pp = getpwuid(getuid()); 947c478bd9Sstevel@tonic-gate pr.pw_uid = pp->pw_uid; 957c478bd9Sstevel@tonic-gate pr.pw_name = pp->pw_name; 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate if (pp == NULL) 987c478bd9Sstevel@tonic-gate atabort(INVALIDUSER); 997c478bd9Sstevel@tonic-gate if (!allowed(pp->pw_name, ATALLOW, ATDENY)) 1007c478bd9Sstevel@tonic-gate atabort(NOTALLOWED); 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate /* 1037c478bd9Sstevel@tonic-gate * Interpret command line flags if they exist. 1047c478bd9Sstevel@tonic-gate */ 1057c478bd9Sstevel@tonic-gate while (argc > 0 && **argv == '-') { 1067c478bd9Sstevel@tonic-gate (*argv)++; 1077c478bd9Sstevel@tonic-gate while (**argv) { 1087c478bd9Sstevel@tonic-gate switch (*(*argv)++) { 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate case 'c' : cflag++; 1117c478bd9Sstevel@tonic-gate break; 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate case 'n' : nflag++; 1147c478bd9Sstevel@tonic-gate break; 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate default : usage(); 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate } 1197c478bd9Sstevel@tonic-gate } 1207c478bd9Sstevel@tonic-gate --argc, ++argv; 1217c478bd9Sstevel@tonic-gate } 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate /* 1247c478bd9Sstevel@tonic-gate * If a certain name (or names) is requested, set a pointer to the 1257c478bd9Sstevel@tonic-gate * beginning of the list. 1267c478bd9Sstevel@tonic-gate */ 1277c478bd9Sstevel@tonic-gate if (argc > 0) { 1287c478bd9Sstevel@tonic-gate ++namewanted; 1297c478bd9Sstevel@tonic-gate uidlist = (uid_t *)malloc(argc * sizeof (uid_t)); 1307c478bd9Sstevel@tonic-gate if (uidlist == NULL) 1317c478bd9Sstevel@tonic-gate atabortperror("can't allocate list of users"); 1327c478bd9Sstevel@tonic-gate for (i = 0; i < argc; i++) { 1337c478bd9Sstevel@tonic-gate if ((chkauthattr(CRONADMIN_AUTH, pr.pw_name)) || 1347c478bd9Sstevel@tonic-gate strcmp(pr.pw_name, argv[i]) == 0) { 1357c478bd9Sstevel@tonic-gate if ((pp = getpwnam(argv[i])) == NULL) { 1367c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1377c478bd9Sstevel@tonic-gate "atq: No such user %s\n", argv[i]); 1387c478bd9Sstevel@tonic-gate exit(1); 1397c478bd9Sstevel@tonic-gate } 1407c478bd9Sstevel@tonic-gate uidlist[argnum] = pp->pw_uid; 1417c478bd9Sstevel@tonic-gate argnum++; 1427c478bd9Sstevel@tonic-gate } 1437c478bd9Sstevel@tonic-gate else 1447c478bd9Sstevel@tonic-gate badarg++; 1457c478bd9Sstevel@tonic-gate } 1467c478bd9Sstevel@tonic-gate if (badarg) 1477c478bd9Sstevel@tonic-gate if (argnum) 1487c478bd9Sstevel@tonic-gate printf("Printing queue information only " 1497c478bd9Sstevel@tonic-gate "for %s:\n", pr.pw_name); 1507c478bd9Sstevel@tonic-gate else { 1517c478bd9Sstevel@tonic-gate printf("atq: Non-priviledged user cannot " 1527c478bd9Sstevel@tonic-gate "request information regarding other " 1537c478bd9Sstevel@tonic-gate "users\n"); 1547c478bd9Sstevel@tonic-gate exit(1); 1557c478bd9Sstevel@tonic-gate } 1567c478bd9Sstevel@tonic-gate } else if (!chkauthattr(CRONADMIN_AUTH, pr.pw_name)) { 1577c478bd9Sstevel@tonic-gate /* no argument specified and the invoker is not root */ 1587c478bd9Sstevel@tonic-gate ++namewanted; 1597c478bd9Sstevel@tonic-gate argnum = 1; 1607c478bd9Sstevel@tonic-gate if ((uidlist = (uid_t *)malloc(sizeof (uid_t))) == NULL) 1617c478bd9Sstevel@tonic-gate atabortperror("can't allocate list of users"); 1627c478bd9Sstevel@tonic-gate *uidlist = pr.pw_uid; 1637c478bd9Sstevel@tonic-gate } 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate /* 1667c478bd9Sstevel@tonic-gate * Move to the spooling area and scan the directory, placing the 1677c478bd9Sstevel@tonic-gate * files in the queue structure. The queue comes back sorted by 1687c478bd9Sstevel@tonic-gate * execution time or creation time. 1697c478bd9Sstevel@tonic-gate */ 1707c478bd9Sstevel@tonic-gate if (chdir(ATDIR) == -1) 1717c478bd9Sstevel@tonic-gate atabortperror(ATDIR); 1727c478bd9Sstevel@tonic-gate if ((numentries = ascandir(".", &queue, filewanted, 1737c478bd9Sstevel@tonic-gate (cflag) ? creation : execution)) < 0) 1747c478bd9Sstevel@tonic-gate atabortperror(ATDIR); 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate /* 1787c478bd9Sstevel@tonic-gate * Either print a message stating: 1797c478bd9Sstevel@tonic-gate * 1807c478bd9Sstevel@tonic-gate * 1) that the spooling area is empty. 1817c478bd9Sstevel@tonic-gate * 2) the number of jobs in the spooling area. 1827c478bd9Sstevel@tonic-gate * 3) the number of jobs in the spooling area belonging to 1837c478bd9Sstevel@tonic-gate * a certain person. 1847c478bd9Sstevel@tonic-gate * 4) that the person requested doesn't have any files in the 1857c478bd9Sstevel@tonic-gate * spooling area. 1867c478bd9Sstevel@tonic-gate * 1877c478bd9Sstevel@tonic-gate * or send the queue off to "printqueue" for printing. 1887c478bd9Sstevel@tonic-gate * 1897c478bd9Sstevel@tonic-gate * This whole process might seem a bit elaborate, but it's worthwhile 1907c478bd9Sstevel@tonic-gate * to print some informative messages for the user. 1917c478bd9Sstevel@tonic-gate * 1927c478bd9Sstevel@tonic-gate */ 1937c478bd9Sstevel@tonic-gate if ((numentries == 0) && (!nflag)) { 1947c478bd9Sstevel@tonic-gate printf("no files in queue.\n"); 1957c478bd9Sstevel@tonic-gate exit(0); 1967c478bd9Sstevel@tonic-gate } 1977c478bd9Sstevel@tonic-gate if (nflag) { 1987c478bd9Sstevel@tonic-gate printf("%d\n", (namewanted) ? 1997c478bd9Sstevel@tonic-gate countfiles(uidlist, argnum) : numentries); 2007c478bd9Sstevel@tonic-gate exit(0); 2017c478bd9Sstevel@tonic-gate } 2027c478bd9Sstevel@tonic-gate if ((namewanted) && (countfiles(uidlist, argnum) == 0)) { 2037c478bd9Sstevel@tonic-gate if (argnum == 1) 2047c478bd9Sstevel@tonic-gate if (argnum != argc) c = pr.pw_name; 2057c478bd9Sstevel@tonic-gate else c = *argv; 2067c478bd9Sstevel@tonic-gate printf("no files for %s.\n", (argnum == 1) ? 2077c478bd9Sstevel@tonic-gate c : "specified users"); 2087c478bd9Sstevel@tonic-gate exit(0); 2097c478bd9Sstevel@tonic-gate } 2107c478bd9Sstevel@tonic-gate printqueue(uidlist, argnum); 211*032624d5Sbasabi return (0); 2127c478bd9Sstevel@tonic-gate } 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate /* 2157c478bd9Sstevel@tonic-gate * Count the number of jobs in the spooling area owned by a certain person(s). 2167c478bd9Sstevel@tonic-gate */ 217*032624d5Sbasabi int 218*032624d5Sbasabi countfiles(uid_t *uidlist, int nuids) 2197c478bd9Sstevel@tonic-gate { 220*032624d5Sbasabi int i, j; /* for loop indices */ 2217c478bd9Sstevel@tonic-gate int entryfound; /* found file owned by users */ 2227c478bd9Sstevel@tonic-gate int numfiles = 0; /* number of files owned by a */ 2237c478bd9Sstevel@tonic-gate /* certain person(s) */ 224*032624d5Sbasabi uid_t *ptr; /* scratch pointer */ 2257c478bd9Sstevel@tonic-gate struct stat stbuf; /* buffer for file stats */ 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate /* 2297c478bd9Sstevel@tonic-gate * For each file in the queue, see if the user(s) own the file. We 2307c478bd9Sstevel@tonic-gate * have to use "entryfound" (rather than simply incrementing "numfiles") 2317c478bd9Sstevel@tonic-gate * so that if a person's name appears twice on the command line we 2327c478bd9Sstevel@tonic-gate * don't double the number of files owned by him/her. 2337c478bd9Sstevel@tonic-gate */ 2347c478bd9Sstevel@tonic-gate for (i = 0; i < numentries; i++) { 2357c478bd9Sstevel@tonic-gate if ((stat(queue[i]->d_name, &stbuf)) < 0) { 2367c478bd9Sstevel@tonic-gate continue; 2377c478bd9Sstevel@tonic-gate } 2387c478bd9Sstevel@tonic-gate ptr = uidlist; 2397c478bd9Sstevel@tonic-gate entryfound = 0; 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate for (j = 0; j < nuids; j++) { 2427c478bd9Sstevel@tonic-gate if (*ptr == stbuf.st_uid) 2437c478bd9Sstevel@tonic-gate ++entryfound; 2447c478bd9Sstevel@tonic-gate ++ptr; 2457c478bd9Sstevel@tonic-gate } 2467c478bd9Sstevel@tonic-gate if (entryfound) 2477c478bd9Sstevel@tonic-gate ++numfiles; 2487c478bd9Sstevel@tonic-gate } 2497c478bd9Sstevel@tonic-gate return (numfiles); 2507c478bd9Sstevel@tonic-gate } 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate /* 2537c478bd9Sstevel@tonic-gate * Print the queue. If only jobs belonging to a certain person(s) are requested, 2547c478bd9Sstevel@tonic-gate * only print jobs that belong to that person(s). 2557c478bd9Sstevel@tonic-gate */ 256*032624d5Sbasabi static void 257*032624d5Sbasabi printqueue(uid_t *uidlist, int nuids) 2587c478bd9Sstevel@tonic-gate { 259*032624d5Sbasabi int i, j; /* for loop indices */ 2607c478bd9Sstevel@tonic-gate int rank; /* rank of a job */ 2617c478bd9Sstevel@tonic-gate int entryfound; /* found file owned by users */ 2627c478bd9Sstevel@tonic-gate char *getname(); 263*032624d5Sbasabi uid_t *ptr; /* scratch pointer */ 2647c478bd9Sstevel@tonic-gate struct stat stbuf; /* buffer for file stats */ 2657c478bd9Sstevel@tonic-gate char curqueue; /* queue of current job */ 2667c478bd9Sstevel@tonic-gate char lastqueue; /* queue of previous job */ 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate /* 2697c478bd9Sstevel@tonic-gate * Print the header for the queue. 2707c478bd9Sstevel@tonic-gate */ 2717c478bd9Sstevel@tonic-gate printf(" Rank Execution Date Owner Job " 2727c478bd9Sstevel@tonic-gate "Queue Job Name\n"); 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate /* 2757c478bd9Sstevel@tonic-gate * Print the queue. If a certain name(s) was requested, print only jobs 2767c478bd9Sstevel@tonic-gate * belonging to that person(s), otherwise print the entire queue. 2777c478bd9Sstevel@tonic-gate * Once again, we have to use "entryfound" (rather than simply 2787c478bd9Sstevel@tonic-gate * comparing each command line argument) so that if a person's name 2797c478bd9Sstevel@tonic-gate * appears twice we don't print each file owned by him/her twice. 2807c478bd9Sstevel@tonic-gate * 2817c478bd9Sstevel@tonic-gate * 2827c478bd9Sstevel@tonic-gate * "printrank", "printdate", and "printjobname" all take existing 2837c478bd9Sstevel@tonic-gate * data and display it in a friendly manner. 2847c478bd9Sstevel@tonic-gate * 2857c478bd9Sstevel@tonic-gate */ 2867c478bd9Sstevel@tonic-gate lastqueue = '\0'; 2877c478bd9Sstevel@tonic-gate for (i = 0; i < numentries; i++) { 2887c478bd9Sstevel@tonic-gate if ((stat(queue[i]->d_name, &stbuf)) < 0) { 2897c478bd9Sstevel@tonic-gate continue; 2907c478bd9Sstevel@tonic-gate } 2917c478bd9Sstevel@tonic-gate curqueue = *(strchr(queue[i]->d_name, '.') + 1); 2927c478bd9Sstevel@tonic-gate if (curqueue != lastqueue) { 2937c478bd9Sstevel@tonic-gate rank = 1; 2947c478bd9Sstevel@tonic-gate lastqueue = curqueue; 2957c478bd9Sstevel@tonic-gate } 2967c478bd9Sstevel@tonic-gate if (namewanted) { 2977c478bd9Sstevel@tonic-gate ptr = uidlist; 2987c478bd9Sstevel@tonic-gate entryfound = 0; 2997c478bd9Sstevel@tonic-gate 3007c478bd9Sstevel@tonic-gate for (j = 0; j < nuids; j++) { 3017c478bd9Sstevel@tonic-gate if (*ptr == stbuf.st_uid) 3027c478bd9Sstevel@tonic-gate ++entryfound; 3037c478bd9Sstevel@tonic-gate ++ptr; 3047c478bd9Sstevel@tonic-gate } 3057c478bd9Sstevel@tonic-gate if (!entryfound) 3067c478bd9Sstevel@tonic-gate continue; 3077c478bd9Sstevel@tonic-gate } 3087c478bd9Sstevel@tonic-gate printrank(rank++); 3097c478bd9Sstevel@tonic-gate printdate(queue[i]->d_name); 3107c478bd9Sstevel@tonic-gate printf("%-10s ", getname(stbuf.st_uid)); 3117c478bd9Sstevel@tonic-gate printf("%-14s ", queue[i]->d_name); 3127c478bd9Sstevel@tonic-gate printf(" %c", curqueue); 3137c478bd9Sstevel@tonic-gate printjobname(queue[i]->d_name); 3147c478bd9Sstevel@tonic-gate } 3157c478bd9Sstevel@tonic-gate ++ptr; 3167c478bd9Sstevel@tonic-gate } 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate /* 3197c478bd9Sstevel@tonic-gate * Get the uid of a person using his/her login name. Return -1 if no 3207c478bd9Sstevel@tonic-gate * such account name exists. 3217c478bd9Sstevel@tonic-gate */ 3227c478bd9Sstevel@tonic-gate uid_t 323*032624d5Sbasabi getid(char *name) 3247c478bd9Sstevel@tonic-gate { 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate struct passwd *pwdinfo; /* password info structure */ 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate if ((pwdinfo = getpwnam(name)) == 0) 3307c478bd9Sstevel@tonic-gate return ((uid_t)-1); 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate return (pwdinfo->pw_uid); 3337c478bd9Sstevel@tonic-gate } 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate /* 3367c478bd9Sstevel@tonic-gate * Get the full login name of a person using his/her user id. 3377c478bd9Sstevel@tonic-gate */ 3387c478bd9Sstevel@tonic-gate char * 339*032624d5Sbasabi getname(uid_t uid) 3407c478bd9Sstevel@tonic-gate { 341*032624d5Sbasabi struct passwd *pwdinfo; /* password info structure */ 3427c478bd9Sstevel@tonic-gate 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate if ((pwdinfo = getpwuid(uid)) == 0) 3457c478bd9Sstevel@tonic-gate return ("???"); 3467c478bd9Sstevel@tonic-gate return (pwdinfo->pw_name); 3477c478bd9Sstevel@tonic-gate } 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate /* 3507c478bd9Sstevel@tonic-gate * Print the rank of a job. (I've got to admit it, I stole it from "lpq") 3517c478bd9Sstevel@tonic-gate */ 352*032624d5Sbasabi static void 353*032624d5Sbasabi printrank(int n) 3547c478bd9Sstevel@tonic-gate { 3557c478bd9Sstevel@tonic-gate static char *r[] = { 3567c478bd9Sstevel@tonic-gate "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th" 3577c478bd9Sstevel@tonic-gate }; 3587c478bd9Sstevel@tonic-gate 3597c478bd9Sstevel@tonic-gate if ((n/10) == 1) 3607c478bd9Sstevel@tonic-gate printf("%3d%-5s", n, "th"); 3617c478bd9Sstevel@tonic-gate else 3627c478bd9Sstevel@tonic-gate printf("%3d%-5s", n, r[n%10]); 3637c478bd9Sstevel@tonic-gate } 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate /* 3667c478bd9Sstevel@tonic-gate * Print the date that a job is to be executed. This takes some manipulation 3677c478bd9Sstevel@tonic-gate * of the file name. 3687c478bd9Sstevel@tonic-gate */ 369*032624d5Sbasabi static void 370*032624d5Sbasabi printdate(char *filename) 3717c478bd9Sstevel@tonic-gate { 3727c478bd9Sstevel@tonic-gate time_t jobdate; 3737c478bd9Sstevel@tonic-gate extern time_t num(); 374*032624d5Sbasabi struct tm *unpackeddate; 3757c478bd9Sstevel@tonic-gate char date[18]; /* reformatted execution date */ 3767c478bd9Sstevel@tonic-gate 3777c478bd9Sstevel@tonic-gate /* 3787c478bd9Sstevel@tonic-gate * Convert the file name to a date. 3797c478bd9Sstevel@tonic-gate */ 3807c478bd9Sstevel@tonic-gate jobdate = num(&filename); 3817c478bd9Sstevel@tonic-gate unpackeddate = localtime(&jobdate); 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate /* years since 1900 + base century 1900 */ 3847c478bd9Sstevel@tonic-gate unpackeddate->tm_year += 1900; 3857c478bd9Sstevel@tonic-gate /* 3867c478bd9Sstevel@tonic-gate * Format the execution date of a job. 3877c478bd9Sstevel@tonic-gate */ 3887c478bd9Sstevel@tonic-gate sprintf(date, "%3s %2d, %4d %02d:%02d", mthnames[unpackeddate->tm_mon], 3897c478bd9Sstevel@tonic-gate unpackeddate->tm_mday, unpackeddate->tm_year, 3907c478bd9Sstevel@tonic-gate unpackeddate->tm_hour, unpackeddate->tm_min); 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate /* 3937c478bd9Sstevel@tonic-gate * Print the date the job will be executed. 3947c478bd9Sstevel@tonic-gate */ 3957c478bd9Sstevel@tonic-gate printf("%-21.18s", date); 3967c478bd9Sstevel@tonic-gate } 3977c478bd9Sstevel@tonic-gate 3987c478bd9Sstevel@tonic-gate /* 3997c478bd9Sstevel@tonic-gate * Print a job name. If the old "at" has been used to create the spoolfile, 4007c478bd9Sstevel@tonic-gate * the three line header that the new version of "at" puts in the spoolfile. 4017c478bd9Sstevel@tonic-gate * Thus, we just print "???". 4027c478bd9Sstevel@tonic-gate */ 403*032624d5Sbasabi static void 404*032624d5Sbasabi printjobname(char *file) 4057c478bd9Sstevel@tonic-gate { 4067c478bd9Sstevel@tonic-gate char *ptr; /* scratch pointer */ 4077c478bd9Sstevel@tonic-gate char jobname[28]; /* the job name */ 4087c478bd9Sstevel@tonic-gate FILE *filename; /* job file in spooling area */ 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate /* 4117c478bd9Sstevel@tonic-gate * Open the job file and grab the third line. 4127c478bd9Sstevel@tonic-gate */ 4137c478bd9Sstevel@tonic-gate printf(" "); 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate if ((filename = fopen(file, "r")) == NULL) { 4167c478bd9Sstevel@tonic-gate printf("%.27s\n", "???"); 4177c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "atq: Can't open job file %s: %s\n", 4187c478bd9Sstevel@tonic-gate file, errmsg(errno)); 4197c478bd9Sstevel@tonic-gate return; 4207c478bd9Sstevel@tonic-gate } 4217c478bd9Sstevel@tonic-gate /* 4227c478bd9Sstevel@tonic-gate * Skip over the first and second lines. 4237c478bd9Sstevel@tonic-gate */ 4247c478bd9Sstevel@tonic-gate fscanf(filename, "%*[^\n]\n"); 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate /* 4277c478bd9Sstevel@tonic-gate * Now get the job name. 4287c478bd9Sstevel@tonic-gate */ 4297c478bd9Sstevel@tonic-gate if (fscanf(filename, ": jobname: %27s%*[^\n]\n", jobname) != 1) { 4307c478bd9Sstevel@tonic-gate printf("%.27s\n", "???"); 4317c478bd9Sstevel@tonic-gate fclose(filename); 4327c478bd9Sstevel@tonic-gate return; 4337c478bd9Sstevel@tonic-gate } 4347c478bd9Sstevel@tonic-gate fclose(filename); 4357c478bd9Sstevel@tonic-gate 4367c478bd9Sstevel@tonic-gate /* 4377c478bd9Sstevel@tonic-gate * Put a pointer at the begining of the line and remove the basename 4387c478bd9Sstevel@tonic-gate * from the job file. 4397c478bd9Sstevel@tonic-gate */ 4407c478bd9Sstevel@tonic-gate ptr = jobname; 4417c478bd9Sstevel@tonic-gate if ((ptr = (char *)strrchr(jobname, '/')) != 0) 4427c478bd9Sstevel@tonic-gate ++ptr; 4437c478bd9Sstevel@tonic-gate else 4447c478bd9Sstevel@tonic-gate ptr = jobname; 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate if (strlen(ptr) > 23) 4477c478bd9Sstevel@tonic-gate printf("%.23s ...\n", ptr); 4487c478bd9Sstevel@tonic-gate else 4497c478bd9Sstevel@tonic-gate printf("%.27s\n", ptr); 4507c478bd9Sstevel@tonic-gate } 4517c478bd9Sstevel@tonic-gate 4527c478bd9Sstevel@tonic-gate 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate /* 4557c478bd9Sstevel@tonic-gate * Sort files by queue, time of creation, and sequence. (used by "ascandir") 4567c478bd9Sstevel@tonic-gate */ 457*032624d5Sbasabi int 458*032624d5Sbasabi creation(struct dirent **d1, struct dirent **d2) 4597c478bd9Sstevel@tonic-gate { 460*032624d5Sbasabi char *p1, *p2; 461*032624d5Sbasabi int i; 4627c478bd9Sstevel@tonic-gate struct stat stbuf1, stbuf2; 463*032624d5Sbasabi int seq1, seq2; 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate if ((p1 = strchr((*d1)->d_name, '.')) == NULL) 4667c478bd9Sstevel@tonic-gate return (0); 4677c478bd9Sstevel@tonic-gate if ((p2 = strchr((*d2)->d_name, '.')) == NULL) 4687c478bd9Sstevel@tonic-gate return (0); 4697c478bd9Sstevel@tonic-gate p1++; 4707c478bd9Sstevel@tonic-gate p2++; 4717c478bd9Sstevel@tonic-gate if ((i = *p1++ - *p2++) != 0) 4727c478bd9Sstevel@tonic-gate return (i); 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate if (stat((*d1)->d_name, &stbuf1) < 0) 4757c478bd9Sstevel@tonic-gate return (0); 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate if (stat((*d2)->d_name, &stbuf2) < 0) 4787c478bd9Sstevel@tonic-gate return (0); 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate if (stbuf1.st_ctime < stbuf2.st_ctime) 4817c478bd9Sstevel@tonic-gate return (-1); 4827c478bd9Sstevel@tonic-gate else if (stbuf1.st_ctime > stbuf2.st_ctime) 4837c478bd9Sstevel@tonic-gate return (1); 4847c478bd9Sstevel@tonic-gate p1++; 4857c478bd9Sstevel@tonic-gate p2++; 4867c478bd9Sstevel@tonic-gate seq1 = atoi(p1); 4877c478bd9Sstevel@tonic-gate seq2 = atoi(p2); 4887c478bd9Sstevel@tonic-gate return (seq1 - seq2); 4897c478bd9Sstevel@tonic-gate } 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate /* 4927c478bd9Sstevel@tonic-gate * Sort files by queue, time of execution, and sequence. (used by "ascandir") 4937c478bd9Sstevel@tonic-gate */ 494*032624d5Sbasabi int 495*032624d5Sbasabi execution(struct dirent **d1, struct dirent **d2) 4967c478bd9Sstevel@tonic-gate { 497*032624d5Sbasabi char *p1, *p2; 498*032624d5Sbasabi int i; 4997c478bd9Sstevel@tonic-gate char *name1, *name2; 500*032624d5Sbasabi time_t time1, time2; 501*032624d5Sbasabi int seq1, seq2; 5027c478bd9Sstevel@tonic-gate extern time_t num(); 5037c478bd9Sstevel@tonic-gate 5047c478bd9Sstevel@tonic-gate name1 = (*d1)->d_name; 5057c478bd9Sstevel@tonic-gate name2 = (*d2)->d_name; 5067c478bd9Sstevel@tonic-gate if ((p1 = strchr(name1, '.')) == NULL) 5077c478bd9Sstevel@tonic-gate return (1); 5087c478bd9Sstevel@tonic-gate if ((p2 = strchr(name2, '.')) == NULL) 5097c478bd9Sstevel@tonic-gate return (1); 5107c478bd9Sstevel@tonic-gate p1++; 5117c478bd9Sstevel@tonic-gate p2++; 5127c478bd9Sstevel@tonic-gate if ((i = *p1++ - *p2++) != 0) 5137c478bd9Sstevel@tonic-gate return (i); 5147c478bd9Sstevel@tonic-gate 5157c478bd9Sstevel@tonic-gate time1 = num(&name1); 5167c478bd9Sstevel@tonic-gate time2 = num(&name2); 5177c478bd9Sstevel@tonic-gate 5187c478bd9Sstevel@tonic-gate if (time1 < time2) 5197c478bd9Sstevel@tonic-gate return (-1); 5207c478bd9Sstevel@tonic-gate else if (time1 > time2) 5217c478bd9Sstevel@tonic-gate return (1); 5227c478bd9Sstevel@tonic-gate p1++; 5237c478bd9Sstevel@tonic-gate p2++; 5247c478bd9Sstevel@tonic-gate seq1 = atoi(p1); 5257c478bd9Sstevel@tonic-gate seq2 = atoi(p2); 5267c478bd9Sstevel@tonic-gate return (seq1 - seq2); 5277c478bd9Sstevel@tonic-gate } 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate 5307c478bd9Sstevel@tonic-gate /* 5317c478bd9Sstevel@tonic-gate * Print usage info and exit. 5327c478bd9Sstevel@tonic-gate */ 533*032624d5Sbasabi static void 534*032624d5Sbasabi usage(void) 5357c478bd9Sstevel@tonic-gate { 5367c478bd9Sstevel@tonic-gate fprintf(stderr, "usage: atq [-c] [-n] [name ...]\n"); 5377c478bd9Sstevel@tonic-gate exit(1); 5387c478bd9Sstevel@tonic-gate } 5397c478bd9Sstevel@tonic-gate 540*032624d5Sbasabi static void 541*032624d5Sbasabi aterror(char *msg) 5427c478bd9Sstevel@tonic-gate { 5437c478bd9Sstevel@tonic-gate fprintf(stderr, "atq: %s\n", msg); 5447c478bd9Sstevel@tonic-gate } 5457c478bd9Sstevel@tonic-gate 546*032624d5Sbasabi static void 547*032624d5Sbasabi atperror(char *msg) 5487c478bd9Sstevel@tonic-gate { 5497c478bd9Sstevel@tonic-gate fprintf(stderr, "atq: %s: %s\n", msg, errmsg(errno)); 5507c478bd9Sstevel@tonic-gate } 5517c478bd9Sstevel@tonic-gate 552*032624d5Sbasabi static void 553*032624d5Sbasabi atabort(char *msg) 5547c478bd9Sstevel@tonic-gate { 5557c478bd9Sstevel@tonic-gate aterror(msg); 5567c478bd9Sstevel@tonic-gate exit(1); 5577c478bd9Sstevel@tonic-gate } 5587c478bd9Sstevel@tonic-gate 559*032624d5Sbasabi static void 560*032624d5Sbasabi atabortperror(char *msg) 5617c478bd9Sstevel@tonic-gate { 5627c478bd9Sstevel@tonic-gate atperror(msg); 5637c478bd9Sstevel@tonic-gate exit(1); 5647c478bd9Sstevel@tonic-gate } 565