Annotation of 43BSD/usr.bin/at/atrm.c, revision 1.1.1.1

1.1       root        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[] = "@(#)atrm.c     5.2 (Berkeley) 5/28/86";
                     15: #endif not lint
                     16: 
                     17: /*
                     18:  *     synopsis: atrm [-f] [-i] [-] [[job #] [user] ...]
                     19:  *
                     20:  *
                     21:  *     Remove files from the directory /usr/spool/at. These files
                     22:  *     represent jobs to be run at a later date.
                     23:  *
                     24:  *     Author: Steve Wall
                     25:  *             Computer Systems Research Group
                     26:  *             University of California @ Berkeley
                     27:  *
                     28:  */
                     29: 
                     30: #include <stdio.h>
                     31: #include <pwd.h>
                     32: #include <ctype.h>
                     33: #include <sys/types.h>
                     34: #include <sys/dir.h>
                     35: #include <sys/file.h>
                     36: #include <sys/stat.h>
                     37: 
                     38: #define SUPERUSER      0                       /* is user super-user? */
                     39: #define MAXENTRIES     1000                    /* max # of entries allowed */
                     40: #define ATDIR          "/usr/spool/at"         /* spooling area */
                     41: 
                     42: 
                     43: int user;                                      /* person requesting removal */
                     44: int fflag = 0;                                 /* suppress announcements? */
                     45: int iflag = 0;                                 /* run interactively? */
                     46: 
                     47: main(argc,argv)
                     48: int argc;
                     49: char **argv;
                     50: 
                     51: {
                     52:        int i;                          /* for loop index */
                     53:        int userid;                     /* uid of owner of file */
                     54:        int isuname;                    /* is a command line argv a user name?*/
                     55:        int numjobs;                    /* # of jobs in spooling area */
                     56:        int usage();                    /* print usage info and exit */
                     57:        int allflag = 0;                /* remove all jobs belonging to user? */
                     58:        int jobexists;                  /* does a requested job exist? */
                     59:        int alphasort();                /* sort jobs by date of execution */
                     60:        int filewanted();               /* should a file be listed in queue? */
                     61:        char *getname();                /* get a user name from a uid */
                     62:        struct stat *statptr;           /* pointer to file stat structure */
                     63:        struct stat *stbuf[MAXENTRIES]; /* array of pointers to stat structs */
                     64:        struct direct **namelist;       /* names of jobs in spooling area */
                     65: 
                     66: 
                     67:        /*
                     68:         * If job number, user name, or "-" is not specified, just print
                     69:         * usage info and exit.
                     70:         */
                     71:        if (argc < 2)
                     72:                usage();
                     73: 
                     74:        --argc; ++argv;
                     75: 
                     76:        /*
                     77:         * Process command line flags.
                     78:         * Special case the "-" option so that others may be grouped.
                     79:         */
                     80:        while (argc > 0 && **argv == '-') {
                     81:                if (*(++(*argv)) == '\0') {
                     82:                        ++allflag;
                     83:                } else while (**argv) switch (*(*argv)++) {
                     84: 
                     85:                        case 'f':       ++fflag;
                     86:                                        break;
                     87:                                        
                     88:                        case 'i':       ++iflag;
                     89:                                        break;
                     90:                                        
                     91:                        default:        usage();
                     92:                }
                     93:                ++argv; --argc;
                     94:        }
                     95: 
                     96:        /*
                     97:         * If all jobs are to be removed and extra command line arguments 
                     98:         * are given, print usage info and exit.
                     99:         */
                    100:        if (allflag && argc) 
                    101:                usage();
                    102: 
                    103:        /*
                    104:         * If only certain jobs are to be removed and no job #'s or user
                    105:         * names are specified, print usage info and exit.
                    106:         */
                    107:        if (!allflag && !argc)
                    108:                usage();
                    109: 
                    110:        /*
                    111:         * If interactive removal and quiet removal are requested, override
                    112:         * quiet removal and run interactively.
                    113:         */
                    114:        if (iflag && fflag)
                    115:                fflag = 0;
                    116: 
                    117:        /* 
                    118:         * Move to spooling area and get user id of person requesting removal.
                    119:         */
                    120:        if (chdir(ATDIR) == -1) {
                    121:                perror(ATDIR);
                    122:                exit(1);
                    123:        }
                    124:        user = getuid();
                    125: 
                    126:        /*
                    127:         * Get a list of the files in the spooling area.
                    128:         */
                    129:        if ((numjobs = scandir(".",&namelist,filewanted,alphasort)) < 0) {
                    130:                perror(ATDIR);
                    131:                exit(1);
                    132:        }
                    133: 
                    134:        /*
                    135:         * Build an array of pointers to the file stats for all jobs in
                    136:         * the spooling area.
                    137:         */
                    138:        for (i = 0; i < numjobs; ++i) { 
                    139:                statptr = (struct stat *) malloc(sizeof(struct stat));
                    140:                if (statptr == NULL) {
                    141:                        perror("malloc");
                    142:                        exit(1);
                    143:                }
                    144:                if (stat(namelist[i]->d_name,statptr) < 0) {
                    145:                        perror("stat");
                    146:                        continue;
                    147:                }
                    148:                stbuf[i] = statptr;
                    149:        }
                    150: 
                    151:        /*
                    152:         * If all jobs belonging to the user are to be removed, compare
                    153:         * the user's id to the owner of the file. If they match, remove
                    154:         * the file. If the user is the super-user, don't bother comparing
                    155:         * the id's. After all files are removed, exit (status 0).
                    156:         */
                    157:        if (allflag) {
                    158:                for (i = 0; i < numjobs; ++i) { 
                    159:                        if (user == SUPERUSER || isowner(getname(user),
                    160:                                                        namelist[i]->d_name)) 
                    161:                                (void) removentry(namelist[i]->d_name,
                    162:                                                (int)stbuf[i]->st_ino,
                    163:                                                        user);
                    164:                }
                    165:                exit(0);
                    166:        }
                    167: 
                    168:        /*
                    169:         * If only certain jobs are to be removed, interpret each command
                    170:         * line argument. A check is done to see if it is a user's name or
                    171:         * a job number (inode #). If it's a user's name, compare the argument
                    172:         * to the files owner. If it's a job number, compare the argument to
                    173:         * the inode number of the file. In either case, if a match occurs,
                    174:         * try to remove the file. (The function "isusername" scans the
                    175:         * argument to see if it is all digits which we will assume means 
                    176:         * that it's a job number (a fairly safe assumption?). This is done
                    177:         * because we have to determine whether we are dealing with a user
                    178:         * name or a job number. By assuming that only arguments that are
                    179:         * all digits is a job number, we allow users to have digits in
                    180:         * their login name i.e. "johndoe2").
                    181:         */
                    182: 
                    183:        while (argc--) {
                    184:                jobexists = 0;
                    185:                isuname = isusername(*argv);
                    186:                for (i = 0; i < numjobs; ++i) {
                    187: 
                    188:                        /* if the inode number is 0, this entry was removed */
                    189:                        if (stbuf[i]->st_ino == 0)
                    190:                                continue;
                    191: 
                    192:                        /* 
                    193:                         * if argv is a username, compare his/her uid to
                    194:                         * the uid of the owner of the file......
                    195:                         */
                    196:                        if (isuname) {
                    197:                                if (!isowner(*argv,namelist[i]->d_name))
                    198:                                        continue;
                    199: 
                    200:                        /*
                    201:                         * otherwise, we assume that the argv is a job # and
                    202:                         * thus compare argv to the inode (job #) of the file.
                    203:                         */
                    204:                        } else {
                    205:                                if (stbuf[i]->st_ino != atoi(*argv)) 
                    206:                                        continue;
                    207:                        }
                    208:                        ++jobexists;
                    209:                        /*
                    210:                         * if the entry is ultimately removed, don't
                    211:                         * try to remove it again later.
                    212:                         */
                    213:                        if (removentry(namelist[i]->d_name,
                    214:                            (int)stbuf[i]->st_ino, user)) {
                    215:                                stbuf[i]->st_ino = 0;
                    216:                        }
                    217:                }
                    218: 
                    219:                /*
                    220:                 * If a requested argument doesn't exist, print a message.
                    221:                 */
                    222:                if (!jobexists && !fflag && !isuname) {
                    223:                        fprintf(stderr, "%6s: no such job number\n", *argv);
                    224:                }
                    225:                ++argv;
                    226:        }
                    227:        exit(0);
                    228: }
                    229: 
                    230: /*
                    231:  * Print usage info and exit.
                    232:  */
                    233: usage()
                    234: {
                    235:        fprintf(stderr,"usage: atrm [-f] [-i] [-] [[job #] [user] ...]\n");
                    236:        exit(1);
                    237: }
                    238: 
                    239: /*
                    240:  * Do we want to include a file in the queue? (used by "scandir") We are looking
                    241:  * for files with following syntax: yy.ddd.hhhh. so the test is made to see if 
                    242:  * the file name has three dots in it. This test will suffice since the only
                    243:  * other files in /usr/spool/at don't have any dots in their name.
                    244:  */
                    245: filewanted(direntry)
                    246: struct direct *direntry;
                    247: {
                    248:        int numdot = 0;                 /* number of dots in a filename */
                    249:        char *filename;                 /* filename we are looking at */
                    250: 
                    251:        filename = direntry->d_name;
                    252:        while (*filename)
                    253:                numdot += (*(filename++) == '.');
                    254:        return(numdot == 3);
                    255: }
                    256: 
                    257: /*
                    258:  * Is a command line argument a username? As noted above we will assume 
                    259:  * that an argument that is all digits means that it's a job number, not
                    260:  * a user's name. We choose to determine whether an argument is a user name
                    261:  * in this manner because then it's ok for someone to have digits in their 
                    262:  * user name.
                    263:  */
                    264: isusername(string)
                    265: char *string;
                    266: {
                    267:        char *ptr;                      /* pointer used for scanning string */
                    268: 
                    269:        ptr = string;
                    270:        while (isdigit(*ptr))
                    271:                ++ptr;
                    272:        return((*ptr == '\0') ? 0 : 1);
                    273: }
                    274: 
                    275: /*
                    276:  * Remove an entry from the queue. The access of the file is checked for
                    277:  * write permission (since all jobs are mode 644). If access is granted,
                    278:  * unlink the file. If the fflag (suppress announcements) is not set,
                    279:  * print the job number that we are removing and the result of the access
                    280:  * check (either "permission denied" or "removed"). If we are running 
                    281:  * interactively (iflag), prompt the user before we unlink the file. If 
                    282:  * the super-user is removing jobs, inform him/her who owns each file before 
                    283:  * it is removed.  Return TRUE if file removed, else FALSE.
                    284:  */
                    285: int
                    286: removentry(filename,inode,user)
                    287: char *filename;
                    288: int inode;
                    289: int user;
                    290: {
                    291: 
                    292:        if (!fflag)
                    293:                printf("%6d: ",inode);
                    294: 
                    295:        if (!isowner(getname(user),filename) && user != SUPERUSER) {
                    296: 
                    297:                if (!fflag) {
                    298:                        printf("permission denied\n");
                    299:                }
                    300:                return (0);
                    301: 
                    302:        } else {
                    303:                if (iflag) {
                    304:                        if (user == SUPERUSER) {
                    305:                                printf("\t(owned by ");
                    306:                                powner(filename);
                    307:                                printf(") ");
                    308:                        }
                    309:                        printf("remove it? ");
                    310:                        if (!yes())
                    311:                                return (0);
                    312:                }
                    313:                if (unlink(filename) < 0) {
                    314:                        if (!fflag) {
                    315:                                fputs("could not remove\n", stdout);
                    316:                                perror(filename);
                    317:                        }
                    318:                        return (0);
                    319:                }
                    320:                if (!fflag && !iflag)
                    321:                        printf("removed\n");
                    322:                return (1);
                    323:        }
                    324: }
                    325: 
                    326: /*
                    327:  * See if "name" owns "job".
                    328:  */
                    329: isowner(name,job)
                    330: char *name;
                    331: char *job;
                    332: {
                    333:        char buf[128];                  /* buffer for 1st line of spoolfile 
                    334:                                           header */
                    335:        FILE *infile;                   /* I/O stream to spoolfile */
                    336: 
                    337:        if ((infile = fopen(job,"r")) == NULL) {
                    338:                fprintf(stderr,"Couldn't open spoolfile ");
                    339:                perror(job);
                    340:                return(0);
                    341:        }
                    342: 
                    343:        if (fscanf(infile,"# owner: %127s%*[^\n]\n",buf) != 1) {
                    344:                fclose(infile);
                    345:                return(0);
                    346:        }
                    347: 
                    348:        fclose(infile);
                    349:        return((strcmp(name,buf) == 0) ? 1 : 0);
                    350: }
                    351: 
                    352: /*
                    353:  * Print the owner of the job. This is stored on the first line of the
                    354:  * spoolfile. If we run into trouble getting the name, we'll just print "???".
                    355:  */
                    356: powner(file)
                    357: char *file;
                    358: {
                    359:        char owner[128];                        /* the owner */
                    360:        FILE *infile;                           /* I/O stream to spoolfile */
                    361: 
                    362:        /*
                    363:         * Open the job file and grab the first line.
                    364:         */
                    365: 
                    366:        if ((infile = fopen(file,"r")) == NULL) {
                    367:                printf("%s","???");
                    368:                perror(file);
                    369:                return;
                    370:        }
                    371: 
                    372:        if (fscanf(infile,"# owner: %127s%*[^\n]\n",owner) != 1) {
                    373:                printf("%s","???");
                    374:                fclose(infile);
                    375:                return;
                    376:        }
                    377: 
                    378:        fclose(infile);
                    379:        printf("%s",owner);
                    380: 
                    381: }
                    382: 
                    383: /*
                    384:  * Get answer to interactive prompts, eating all characters beyond the first
                    385:  * one. If a 'y' is typed, return 1.
                    386:  */
                    387: yes()
                    388: {
                    389:        char ch;                                /* dummy variable */
                    390:        char ch1;                               /* dummy variable */
                    391: 
                    392:        ch = ch1 = getchar();
                    393:        while (ch1 != '\n' && ch1 != EOF)
                    394:                ch1 = getchar();
                    395:        if (isupper(ch))
                    396:                ch = tolower(ch);
                    397:        return(ch == 'y');
                    398: }
                    399: 
                    400: /*
                    401:  * Get the uid of a person using his/her login name. Return -1 if no
                    402:  * such account name exists.
                    403:  */
                    404: getid(name)
                    405: char *name;
                    406: {
                    407: 
                    408:        struct passwd *pwdinfo;         /* password info structure */
                    409:        
                    410:        if ((pwdinfo = getpwnam(name)) == 0)
                    411:                return(-1);
                    412: 
                    413:        return(pwdinfo->pw_uid);
                    414: }
                    415: 
                    416: /*
                    417:  * Get the full login name of a person using his/her user id.
                    418:  */
                    419: char *
                    420: getname(uid)
                    421: int uid;
                    422: {
                    423:        struct passwd *pwdinfo;                 /* password info structure */
                    424:        
                    425: 
                    426:        if ((pwdinfo = getpwuid(uid)) == 0)
                    427:                return("???");
                    428:        return(pwdinfo->pw_name);
                    429: }
                    430: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.