1 523 basabi /* 2 11115 Nobutomo * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 3 523 basabi * Use is subject to license terms. 4 523 basabi */ 5 523 basabi 6 0 stevel /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 7 0 stevel /* All Rights Reserved */ 8 0 stevel 9 0 stevel 10 0 stevel /* 11 0 stevel * Copyright (c) 1983 Regents of the University of California. 12 0 stevel * All rights reserved. The Berkeley software License Agreement 13 0 stevel * specifies the terms and conditions for redistribution. 14 0 stevel */ 15 0 stevel 16 0 stevel /* 17 0 stevel * 18 0 stevel * Synopsis: atq [ -c ] [ -n ] [ name ... ] 19 0 stevel * 20 0 stevel * 21 0 stevel * Print the queue of files waiting to be executed. These files 22 0 stevel * were created by using the "at" command and are located in the 23 0 stevel * directory defined by ATDIR. 24 0 stevel */ 25 0 stevel 26 0 stevel #include <stdio.h> 27 0 stevel #include <sys/types.h> 28 0 stevel #include <sys/file.h> 29 0 stevel #include <dirent.h> 30 0 stevel #include <sys/stat.h> 31 0 stevel #include <time.h> 32 0 stevel #include <pwd.h> 33 0 stevel #include <ctype.h> 34 0 stevel #include <unistd.h> 35 0 stevel #include <locale.h> 36 0 stevel #include <errno.h> 37 4774 as145665 #include <stdlib.h> 38 4774 as145665 #include <string.h> 39 0 stevel #include "cron.h" 40 0 stevel 41 0 stevel extern char *errmsg(); 42 0 stevel extern char *strchr(); 43 0 stevel 44 0 stevel /* 45 0 stevel * Months of the year 46 0 stevel */ 47 0 stevel static char *mthnames[12] = { 48 0 stevel "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", 49 0 stevel "Aug", "Sep", "Oct", "Nov", "Dec", 50 0 stevel }; 51 0 stevel 52 0 stevel int numentries; /* number of entries in spooling area */ 53 0 stevel int namewanted = 0; /* print jobs for a certain person */ 54 0 stevel struct dirent **queue; /* the queue itself */ 55 0 stevel 56 0 stevel #define INVALIDUSER "you are not a valid user (no entry in /etc/passwd)" 57 0 stevel #define NOTALLOWED "you are not authorized to use at. Sorry." 58 0 stevel 59 523 basabi static void atabortperror(char *msg); 60 523 basabi static void atabort(char *msg); 61 523 basabi static void aterror(char *msg); 62 523 basabi static void atperror(char *msg); 63 523 basabi static void usage(void); 64 523 basabi static void printjobname(char *file); 65 523 basabi static void printdate(char *filename); 66 523 basabi static void printrank(int n); 67 523 basabi static void printqueue(uid_t *uidlist, int nuids); 68 0 stevel 69 523 basabi int 70 523 basabi main(int argc, char **argv) 71 0 stevel { 72 0 stevel 73 523 basabi struct passwd *pp; /* password file entry pointer */ 74 0 stevel struct passwd pr; 75 523 basabi int i; 76 0 stevel int cflag = 0; /* print in order of creation time */ 77 0 stevel int nflag = 0; /* just print the number of jobs in */ 78 0 stevel /* queue */ 79 0 stevel extern int creation(); /* sort jobs by date of creation */ 80 0 stevel extern int execution(); /* sort jobs by date of execution */ 81 0 stevel int filewanted(); /* should file be included in queue? */ 82 0 stevel int countfiles(); /* count the number of files in queue */ 83 0 stevel /* for a given person */ 84 0 stevel uid_t *uidlist = NULL; /* array of spec. owner ID(s) requ. */ 85 0 stevel int argnum = 0; /* number of names passed as arg't */ 86 0 stevel int badarg = 0; 87 0 stevel char *c; 88 0 stevel 89 0 stevel 90 0 stevel --argc, ++argv; 91 0 stevel 92 0 stevel (void) setlocale(LC_ALL, ""); 93 0 stevel pp = getpwuid(getuid()); 94 0 stevel pr.pw_uid = pp->pw_uid; 95 0 stevel pr.pw_name = pp->pw_name; 96 0 stevel 97 0 stevel if (pp == NULL) 98 0 stevel atabort(INVALIDUSER); 99 0 stevel if (!allowed(pp->pw_name, ATALLOW, ATDENY)) 100 0 stevel atabort(NOTALLOWED); 101 0 stevel 102 0 stevel /* 103 0 stevel * Interpret command line flags if they exist. 104 0 stevel */ 105 0 stevel while (argc > 0 && **argv == '-') { 106 0 stevel (*argv)++; 107 0 stevel while (**argv) { 108 0 stevel switch (*(*argv)++) { 109 0 stevel 110 0 stevel case 'c' : cflag++; 111 0 stevel break; 112 0 stevel 113 0 stevel case 'n' : nflag++; 114 0 stevel break; 115 0 stevel 116 0 stevel default : usage(); 117 0 stevel 118 0 stevel } 119 0 stevel } 120 0 stevel --argc, ++argv; 121 0 stevel } 122 0 stevel 123 0 stevel /* 124 0 stevel * If a certain name (or names) is requested, set a pointer to the 125 0 stevel * beginning of the list. 126 0 stevel */ 127 0 stevel if (argc > 0) { 128 0 stevel ++namewanted; 129 0 stevel uidlist = (uid_t *)malloc(argc * sizeof (uid_t)); 130 0 stevel if (uidlist == NULL) 131 0 stevel atabortperror("can't allocate list of users"); 132 0 stevel for (i = 0; i < argc; i++) { 133 11115 Nobutomo if (cron_admin(pr.pw_name) || 134 4774 as145665 strcmp(pr.pw_name, argv[i]) == 0) { 135 0 stevel if ((pp = getpwnam(argv[i])) == NULL) { 136 0 stevel (void) fprintf(stderr, 137 0 stevel "atq: No such user %s\n", argv[i]); 138 0 stevel exit(1); 139 0 stevel } 140 0 stevel uidlist[argnum] = pp->pw_uid; 141 0 stevel argnum++; 142 0 stevel } 143 0 stevel else 144 0 stevel badarg++; 145 0 stevel } 146 0 stevel if (badarg) 147 0 stevel if (argnum) 148 0 stevel printf("Printing queue information only " 149 0 stevel "for %s:\n", pr.pw_name); 150 0 stevel else { 151 0 stevel printf("atq: Non-priviledged user cannot " 152 0 stevel "request information regarding other " 153 0 stevel "users\n"); 154 0 stevel exit(1); 155 0 stevel } 156 11115 Nobutomo } else if (!cron_admin(pr.pw_name)) { 157 0 stevel /* no argument specified and the invoker is not root */ 158 0 stevel ++namewanted; 159 0 stevel argnum = 1; 160 0 stevel if ((uidlist = (uid_t *)malloc(sizeof (uid_t))) == NULL) 161 0 stevel atabortperror("can't allocate list of users"); 162 0 stevel *uidlist = pr.pw_uid; 163 0 stevel } 164 0 stevel 165 0 stevel /* 166 0 stevel * Move to the spooling area and scan the directory, placing the 167 0 stevel * files in the queue structure. The queue comes back sorted by 168 0 stevel * execution time or creation time. 169 0 stevel */ 170 0 stevel if (chdir(ATDIR) == -1) 171 0 stevel atabortperror(ATDIR); 172 6628 jk217608 if ((numentries = scandir(".", &queue, filewanted, 173 0 stevel (cflag) ? creation : execution)) < 0) 174 0 stevel atabortperror(ATDIR); 175 0 stevel 176 0 stevel 177 0 stevel /* 178 0 stevel * Either print a message stating: 179 0 stevel * 180 0 stevel * 1) that the spooling area is empty. 181 0 stevel * 2) the number of jobs in the spooling area. 182 0 stevel * 3) the number of jobs in the spooling area belonging to 183 0 stevel * a certain person. 184 0 stevel * 4) that the person requested doesn't have any files in the 185 0 stevel * spooling area. 186 0 stevel * 187 0 stevel * or send the queue off to "printqueue" for printing. 188 0 stevel * 189 0 stevel * This whole process might seem a bit elaborate, but it's worthwhile 190 0 stevel * to print some informative messages for the user. 191 0 stevel * 192 0 stevel */ 193 0 stevel if ((numentries == 0) && (!nflag)) { 194 0 stevel printf("no files in queue.\n"); 195 0 stevel exit(0); 196 0 stevel } 197 0 stevel if (nflag) { 198 0 stevel printf("%d\n", (namewanted) ? 199 0 stevel countfiles(uidlist, argnum) : numentries); 200 0 stevel exit(0); 201 0 stevel } 202 0 stevel if ((namewanted) && (countfiles(uidlist, argnum) == 0)) { 203 0 stevel if (argnum == 1) 204 0 stevel if (argnum != argc) c = pr.pw_name; 205 0 stevel else c = *argv; 206 0 stevel printf("no files for %s.\n", (argnum == 1) ? 207 4774 as145665 c : "specified users"); 208 0 stevel exit(0); 209 0 stevel } 210 0 stevel printqueue(uidlist, argnum); 211 523 basabi return (0); 212 0 stevel } 213 0 stevel 214 0 stevel /* 215 0 stevel * Count the number of jobs in the spooling area owned by a certain person(s). 216 0 stevel */ 217 523 basabi int 218 523 basabi countfiles(uid_t *uidlist, int nuids) 219 0 stevel { 220 523 basabi int i, j; /* for loop indices */ 221 0 stevel int entryfound; /* found file owned by users */ 222 0 stevel int numfiles = 0; /* number of files owned by a */ 223 0 stevel /* certain person(s) */ 224 523 basabi uid_t *ptr; /* scratch pointer */ 225 0 stevel struct stat stbuf; /* buffer for file stats */ 226 0 stevel 227 0 stevel 228 0 stevel /* 229 0 stevel * For each file in the queue, see if the user(s) own the file. We 230 0 stevel * have to use "entryfound" (rather than simply incrementing "numfiles") 231 0 stevel * so that if a person's name appears twice on the command line we 232 0 stevel * don't double the number of files owned by him/her. 233 0 stevel */ 234 0 stevel for (i = 0; i < numentries; i++) { 235 0 stevel if ((stat(queue[i]->d_name, &stbuf)) < 0) { 236 0 stevel continue; 237 0 stevel } 238 0 stevel ptr = uidlist; 239 0 stevel entryfound = 0; 240 0 stevel 241 0 stevel for (j = 0; j < nuids; j++) { 242 0 stevel if (*ptr == stbuf.st_uid) 243 0 stevel ++entryfound; 244 0 stevel ++ptr; 245 0 stevel } 246 0 stevel if (entryfound) 247 0 stevel ++numfiles; 248 0 stevel } 249 0 stevel return (numfiles); 250 0 stevel } 251 0 stevel 252 0 stevel /* 253 0 stevel * Print the queue. If only jobs belonging to a certain person(s) are requested, 254 0 stevel * only print jobs that belong to that person(s). 255 0 stevel */ 256 523 basabi static void 257 523 basabi printqueue(uid_t *uidlist, int nuids) 258 0 stevel { 259 523 basabi int i, j; /* for loop indices */ 260 0 stevel int rank; /* rank of a job */ 261 0 stevel int entryfound; /* found file owned by users */ 262 0 stevel char *getname(); 263 523 basabi uid_t *ptr; /* scratch pointer */ 264 0 stevel struct stat stbuf; /* buffer for file stats */ 265 0 stevel char curqueue; /* queue of current job */ 266 0 stevel char lastqueue; /* queue of previous job */ 267 0 stevel 268 0 stevel /* 269 0 stevel * Print the header for the queue. 270 0 stevel */ 271 0 stevel printf(" Rank Execution Date Owner Job " 272 0 stevel "Queue Job Name\n"); 273 0 stevel 274 0 stevel /* 275 0 stevel * Print the queue. If a certain name(s) was requested, print only jobs 276 0 stevel * belonging to that person(s), otherwise print the entire queue. 277 0 stevel * Once again, we have to use "entryfound" (rather than simply 278 0 stevel * comparing each command line argument) so that if a person's name 279 0 stevel * appears twice we don't print each file owned by him/her twice. 280 0 stevel * 281 0 stevel * 282 0 stevel * "printrank", "printdate", and "printjobname" all take existing 283 0 stevel * data and display it in a friendly manner. 284 0 stevel * 285 0 stevel */ 286 0 stevel lastqueue = '\0'; 287 0 stevel for (i = 0; i < numentries; i++) { 288 0 stevel if ((stat(queue[i]->d_name, &stbuf)) < 0) { 289 0 stevel continue; 290 0 stevel } 291 0 stevel curqueue = *(strchr(queue[i]->d_name, '.') + 1); 292 0 stevel if (curqueue != lastqueue) { 293 0 stevel rank = 1; 294 0 stevel lastqueue = curqueue; 295 0 stevel } 296 0 stevel if (namewanted) { 297 0 stevel ptr = uidlist; 298 0 stevel entryfound = 0; 299 0 stevel 300 0 stevel for (j = 0; j < nuids; j++) { 301 0 stevel if (*ptr == stbuf.st_uid) 302 0 stevel ++entryfound; 303 0 stevel ++ptr; 304 0 stevel } 305 0 stevel if (!entryfound) 306 0 stevel continue; 307 0 stevel } 308 0 stevel printrank(rank++); 309 0 stevel printdate(queue[i]->d_name); 310 0 stevel printf("%-10s ", getname(stbuf.st_uid)); 311 0 stevel printf("%-14s ", queue[i]->d_name); 312 0 stevel printf(" %c", curqueue); 313 0 stevel printjobname(queue[i]->d_name); 314 0 stevel } 315 0 stevel ++ptr; 316 0 stevel } 317 0 stevel 318 0 stevel /* 319 0 stevel * Get the uid of a person using his/her login name. Return -1 if no 320 0 stevel * such account name exists. 321 0 stevel */ 322 0 stevel uid_t 323 523 basabi getid(char *name) 324 0 stevel { 325 0 stevel 326 0 stevel struct passwd *pwdinfo; /* password info structure */ 327 0 stevel 328 0 stevel 329 0 stevel if ((pwdinfo = getpwnam(name)) == 0) 330 0 stevel return ((uid_t)-1); 331 0 stevel 332 0 stevel return (pwdinfo->pw_uid); 333 0 stevel } 334 0 stevel 335 0 stevel /* 336 0 stevel * Get the full login name of a person using his/her user id. 337 0 stevel */ 338 0 stevel char * 339 523 basabi getname(uid_t uid) 340 0 stevel { 341 523 basabi struct passwd *pwdinfo; /* password info structure */ 342 0 stevel 343 0 stevel 344 0 stevel if ((pwdinfo = getpwuid(uid)) == 0) 345 0 stevel return ("???"); 346 0 stevel return (pwdinfo->pw_name); 347 0 stevel } 348 0 stevel 349 0 stevel /* 350 0 stevel * Print the rank of a job. (I've got to admit it, I stole it from "lpq") 351 0 stevel */ 352 523 basabi static void 353 523 basabi printrank(int n) 354 0 stevel { 355 0 stevel static char *r[] = { 356 0 stevel "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th" 357 0 stevel }; 358 0 stevel 359 0 stevel if ((n/10) == 1) 360 0 stevel printf("%3d%-5s", n, "th"); 361 0 stevel else 362 0 stevel printf("%3d%-5s", n, r[n%10]); 363 0 stevel } 364 0 stevel 365 0 stevel /* 366 0 stevel * Print the date that a job is to be executed. This takes some manipulation 367 0 stevel * of the file name. 368 0 stevel */ 369 523 basabi static void 370 523 basabi printdate(char *filename) 371 0 stevel { 372 0 stevel time_t jobdate; 373 523 basabi struct tm *unpackeddate; 374 0 stevel char date[18]; /* reformatted execution date */ 375 0 stevel 376 0 stevel /* 377 0 stevel * Convert the file name to a date. 378 0 stevel */ 379 0 stevel jobdate = num(&filename); 380 0 stevel unpackeddate = localtime(&jobdate); 381 0 stevel 382 0 stevel /* years since 1900 + base century 1900 */ 383 0 stevel unpackeddate->tm_year += 1900; 384 0 stevel /* 385 0 stevel * Format the execution date of a job. 386 0 stevel */ 387 0 stevel sprintf(date, "%3s %2d, %4d %02d:%02d", mthnames[unpackeddate->tm_mon], 388 0 stevel unpackeddate->tm_mday, unpackeddate->tm_year, 389 0 stevel unpackeddate->tm_hour, unpackeddate->tm_min); 390 0 stevel 391 0 stevel /* 392 0 stevel * Print the date the job will be executed. 393 0 stevel */ 394 0 stevel printf("%-21.18s", date); 395 0 stevel } 396 0 stevel 397 0 stevel /* 398 0 stevel * Print a job name. If the old "at" has been used to create the spoolfile, 399 0 stevel * the three line header that the new version of "at" puts in the spoolfile. 400 0 stevel * Thus, we just print "???". 401 0 stevel */ 402 523 basabi static void 403 523 basabi printjobname(char *file) 404 0 stevel { 405 0 stevel char *ptr; /* scratch pointer */ 406 0 stevel char jobname[28]; /* the job name */ 407 0 stevel FILE *filename; /* job file in spooling area */ 408 0 stevel 409 0 stevel /* 410 0 stevel * Open the job file and grab the third line. 411 0 stevel */ 412 0 stevel printf(" "); 413 0 stevel 414 0 stevel if ((filename = fopen(file, "r")) == NULL) { 415 0 stevel printf("%.27s\n", "???"); 416 0 stevel (void) fprintf(stderr, "atq: Can't open job file %s: %s\n", 417 0 stevel file, errmsg(errno)); 418 0 stevel return; 419 0 stevel } 420 0 stevel /* 421 0 stevel * Skip over the first and second lines. 422 0 stevel */ 423 0 stevel fscanf(filename, "%*[^\n]\n"); 424 0 stevel 425 0 stevel /* 426 0 stevel * Now get the job name. 427 0 stevel */ 428 0 stevel if (fscanf(filename, ": jobname: %27s%*[^\n]\n", jobname) != 1) { 429 0 stevel printf("%.27s\n", "???"); 430 0 stevel fclose(filename); 431 0 stevel return; 432 0 stevel } 433 0 stevel fclose(filename); 434 0 stevel 435 0 stevel /* 436 0 stevel * Put a pointer at the begining of the line and remove the basename 437 0 stevel * from the job file. 438 0 stevel */ 439 0 stevel ptr = jobname; 440 0 stevel if ((ptr = (char *)strrchr(jobname, '/')) != 0) 441 0 stevel ++ptr; 442 0 stevel else 443 0 stevel ptr = jobname; 444 0 stevel 445 0 stevel if (strlen(ptr) > 23) 446 0 stevel printf("%.23s ...\n", ptr); 447 0 stevel else 448 0 stevel printf("%.27s\n", ptr); 449 0 stevel } 450 0 stevel 451 0 stevel 452 0 stevel 453 0 stevel /* 454 6628 jk217608 * Sort files by queue, time of creation, and sequence. (used by "scandir") 455 0 stevel */ 456 523 basabi int 457 523 basabi creation(struct dirent **d1, struct dirent **d2) 458 0 stevel { 459 523 basabi char *p1, *p2; 460 523 basabi int i; 461 0 stevel struct stat stbuf1, stbuf2; 462 523 basabi int seq1, seq2; 463 0 stevel 464 0 stevel if ((p1 = strchr((*d1)->d_name, '.')) == NULL) 465 0 stevel return (0); 466 0 stevel if ((p2 = strchr((*d2)->d_name, '.')) == NULL) 467 0 stevel return (0); 468 0 stevel p1++; 469 0 stevel p2++; 470 0 stevel if ((i = *p1++ - *p2++) != 0) 471 0 stevel return (i); 472 0 stevel 473 0 stevel if (stat((*d1)->d_name, &stbuf1) < 0) 474 0 stevel return (0); 475 0 stevel 476 0 stevel if (stat((*d2)->d_name, &stbuf2) < 0) 477 0 stevel return (0); 478 0 stevel 479 0 stevel if (stbuf1.st_ctime < stbuf2.st_ctime) 480 0 stevel return (-1); 481 0 stevel else if (stbuf1.st_ctime > stbuf2.st_ctime) 482 0 stevel return (1); 483 0 stevel p1++; 484 0 stevel p2++; 485 0 stevel seq1 = atoi(p1); 486 0 stevel seq2 = atoi(p2); 487 0 stevel return (seq1 - seq2); 488 0 stevel } 489 0 stevel 490 0 stevel /* 491 6628 jk217608 * Sort files by queue, time of execution, and sequence. (used by "scandir") 492 0 stevel */ 493 523 basabi int 494 523 basabi execution(struct dirent **d1, struct dirent **d2) 495 0 stevel { 496 523 basabi char *p1, *p2; 497 523 basabi int i; 498 0 stevel char *name1, *name2; 499 523 basabi time_t time1, time2; 500 523 basabi int seq1, seq2; 501 0 stevel 502 0 stevel name1 = (*d1)->d_name; 503 0 stevel name2 = (*d2)->d_name; 504 0 stevel if ((p1 = strchr(name1, '.')) == NULL) 505 0 stevel return (1); 506 0 stevel if ((p2 = strchr(name2, '.')) == NULL) 507 0 stevel return (1); 508 0 stevel p1++; 509 0 stevel p2++; 510 0 stevel if ((i = *p1++ - *p2++) != 0) 511 0 stevel return (i); 512 0 stevel 513 0 stevel time1 = num(&name1); 514 0 stevel time2 = num(&name2); 515 0 stevel 516 0 stevel if (time1 < time2) 517 0 stevel return (-1); 518 0 stevel else if (time1 > time2) 519 0 stevel return (1); 520 0 stevel p1++; 521 0 stevel p2++; 522 0 stevel seq1 = atoi(p1); 523 0 stevel seq2 = atoi(p2); 524 0 stevel return (seq1 - seq2); 525 0 stevel } 526 0 stevel 527 0 stevel 528 0 stevel /* 529 0 stevel * Print usage info and exit. 530 0 stevel */ 531 523 basabi static void 532 523 basabi usage(void) 533 0 stevel { 534 0 stevel fprintf(stderr, "usage: atq [-c] [-n] [name ...]\n"); 535 0 stevel exit(1); 536 0 stevel } 537 0 stevel 538 523 basabi static void 539 523 basabi aterror(char *msg) 540 0 stevel { 541 0 stevel fprintf(stderr, "atq: %s\n", msg); 542 0 stevel } 543 0 stevel 544 523 basabi static void 545 523 basabi atperror(char *msg) 546 0 stevel { 547 0 stevel fprintf(stderr, "atq: %s: %s\n", msg, errmsg(errno)); 548 0 stevel } 549 0 stevel 550 523 basabi static void 551 523 basabi atabort(char *msg) 552 0 stevel { 553 0 stevel aterror(msg); 554 0 stevel exit(1); 555 0 stevel } 556 0 stevel 557 523 basabi static void 558 523 basabi atabortperror(char *msg) 559 0 stevel { 560 0 stevel atperror(msg); 561 0 stevel exit(1); 562 0 stevel } 563