Ignore:
Timestamp:
Nov 4, 2007, 3:16:40 AM (13 years ago)
Author:
Bruno Cornec
Message:

Update to busybox 1.7.2

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.5/mindi-busybox/miscutils/crontab.c

    r821 r1765  
    1111 */
    1212
    13 #include "busybox.h"
    14 #include <stdio.h>
    15 #include <stdlib.h>
    16 #include <stdarg.h>
    17 #include <string.h>
    18 #include <errno.h>
    19 #include <time.h>
    20 #include <dirent.h>
    21 #include <fcntl.h>
    22 #include <unistd.h>
    23 #include <syslog.h>
    24 #include <signal.h>
    25 #include <getopt.h>
    26 #include <sys/ioctl.h>
    27 #include <sys/wait.h>
    28 #include <sys/stat.h>
    29 #include <sys/resource.h>
     13#include "libbb.h"
    3014
    3115#ifndef CRONTABS
     
    3923#endif
    4024#ifndef PATH_VI
    41 #define PATH_VI         "/bin/vi"   /* location of vi       */
     25#define PATH_VI         "/bin/vi"   /* location of vi */
    4226#endif
    4327
    44 static const char  *CDir = CRONTABS;
     28static const char *CDir = CRONTABS;
    4529
    4630static void EditFile(const char *user, const char *file);
    4731static int GetReplaceStream(const char *user, const char *file);
    48 static int  ChangeUser(const char *user, short dochdir);
    49 
    50 int
    51 crontab_main(int ac, char **av)
     32static int ChangeUser(const char *user, short dochdir);
     33
     34int crontab_main(int ac, char **av);
     35int crontab_main(int ac, char **av)
    5236{
    53     enum { NONE, EDIT, LIST, REPLACE, DELETE } option = NONE;
    54     const struct passwd *pas;
    55     const char *repFile = NULL;
    56     int repFd = 0;
    57     int i;
    58     char caller[256];           /* user that ran program */
    59     int   UserId;
    60 
    61     UserId = getuid();
    62     if ((pas = getpwuid(UserId)) == NULL)
    63     bb_perror_msg_and_die("getpwuid");
    64 
    65     safe_strncpy(caller, pas->pw_name, sizeof(caller));
    66 
    67     i = 1;
    68     if (ac > 1) {
    69     if (av[1][0] == '-' && av[1][1] == 0) {
    70         option = REPLACE;
    71         ++i;
    72     } else if (av[1][0] != '-') {
    73         option = REPLACE;
    74         ++i;
    75         repFile = av[1];
    76     }
    77     }
    78 
    79     for (; i < ac; ++i) {
    80     char *ptr = av[i];
    81 
    82     if (*ptr != '-')
    83         break;
    84     ptr += 2;
    85 
    86     switch(ptr[-1]) {
    87     case 'l':
    88         if (ptr[-1] == 'l')
    89         option = LIST;
    90         /* fall through */
    91     case 'e':
    92         if (ptr[-1] == 'e')
    93         option = EDIT;
    94         /* fall through */
    95     case 'd':
    96         if (ptr[-1] == 'd')
    97         option = DELETE;
    98         /* fall through */
    99     case 'u':
    100         if (i + 1 < ac && av[i+1][0] != '-') {
    101         ++i;
    102         if (getuid() == geteuid()) {
    103             pas = getpwnam(av[i]);
    104             if (pas) {
    105             UserId = pas->pw_uid;
    106             } else {
    107             bb_error_msg_and_die("user %s unknown", av[i]);
    108             }
    109         } else {
    110             bb_error_msg_and_die("only the superuser may specify a user");
    111         }
    112         }
    113         break;
    114     case 'c':
    115         if (getuid() == geteuid()) {
    116         CDir = (*ptr) ? ptr : av[++i];
    117         } else {
    118         bb_error_msg_and_die("-c option: superuser only");
    119         }
    120         break;
     37    enum { NONE, EDIT, LIST, REPLACE, DELETE } option = NONE;
     38    const struct passwd *pas;
     39    const char *repFile = NULL;
     40    int repFd = 0;
     41    int i;
     42    char caller[256];           /* user that ran program */
     43    char buf[1024];
     44    int UserId;
     45
     46    UserId = getuid();
     47    pas = getpwuid(UserId);
     48    if (pas == NULL)
     49        bb_perror_msg_and_die("getpwuid");
     50
     51    safe_strncpy(caller, pas->pw_name, sizeof(caller));
     52
     53    i = 1;
     54    if (ac > 1) {
     55        if (LONE_DASH(av[1])) {
     56            option = REPLACE;
     57            ++i;
     58        } else if (av[1][0] != '-') {
     59            option = REPLACE;
     60            ++i;
     61            repFile = av[1];
     62        }
     63    }
     64
     65    for (; i < ac; ++i) {
     66        char *ptr = av[i];
     67
     68        if (*ptr != '-')
     69            break;
     70        ptr += 2;
     71
     72        switch (ptr[-1]) {
     73        case 'l':
     74            if (ptr[-1] == 'l')
     75                option = LIST;
     76            /* fall through */
     77        case 'e':
     78            if (ptr[-1] == 'e')
     79                option = EDIT;
     80            /* fall through */
     81        case 'd':
     82            if (ptr[-1] == 'd')
     83                option = DELETE;
     84            /* fall through */
     85        case 'u':
     86            if (i + 1 < ac && av[i+1][0] != '-') {
     87                ++i;
     88                if (getuid() == geteuid()) {
     89                    pas = getpwnam(av[i]);
     90                    if (pas) {
     91                        UserId = pas->pw_uid;
     92                    } else {
     93                        bb_error_msg_and_die("user %s unknown", av[i]);
     94                    }
     95                } else {
     96                    bb_error_msg_and_die("only the superuser may specify a user");
     97                }
     98            }
     99            break;
     100        case 'c':
     101            if (getuid() == geteuid()) {
     102                CDir = (*ptr) ? ptr : av[++i];
     103            } else {
     104                bb_error_msg_and_die("-c option: superuser only");
     105            }
     106            break;
     107        default:
     108            i = ac;
     109            break;
     110        }
     111    }
     112    if (i != ac || option == NONE)
     113        bb_show_usage();
     114
     115    /*
     116     * Get password entry
     117     */
     118
     119    pas = getpwuid(UserId);
     120    if (pas == NULL)
     121        bb_perror_msg_and_die("getpwuid");
     122
     123    /*
     124     * If there is a replacement file, obtain a secure descriptor to it.
     125     */
     126
     127    if (repFile) {
     128        repFd = GetReplaceStream(caller, repFile);
     129        if (repFd < 0)
     130            bb_error_msg_and_die("cannot read replacement file");
     131    }
     132
     133    /*
     134     * Change directory to our crontab directory
     135     */
     136
     137    xchdir(CDir);
     138
     139    /*
     140     * Handle options as appropriate
     141     */
     142
     143    switch (option) {
     144    case LIST:
     145        {
     146            FILE *fi;
     147
     148            fi = fopen(pas->pw_name, "r");
     149            if (fi) {
     150                while (fgets(buf, sizeof(buf), fi) != NULL)
     151                    fputs(buf, stdout);
     152                fclose(fi);
     153            } else {
     154                bb_error_msg("no crontab for %s", pas->pw_name);
     155            }
     156        }
     157        break;
     158    case EDIT:
     159        {
     160/* FIXME: messy code here! we have file copying helpers for this! */
     161            FILE *fi;
     162            int fd;
     163            int n;
     164            char tmp[128];
     165
     166            snprintf(tmp, sizeof(tmp), TMPDIR "/crontab.%d", getpid());
     167            fd = xopen3(tmp, O_RDWR|O_CREAT|O_TRUNC|O_EXCL, 0600);
     168/* race, use fchown */
     169            chown(tmp, getuid(), getgid());
     170            fi = fopen(pas->pw_name, "r");
     171            if (fi) {
     172                while ((n = fread(buf, 1, sizeof(buf), fi)) > 0)
     173                    full_write(fd, buf, n);
     174            }
     175            EditFile(caller, tmp);
     176            remove(tmp);
     177            lseek(fd, 0L, SEEK_SET);
     178            repFd = fd;
     179        }
     180        option = REPLACE;
     181        /* fall through */
     182    case REPLACE:
     183        {
     184/* same here */
     185            char path[1024];
     186            int fd;
     187            int n;
     188
     189            snprintf(path, sizeof(path), "%s.new", pas->pw_name);
     190            fd = open(path, O_CREAT|O_TRUNC|O_APPEND|O_WRONLY, 0600);
     191            if (fd >= 0) {
     192                while ((n = read(repFd, buf, sizeof(buf))) > 0) {
     193                    full_write(fd, buf, n);
     194                }
     195                close(fd);
     196                rename(path, pas->pw_name);
     197            } else {
     198                bb_error_msg("cannot create %s/%s", CDir, path);
     199            }
     200            close(repFd);
     201        }
     202        break;
     203    case DELETE:
     204        remove(pas->pw_name);
     205        break;
     206    case NONE:
    121207    default:
    122         i = ac;
    123         break;
    124     }
    125     }
    126     if (i != ac || option == NONE)
    127     bb_show_usage();
    128 
    129     /*
    130      * Get password entry
    131      */
    132 
    133     if ((pas = getpwuid(UserId)) == NULL)
    134     bb_perror_msg_and_die("getpwuid");
    135 
    136     /*
    137      * If there is a replacement file, obtain a secure descriptor to it.
    138      */
    139 
    140     if (repFile) {
    141     repFd = GetReplaceStream(caller, repFile);
    142     if (repFd < 0)
    143         bb_error_msg_and_die("unable to read replacement file");
    144     }
    145 
    146     /*
    147      * Change directory to our crontab directory
    148      */
    149 
    150     bb_xchdir(CDir);
    151 
    152     /*
    153      * Handle options as appropriate
    154      */
    155 
    156     switch(option) {
    157     case LIST:
    158     {
    159         FILE *fi;
    160         char buf[1024];
    161 
    162         if ((fi = fopen(pas->pw_name, "r"))) {
    163         while (fgets(buf, sizeof(buf), fi) != NULL)
    164             fputs(buf, stdout);
    165         fclose(fi);
    166         } else {
    167         bb_error_msg("no crontab for %s", pas->pw_name);
    168         }
    169     }
    170     break;
    171     case EDIT:
    172     {
    173         FILE *fi;
    174         int fd;
    175         int n;
    176         char tmp[128];
    177         char buf[1024];
    178 
    179         snprintf(tmp, sizeof(tmp), TMPDIR "/crontab.%d", getpid());
    180         fd = bb_xopen3(tmp, O_RDWR|O_CREAT|O_TRUNC|O_EXCL, 0600);
    181         chown(tmp, getuid(), getgid());
    182         if ((fi = fopen(pas->pw_name, "r"))) {
    183         while ((n = fread(buf, 1, sizeof(buf), fi)) > 0)
    184             write(fd, buf, n);
    185         }
    186         EditFile(caller, tmp);
    187         remove(tmp);
    188         lseek(fd, 0L, 0);
    189         repFd = fd;
    190     }
    191     option = REPLACE;
    192     /* fall through */
    193     case REPLACE:
    194     {
    195         char buf[1024];
    196         char path[1024];
    197         int fd;
    198         int n;
    199 
    200         snprintf(path, sizeof(path), "%s.new", pas->pw_name);
    201         if ((fd = open(path, O_CREAT|O_TRUNC|O_APPEND|O_WRONLY, 0600)) >= 0) {
    202         while ((n = read(repFd, buf, sizeof(buf))) > 0) {
    203             write(fd, buf, n);
    204         }
    205         close(fd);
    206         rename(path, pas->pw_name);
    207         } else {
    208         bb_error_msg("unable to create %s/%s", CDir, path);
    209         }
    210         close(repFd);
    211     }
    212     break;
    213     case DELETE:
    214     remove(pas->pw_name);
    215     break;
    216     case NONE:
    217     default:
    218     break;
    219     }
    220 
    221     /*
    222      *  Bump notification file.  Handle window where crond picks file up
    223      *  before we can write our entry out.
    224      */
    225 
    226     if (option == REPLACE || option == DELETE) {
    227     FILE *fo;
    228     struct stat st;
    229 
    230     while ((fo = fopen(CRONUPDATE, "a"))) {
    231         fprintf(fo, "%s\n", pas->pw_name);
    232         fflush(fo);
    233         if (fstat(fileno(fo), &st) != 0 || st.st_nlink != 0) {
    234         fclose(fo);
    235208        break;
    236         }
    237         fclose(fo);
    238         /* loop */
    239     }
    240     if (fo == NULL) {
    241         bb_error_msg("unable to append to %s/%s", CDir, CRONUPDATE);
    242     }
    243     }
    244     return 0;
     209    }
     210
     211    /*
     212     *  Bump notification file.  Handle window where crond picks file up
     213     *  before we can write our entry out.
     214     */
     215
     216    if (option == REPLACE || option == DELETE) {
     217        FILE *fo;
     218        struct stat st;
     219
     220        while ((fo = fopen(CRONUPDATE, "a"))) {
     221            fprintf(fo, "%s\n", pas->pw_name);
     222            fflush(fo);
     223            if (fstat(fileno(fo), &st) != 0 || st.st_nlink != 0) {
     224                fclose(fo);
     225                break;
     226            }
     227            fclose(fo);
     228            /* loop */
     229        }
     230        if (fo == NULL) {
     231            bb_error_msg("cannot append to %s/%s", CDir, CRONUPDATE);
     232        }
     233    }
     234    return 0;
    245235}
    246236
    247 static int
    248 GetReplaceStream(const char *user, const char *file)
     237static int GetReplaceStream(const char *user, const char *file)
    249238{
    250     int filedes[2];
    251     int pid;
    252     int fd;
    253     int n;
    254     char buf[1024];
    255 
    256     if (pipe(filedes) < 0) {
    257     perror("pipe");
    258     return(-1);
    259     }
    260     if ((pid = fork()) < 0) {
    261     perror("fork");
    262     return(-1);
    263     }
    264     if (pid > 0) {
    265     /*
    266      * PARENT
    267      */
    268 
    269     close(filedes[1]);
    270     if (read(filedes[0], buf, 1) != 1) {
    271         close(filedes[0]);
    272         filedes[0] = -1;
    273     }
    274     return(filedes[0]);
    275     }
    276 
    277     /*
    278      * CHILD
    279      */
    280 
    281     close(filedes[0]);
    282 
    283     if (ChangeUser(user, 0) < 0)
     239    int filedes[2];
     240    int pid;
     241    int fd;
     242    int n;
     243    char buf[1024];
     244
     245    if (pipe(filedes) < 0) {
     246        perror("pipe");
     247        return -1;
     248    }
     249    pid = fork();
     250    if (pid < 0) {
     251        perror("fork");
     252        return -1;
     253    }
     254    if (pid > 0) {
     255        /*
     256         * PARENT
     257         */
     258
     259        close(filedes[1]);
     260        if (read(filedes[0], buf, 1) != 1) {
     261            close(filedes[0]);
     262            filedes[0] = -1;
     263        }
     264        return filedes[0];
     265    }
     266
     267    /*
     268     * CHILD
     269     */
     270
     271    close(filedes[0]);
     272
     273    if (ChangeUser(user, 0) < 0)
     274        exit(0);
     275
     276    xfunc_error_retval = 0;
     277    fd = xopen(file, O_RDONLY);
     278    buf[0] = 0;
     279    write(filedes[1], buf, 1);
     280    while ((n = read(fd, buf, sizeof(buf))) > 0) {
     281        write(filedes[1], buf, n);
     282    }
    284283    exit(0);
    285 
    286     bb_default_error_retval = 0;
    287     fd = bb_xopen3(file, O_RDONLY, 0);
    288     buf[0] = 0;
    289     write(filedes[1], buf, 1);
    290     while ((n = read(fd, buf, sizeof(buf))) > 0) {
    291     write(filedes[1], buf, n);
    292     }
    293     exit(0);
    294284}
    295285
    296 static void
    297 EditFile(const char *user, const char *file)
     286static void EditFile(const char *user, const char *file)
    298287{
    299     int pid;
    300 
    301     if ((pid = fork()) == 0) {
    302     /*
    303      * CHILD - change user and run editor
    304      */
    305     char *ptr;
    306     char visual[1024];
    307 
    308     if (ChangeUser(user, 1) < 0)
    309         exit(0);
    310     if ((ptr = getenv("VISUAL")) == NULL || strlen(ptr) > 256)
    311         ptr = PATH_VI;
    312 
    313     snprintf(visual, sizeof(visual), "%s %s", ptr, file);
    314     execl(DEFAULT_SHELL, DEFAULT_SHELL, "-c", visual, NULL);
    315     perror("exec");
    316     exit(0);
    317     }
    318     if (pid < 0) {
    319     /*
    320      * PARENT - failure
    321      */
    322     bb_perror_msg_and_die("fork");
    323     }
    324     wait4(pid, NULL, 0, NULL);
     288    int pid = fork();
     289
     290    if (pid == 0) {
     291        /*
     292         * CHILD - change user and run editor
     293         */
     294        const char *ptr;
     295
     296        if (ChangeUser(user, 1) < 0)
     297            exit(0);
     298        ptr = getenv("VISUAL");
     299        if (ptr == NULL)
     300            ptr = getenv("EDITOR");
     301        if (ptr == NULL)
     302            ptr = PATH_VI;
     303
     304        ptr = xasprintf("%s %s", ptr, file);
     305        execl(DEFAULT_SHELL, DEFAULT_SHELL, "-c", ptr, NULL);
     306        bb_perror_msg_and_die("exec");
     307    }
     308    if (pid < 0) {
     309        /*
     310         * PARENT - failure
     311         */
     312        bb_perror_msg_and_die("fork");
     313    }
     314    wait4(pid, NULL, 0, NULL);
    325315}
    326316
    327 static int
    328 ChangeUser(const char *user, short dochdir)
     317static int ChangeUser(const char *user, short dochdir)
    329318{
    330     struct passwd *pas;
    331 
    332     /*
    333     * Obtain password entry and change privileges
    334     */
    335 
    336     if ((pas = getpwnam(user)) == NULL) {
    337     bb_perror_msg_and_die("failed to get uid for %s", user);
    338     return(-1);
    339     }
    340     setenv("USER", pas->pw_name, 1);
    341     setenv("HOME", pas->pw_dir, 1);
    342     setenv("SHELL", DEFAULT_SHELL, 1);
    343 
    344     /*
    345     * Change running state to the user in question
    346     */
    347     change_identity(pas);
    348 
    349     if (dochdir) {
    350     if (chdir(pas->pw_dir) < 0) {
    351         bb_perror_msg("chdir failed: %s %s", user, pas->pw_dir);
    352         bb_xchdir(TMPDIR);
    353     }
    354     }
    355     return(pas->pw_uid);
     319    struct passwd *pas;
     320
     321    /*
     322    * Obtain password entry and change privileges
     323    */
     324
     325    pas = getpwnam(user);
     326    if (pas == NULL) {
     327        bb_perror_msg_and_die("failed to get uid for %s", user);
     328    }
     329    setenv("USER", pas->pw_name, 1);
     330    setenv("HOME", pas->pw_dir, 1);
     331    setenv("SHELL", DEFAULT_SHELL, 1);
     332
     333    /*
     334    * Change running state to the user in question
     335    */
     336    change_identity(pas);
     337
     338    if (dochdir) {
     339        if (chdir(pas->pw_dir) < 0) {
     340            bb_perror_msg("chdir(%s) by %s failed", pas->pw_dir, user);
     341            xchdir(TMPDIR);
     342        }
     343    }
     344    return pas->pw_uid;
    356345}
Note: See TracChangeset for help on using the changeset viewer.