Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/procps/sysctl.c


Ignore:
Timestamp:
Feb 25, 2011, 9:26:54 PM (13 years ago)
Author:
Bruno Cornec
Message:
  • Update mindi-busybox to 1.18.3 to avoid problems with the tar command which is now failing on recent versions with busybox 1.7.3
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.9/mindi-busybox/procps/sysctl.c

    r1765 r2725  
    55 * Copyright 1999 George Staikos
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 *
    99 * Changelog:
    10  *  v1.01:
    11  *      - added -p <preload> to preload values from a file
    12  *  v1.01.1
    13  *      - busybox applet aware by <solar@gentoo.org>
    14  *
     10 * v1.01   - added -p <preload> to preload values from a file
     11 * v1.01.1 - busybox applet aware by <solar@gentoo.org>
    1512 */
    1613
    1714#include "libbb.h"
    1815
    19 /*
    20  *    Function Prototypes
    21  */
    22 static int sysctl_read_setting(const char *setting, int output);
    23 static int sysctl_write_setting(const char *setting, int output);
    24 static int sysctl_preload_file(const char *filename, int output);
    25 static int sysctl_display_all(const char *path, int output, int show_table);
    26 
    27 /*
    28  *    Globals...
    29  */
    30 static const char PROC_PATH[] ALIGN1 = "/proc/sys/";
    31 static const char DEFAULT_PRELOAD[] ALIGN1 = "/etc/sysctl.conf";
    32 
    33 /* error messages */
    34 static const char ERR_UNKNOWN_PARAMETER[] ALIGN1 =
    35     "error: Unknown parameter '%s'\n";
    36 static const char ERR_MALFORMED_SETTING[] ALIGN1 =
    37     "error: Malformed setting '%s'\n";
    38 static const char ERR_NO_EQUALS[] ALIGN1 =
    39     "error: '%s' must be of the form name=value\n";
    40 static const char ERR_INVALID_KEY[] ALIGN1 =
    41     "error: '%s' is an unknown key\n";
    42 static const char ERR_UNKNOWN_WRITING[] ALIGN1 =
    43     "error: unknown error %d setting key '%s'\n";
    44 static const char ERR_UNKNOWN_READING[] ALIGN1 =
    45     "error: unknown error %d reading key '%s'\n";
    46 static const char ERR_PERMISSION_DENIED[] ALIGN1 =
    47     "error: permission denied on key '%s'\n";
    48 static const char ERR_PRELOAD_FILE[] ALIGN1 =
    49     "error: cannot open preload file '%s'\n";
    50 static const char WARN_BAD_LINE[] ALIGN1 =
    51     "warning: %s(%d): invalid syntax, continuing...\n";
    52 
    53 
    54 static void dwrite_str(int fd, const char *buf)
    55 {
    56     write(fd, buf, strlen(buf));
    57 }
    58 
    59 /*
    60  *    sysctl_main()...
    61  */
    62 int sysctl_main(int argc, char **argv);
    63 int sysctl_main(int argc, char **argv)
    64 {
    65     int retval = 0;
    66     int output = 1;
    67     int write_mode = 0;
    68     int switches_allowed = 1;
    69 
    70     if (argc < 2)
    71         bb_show_usage();
    72 
    73     argv++;
    74 
    75     for (; argv && *argv && **argv; argv++) {
    76         if (switches_allowed && **argv == '-') {    /* we have a switch */
    77             switch ((*argv)[1]) {
    78             case 'n':
    79                 output = 0;
    80                 break;
    81             case 'w':
    82                 write_mode = 1;
    83                 switches_allowed = 0;
    84                 break;
    85             case 'p':
    86                 argv++;
    87                 return
    88                     sysctl_preload_file(((argv && *argv
    89                                           && **argv) ? *argv :
    90                                          DEFAULT_PRELOAD), output);
    91             case 'a':
    92             case 'A':
    93                 switches_allowed = 0;
    94                 return sysctl_display_all(PROC_PATH, output,
    95                                           ((*argv)[1] == 'a') ? 0 : 1);
    96             case 'h':
    97             case '?':
    98                 bb_show_usage();
    99             default:
    100                 bb_error_msg(ERR_UNKNOWN_PARAMETER, *argv);
    101                 bb_show_usage();
     16enum {
     17    FLAG_SHOW_KEYS       = 1 << 0,
     18    FLAG_SHOW_KEY_ERRORS = 1 << 1,
     19    FLAG_TABLE_FORMAT    = 1 << 2, /* not implemented */
     20    FLAG_SHOW_ALL        = 1 << 3,
     21    FLAG_PRELOAD_FILE    = 1 << 4,
     22    FLAG_WRITE           = 1 << 5,
     23};
     24#define OPTION_STR "neAapw"
     25
     26static void sysctl_dots_to_slashes(char *name)
     27{
     28    char *cptr, *last_good, *end;
     29
     30    /* Convert minimum number of '.' to '/' so that
     31     * we end up with existing file's name.
     32     *
     33     * Example from bug 3894:
     34     * net.ipv4.conf.eth0.100.mc_forwarding ->
     35     * net/ipv4/conf/eth0.100/mc_forwarding
     36     * NB: net/ipv4/conf/eth0/mc_forwarding *also exists*,
     37     * therefore we must start from the end, and if
     38     * we replaced even one . -> /, start over again,
     39     * but never replace dots before the position
     40     * where last replacement occurred.
     41     *
     42     * Another bug we later had is that
     43     * net.ipv4.conf.eth0.100
     44     * (without .mc_forwarding) was mishandled.
     45     *
     46     * To set up testing: modprobe 8021q; vconfig add eth0 100
     47     */
     48    end = name + strlen(name);
     49    last_good = name - 1;
     50    *end = '.'; /* trick the loop into trying full name too */
     51
     52 again:
     53    cptr = end;
     54    while (cptr > last_good) {
     55        if (*cptr == '.') {
     56            *cptr = '\0';
     57            //bb_error_msg("trying:'%s'", name);
     58            if (access(name, F_OK) == 0) {
     59                *cptr = '/';
     60                //bb_error_msg("replaced:'%s'", name);
     61                last_good = cptr;
     62                goto again;
    10263            }
    103         } else {
    104             switches_allowed = 0;
    105             if (write_mode)
    106                 retval = sysctl_write_setting(*argv, output);
    107             else
    108                 sysctl_read_setting(*argv, output);
    109         }
    110     }
    111     return retval;
    112 }                       /* end sysctl_main() */
    113 
    114 
    115 
    116 /*
    117  *     sysctl_preload_file
    118  *  preload the sysctl's from a conf file
    119  *           - we parse the file and then reform it (strip out whitespace)
    120  */
    121 #define PRELOAD_BUF 256
    122 
    123 int sysctl_preload_file(const char *filename, int output)
    124 {
    125     int lineno = 0;
    126     char oneline[PRELOAD_BUF];
    127     char buffer[PRELOAD_BUF];
    128     char *name, *value, *ptr;
    129     FILE *fp = NULL;
    130 
    131     if (!filename || ((fp = fopen(filename, "r")) == NULL)) {
    132         bb_error_msg_and_die(ERR_PRELOAD_FILE, filename);
    133     }
    134 
    135     while (fgets(oneline, sizeof(oneline) - 1, fp)) {
    136         oneline[sizeof(oneline) - 1] = '\0';
    137         lineno++;
    138         trim(oneline);
    139         ptr = (char *) oneline;
    140 
    141         if (*ptr == '#' || *ptr == ';')
    142             continue;
    143 
    144         if (strlen(ptr) < 2)
    145             continue;
    146 
    147         name = strtok(ptr, "=");
    148         if (!name || !*name) {
    149             bb_error_msg(WARN_BAD_LINE, filename, lineno);
    150             continue;
    151         }
    152 
    153         trim(name);
    154 
    155         value = strtok(NULL, "\n\r");
    156         if (!value || !*value) {
    157             bb_error_msg(WARN_BAD_LINE, filename, lineno);
    158             continue;
    159         }
    160 
    161         while ((*value == ' ' || *value == '\t') && *value != 0)
    162             value++;
    163         /* safe because sizeof(oneline) == sizeof(buffer) */
    164         sprintf(buffer, "%s=%s", name, value);
    165         sysctl_write_setting(buffer, output);
    166     }
    167     fclose(fp);
    168     return 0;
    169 }                       /* end sysctl_preload_file() */
    170 
    171 
    172 /*
    173  *     Write a single sysctl setting
    174  */
    175 int sysctl_write_setting(const char *setting, int output)
    176 {
    177     int retval = 0;
    178     const char *name = setting;
    179     const char *value;
    180     const char *equals;
    181     char *tmpname, *outname, *cptr;
    182     int fd = -1;
    183 
    184     if (!name)          /* probably dont' want to display this  err */
    185         return 0;
    186 
    187     if (!(equals = strchr(setting, '='))) {
    188         bb_error_msg(ERR_NO_EQUALS, setting);
    189         return -1;
    190     }
    191 
    192     value = equals + sizeof(char);  /* point to the value in name=value */
    193 
    194     if (!*name || !*value || name == equals) {
    195         bb_error_msg(ERR_MALFORMED_SETTING, setting);
    196         return -2;
    197     }
    198 
    199     tmpname = xasprintf("%s%.*s", PROC_PATH, (int)(equals - name), name);
    200     outname = xstrdup(tmpname + strlen(PROC_PATH));
    201 
    202     while ((cptr = strchr(tmpname, '.')) != NULL)
    203         *cptr = '/';
    204 
    205     while ((cptr = strchr(outname, '/')) != NULL)
    206         *cptr = '.';
    207 
    208     fd = open(tmpname, O_WRONLY | O_CREAT | O_TRUNC, 0666);
     64            *cptr = '.';
     65        }
     66        cptr--;
     67    }
     68    *end = '\0';
     69}
     70
     71static int sysctl_act_on_setting(char *setting)
     72{
     73    int fd, retval = EXIT_SUCCESS;
     74    char *cptr, *outname;
     75    char *value = value; /* for compiler */
     76
     77    outname = xstrdup(setting);
     78
     79    cptr = outname;
     80    while (*cptr) {
     81        if (*cptr == '/')
     82            *cptr = '.';
     83        cptr++;
     84    }
     85
     86    if (option_mask32 & FLAG_WRITE) {
     87        cptr = strchr(setting, '=');
     88        if (cptr == NULL) {
     89            bb_error_msg("error: '%s' must be of the form name=value",
     90                outname);
     91            retval = EXIT_FAILURE;
     92            goto end;
     93        }
     94        value = cptr + 1;  /* point to the value in name=value */
     95        if (setting == cptr || !*value) {
     96            bb_error_msg("error: malformed setting '%s'", outname);
     97            retval = EXIT_FAILURE;
     98            goto end;
     99        }
     100        *cptr = '\0';
     101        outname[cptr - setting] = '\0';
     102        /* procps 3.2.7 actually uses these flags */
     103        fd = open(setting, O_WRONLY|O_CREAT|O_TRUNC, 0666);
     104    } else {
     105        fd = open(setting, O_RDONLY);
     106    }
     107
    209108    if (fd < 0) {
    210109        switch (errno) {
    211110        case ENOENT:
    212             bb_error_msg(ERR_INVALID_KEY, outname);
    213             break;
    214         case EACCES:
    215             bb_perror_msg(ERR_PERMISSION_DENIED, outname);
     111            if (option_mask32 & FLAG_SHOW_KEY_ERRORS)
     112                bb_error_msg("error: '%s' is an unknown key", outname);
    216113            break;
    217114        default:
    218             bb_error_msg(ERR_UNKNOWN_WRITING, errno, outname);
     115            bb_perror_msg("error %sing key '%s'",
     116                    option_mask32 & FLAG_WRITE ?
     117                        "sett" : "read",
     118                    outname);
    219119            break;
    220120        }
    221         retval = -1;
     121        retval = EXIT_FAILURE;
     122        goto end;
     123    }
     124
     125    if (option_mask32 & FLAG_WRITE) {
     126//TODO: procps 3.2.7 writes "value\n", note trailing "\n"
     127        xwrite_str(fd, value);
     128        close(fd);
     129        if (option_mask32 & FLAG_SHOW_KEYS)
     130            printf("%s = ", outname);
     131        puts(value);
    222132    } else {
    223         dwrite_str(fd, value);
     133        char c;
     134
     135        value = cptr = xmalloc_read(fd, NULL);
    224136        close(fd);
    225         if (output) {
    226             dwrite_str(STDOUT_FILENO, outname);
    227             dwrite_str(STDOUT_FILENO, " = ");
    228         }
    229         dwrite_str(STDOUT_FILENO, value);
    230         dwrite_str(STDOUT_FILENO, "\n");
    231     }
    232 
    233     /* cleanup */
    234     free(tmpname);
     137        if (value == NULL) {
     138            bb_perror_msg("error reading key '%s'", outname);
     139            goto end;
     140        }
     141
     142        /* dev.cdrom.info and sunrpc.transports, for example,
     143         * are multi-line. Try "sysctl sunrpc.transports"
     144         */
     145        while ((c = *cptr) != '\0') {
     146            if (option_mask32 & FLAG_SHOW_KEYS)
     147                printf("%s = ", outname);
     148            while (1) {
     149                fputc(c, stdout);
     150                cptr++;
     151                if (c == '\n')
     152                    break;
     153                c = *cptr;
     154                if (c == '\0')
     155                    break;
     156            }
     157        }
     158        free(value);
     159    }
     160 end:
    235161    free(outname);
    236162    return retval;
    237 }                       /* end sysctl_write_setting() */
    238 
    239 
    240 /*
    241  *     Read a sysctl setting
    242  *
     163}
     164
     165static int sysctl_act_recursive(const char *path)
     166{
     167    DIR *dirp;
     168    struct stat buf;
     169    struct dirent *entry;
     170    char *next;
     171    int retval = 0;
     172
     173    stat(path, &buf);
     174    if (S_ISDIR(buf.st_mode) && !(option_mask32 & FLAG_WRITE)) {
     175        dirp = opendir(path);
     176        if (dirp == NULL)
     177            return -1;
     178        while ((entry = readdir(dirp)) != NULL) {
     179            next = concat_subpath_file(path, entry->d_name);
     180            if (next == NULL)
     181                continue; /* d_name is "." or ".." */
     182            /* if path was ".", drop "./" prefix: */
     183            retval |= sysctl_act_recursive((next[0] == '.' && next[1] == '/') ?
     184                        next + 2 : next);
     185            free(next);
     186        }
     187        closedir(dirp);
     188    } else {
     189        char *name = xstrdup(path);
     190        retval |= sysctl_act_on_setting(name);
     191        free(name);
     192    }
     193
     194    return retval;
     195}
     196
     197/* Set sysctl's from a conf file. Format example:
     198 * # Controls IP packet forwarding
     199 * net.ipv4.ip_forward = 0
    243200 */
    244 int sysctl_read_setting(const char *setting, int output)
    245 {
    246     int retval = 0;
    247     char *tmpname, *outname, *cptr;
    248     char inbuf[1025];
    249     const char *name = setting;
    250     FILE *fp;
    251 
    252     if (!setting || !*setting)
    253         bb_error_msg(ERR_INVALID_KEY, setting);
    254 
    255     tmpname = concat_path_file(PROC_PATH, name);
    256     outname = xstrdup(tmpname + strlen(PROC_PATH));
    257 
    258     while ((cptr = strchr(tmpname, '.')) != NULL)
    259         *cptr = '/';
    260     while ((cptr = strchr(outname, '/')) != NULL)
    261         *cptr = '.';
    262 
    263     if ((fp = fopen(tmpname, "r")) == NULL) {
    264         switch (errno) {
    265         case ENOENT:
    266             bb_error_msg(ERR_INVALID_KEY, outname);
    267             break;
    268         case EACCES:
    269             bb_error_msg(ERR_PERMISSION_DENIED, outname);
    270             break;
    271         default:
    272             bb_error_msg(ERR_UNKNOWN_READING, errno, outname);
    273             break;
    274         }
    275         retval = -1;
    276     } else {
    277         while (fgets(inbuf, sizeof(inbuf) - 1, fp)) {
    278             if (output) {
    279                 dwrite_str(STDOUT_FILENO, outname);
    280                 dwrite_str(STDOUT_FILENO, " = ");
    281             }
    282             dwrite_str(STDOUT_FILENO, inbuf);
    283         }
    284         fclose(fp);
    285     }
    286 
    287     free(tmpname);
    288     free(outname);
     201static int sysctl_handle_preload_file(const char *filename)
     202{
     203    char *token[2];
     204    parser_t *parser;
     205
     206    parser = config_open(filename);
     207    /* Must do it _after_ config_open(): */
     208    xchdir("/proc/sys");
     209    /* xchroot(".") - if you are paranoid */
     210
     211//TODO: ';' is comment char too
     212//TODO: comment may be only at line start. "var=1 #abc" - "1 #abc" is the value
     213// (but _whitespace_ from ends should be trimmed first (and we do it right))
     214//TODO: "var==1" is mishandled (must use "=1" as a value, but uses "1")
     215// can it be fixed by removing PARSE_COLLAPSE bit?
     216    while (config_read(parser, token, 2, 2, "# \t=", PARSE_NORMAL)) {
     217        char *tp;
     218        sysctl_dots_to_slashes(token[0]);
     219        tp = xasprintf("%s=%s", token[0], token[1]);
     220        sysctl_act_recursive(tp);
     221        free(tp);
     222    }
     223    if (ENABLE_FEATURE_CLEAN_UP)
     224        config_close(parser);
     225    return 0;
     226}
     227
     228int sysctl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     229int sysctl_main(int argc UNUSED_PARAM, char **argv)
     230{
     231    int retval;
     232    int opt;
     233
     234    opt = getopt32(argv, "+" OPTION_STR); /* '+' - stop on first non-option */
     235    argv += optind;
     236    opt ^= (FLAG_SHOW_KEYS | FLAG_SHOW_KEY_ERRORS);
     237    option_mask32 = opt;
     238
     239    if (opt & FLAG_PRELOAD_FILE) {
     240        option_mask32 |= FLAG_WRITE;
     241        /* xchdir("/proc/sys") is inside */
     242        return sysctl_handle_preload_file(*argv ? *argv : "/etc/sysctl.conf");
     243    }
     244    xchdir("/proc/sys");
     245    /* xchroot(".") - if you are paranoid */
     246    if (opt & (FLAG_TABLE_FORMAT | FLAG_SHOW_ALL)) {
     247        return sysctl_act_recursive(".");
     248    }
     249
     250    retval = 0;
     251    while (*argv) {
     252        sysctl_dots_to_slashes(*argv);
     253        retval |= sysctl_act_recursive(*argv);
     254        argv++;
     255    }
     256
    289257    return retval;
    290 }                       /* end sysctl_read_setting() */
    291 
    292 
    293 
    294 /*
    295  *     Display all the sysctl settings
    296  *
    297  */
    298 int sysctl_display_all(const char *path, int output, int show_table)
    299 {
    300     int retval = 0;
    301     int retval2;
    302     DIR *dp;
    303     struct dirent *de;
    304     char *tmpdir;
    305     struct stat ts;
    306 
    307     dp = opendir(path);
    308     if (!dp) {
    309         retval = -1;
    310     } else {
    311         while ((de = readdir(dp)) != NULL) {
    312             tmpdir = concat_subpath_file(path, de->d_name);
    313             if (tmpdir == NULL)
    314                 continue;
    315             retval2 = stat(tmpdir, &ts);
    316             if (retval2 != 0)
    317                 bb_perror_msg(tmpdir);
    318             else {
    319                 if (S_ISDIR(ts.st_mode)) {
    320                     sysctl_display_all(tmpdir, output, show_table);
    321                 } else
    322                     retval |=
    323                         sysctl_read_setting(tmpdir + strlen(PROC_PATH),
    324                                             output);
    325 
    326             }
    327             free(tmpdir);
    328         }               /* end while */
    329         closedir(dp);
    330     }
    331 
    332     return retval;
    333 }                       /* end sysctl_display_all() */
     258}
Note: See TracChangeset for help on using the changeset viewer.