Ignore:
Timestamp:
Nov 4, 2007, 3:16:40 AM (16 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/util-linux/mdev.c

    r902 r1765  
    1 /* vi:set ts=4:
     1/* vi: set sw=4 ts=4: */
     2/*
    23 *
    34 * mdev - Mini udev for busybox
     
    67 * Copyright 2005 Frank Sorenson <frank@tuxrocks.com>
    78 *
    8  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     9 * Licensed under GPL version 2, see file LICENSE in this tarball for details.
    910 */
    1011
    11 #include "busybox.h"
    12 #include <ctype.h>
    13 #include <errno.h>
    14 #include <sys/mman.h>
    15 #include <sys/sysmacros.h>
     12#include "libbb.h"
    1613#include "xregex.h"
    1714
    18 #define DEV_PATH    "/dev"
    19 
    20 struct mdev_globals
    21 {
     15struct globals {
    2216    int root_major, root_minor;
    23 } mdev_globals;
    24 
    25 #define bbg mdev_globals
     17};
     18#define G (*(struct globals*)&bb_common_bufsiz1)
     19#define root_major (G.root_major)
     20#define root_minor (G.root_minor)
     21
     22#define MAX_SYSFS_DEPTH 3 /* prevent infinite loops in /sys symlinks */
    2623
    2724/* mknod in /dev based on a path like "/sys/block/hda/hda1" */
    2825static void make_device(char *path, int delete)
    2926{
    30     char *device_name;
    31     int major, minor, type, len, fd;
     27    const char *device_name;
     28    int major, minor, type, len;
    3229    int mode = 0660;
    3330    uid_t uid = 0;
     
    4340    if (!delete) {
    4441        strcat(path, "/dev");
    45         fd = open(path, O_RDONLY);
    46         len = read(fd, temp + 1, 64);
     42        len = open_read_close(path, temp + 1, 64);
    4743        *temp++ = 0;
    48         close(fd);
    4944        if (len < 1) return;
    5045    }
     
    5247    /* Determine device name, type, major and minor */
    5348
    54     device_name = strrchr(path, '/') + 1;
     49    device_name = bb_basename(path);
    5550    type = path[5]=='c' ? S_IFCHR : S_IFBLK;
    5651
     
    5954    if (ENABLE_FEATURE_MDEV_CONF) {
    6055        char *conf, *pos, *end;
     56        int line, fd;
    6157
    6258        /* mmap the config file */
    63         if (-1 != (fd=open("/etc/mdev.conf",O_RDONLY))) {
    64             len = lseek(fd, 0, SEEK_END);
    65             conf = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
    66             if (conf) {
    67                 int line = 0;
    68 
    69                 /* Loop through lines in mmaped file*/
    70                 for (pos=conf; pos-conf<len;) {
    71                     int field;
    72                     char *end2;
    73 
    74                     line++;
    75                     /* find end of this line */
    76                     for(end=pos; end-conf<len && *end!='\n'; end++)
     59        fd = open("/etc/mdev.conf", O_RDONLY);
     60        if (fd < 0)
     61            goto end_parse;
     62        len = xlseek(fd, 0, SEEK_END);
     63        conf = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
     64        close(fd);
     65        if (!conf)
     66            goto end_parse;
     67
     68        line = 0;
     69        /* Loop through lines in mmaped file*/
     70        for (pos=conf; pos-conf<len;) {
     71            int field;
     72            char *end2;
     73
     74            line++;
     75            /* find end of this line */
     76            for (end=pos; end-conf<len && *end!='\n'; end++)
     77                ;
     78
     79            /* Three fields: regex, uid:gid, mode */
     80            for (field=0; field < (3 + ENABLE_FEATURE_MDEV_EXEC);
     81                    field++)
     82            {
     83                /* Skip whitespace */
     84                while (pos<end && isspace(*pos)) pos++;
     85                if (pos==end || *pos=='#') break;
     86                for (end2=pos;
     87                    end2<end && !isspace(*end2) && *end2!='#'; end2++)
     88                    ;
     89
     90                if (field == 0) {
     91                    /* Regex to match this device */
     92
     93                    char *regex = xstrndup(pos, end2-pos);
     94                    regex_t match;
     95                    regmatch_t off;
     96                    int result;
     97
     98                    /* Is this it? */
     99                    xregcomp(&match,regex, REG_EXTENDED);
     100                    result = regexec(&match, device_name, 1, &off, 0);
     101                    regfree(&match);
     102                    free(regex);
     103
     104                    /* If not this device, skip rest of line */
     105                    if (result || off.rm_so
     106                            || off.rm_eo != strlen(device_name))
     107                        break;
     108                }
     109                if (field == 1) {
     110                    /* uid:gid */
     111
     112                    char *s, *s2;
     113
     114                    /* Find : */
     115                    for (s=pos; s<end2 && *s!=':'; s++)
    77116                        ;
    78 
    79                     /* Three fields: regex, uid:gid, mode */
    80                     for (field=0; field < (3 + ENABLE_FEATURE_MDEV_EXEC);
    81                             field++)
    82                     {
    83                         /* Skip whitespace */
    84                         while (pos<end && isspace(*pos)) pos++;
    85                         if (pos==end || *pos=='#') break;
    86                         for (end2=pos;
    87                             end2<end && !isspace(*end2) && *end2!='#'; end2++)
    88                             ;
    89 
    90                         if (!field) {
    91                             /* Regex to match this device */
    92 
    93                             char *regex = strndupa(pos, end2-pos);
    94                             regex_t match;
    95                             regmatch_t off;
    96                             int result;
    97 
    98                             /* Is this it? */
    99                             xregcomp(&match,regex, REG_EXTENDED);
    100                             result = regexec(&match, device_name, 1, &off, 0);
    101                             regfree(&match);
    102 
    103                             /* If not this device, skip rest of line */
    104                             if (result || off.rm_so
    105                                     || off.rm_eo != strlen(device_name))
    106                                 break;
    107 
    108                         } else if (field == 1) {
    109                             /* uid:gid */
    110 
    111                             char *s, *s2;
    112 
    113                             /* Find : */
    114                             for(s=pos; s<end2 && *s!=':'; s++)
    115                                 ;
    116                             if (s == end2) break;
    117 
    118                             /* Parse UID */
    119                             uid = strtoul(pos,&s2,10);
    120                             if (s != s2) {
    121                                 struct passwd *pass;
    122                                 pass = getpwnam(strndupa(pos, s-pos));
    123                                 if (!pass) break;
    124                                 uid = pass->pw_uid;
    125                             }
    126                             s++;
    127                             /* parse GID */
    128                             gid = strtoul(s, &s2, 10);
    129                             if (end2 != s2) {
    130                                 struct group *grp;
    131                                 grp = getgrnam(strndupa(s, end2-s));
    132                                 if (!grp) break;
    133                                 gid = grp->gr_gid;
    134                             }
    135                         } else if (field == 2) {
    136                             /* mode */
    137 
    138                             mode = strtoul(pos, &pos, 8);
    139                             if (pos != end2) break;
    140                         } else if (ENABLE_FEATURE_MDEV_EXEC && field == 3) {
    141                             // Command to run
    142                             char *s = "@$*", *s2;
    143                             if (!(s2 = strchr(s, *pos++))) {
    144                                 // Force error
    145                                 field = 1;
    146                                 break;
    147                             }
    148                             if ((s2-s+1) & (1<<delete))
    149                                 command = bb_xstrndup(pos, end-pos);
    150                         }
    151 
    152                         pos = end2;
     117                    if (s == end2) break;
     118
     119                    /* Parse UID */
     120                    uid = strtoul(pos, &s2, 10);
     121                    if (s != s2) {
     122                        struct passwd *pass;
     123                        char *_unam = xstrndup(pos, s-pos);
     124                        pass = getpwnam(_unam);
     125                        free(_unam);
     126                        if (!pass) break;
     127                        uid = pass->pw_uid;
    153128                    }
    154 
    155                     /* Did everything parse happily? */
    156 
    157                     if (field > 2) break;
    158                     if (field) bb_error_msg_and_die("Bad line %d",line);
    159 
    160                     /* Next line */
    161                     pos = ++end;
     129                    s++;
     130                    /* parse GID */
     131                    gid = strtoul(s, &s2, 10);
     132                    if (end2 != s2) {
     133                        struct group *grp;
     134                        char *_grnam = xstrndup(s, end2-s);
     135                        grp = getgrnam(_grnam);
     136                        free(_grnam);
     137                        if (!grp) break;
     138                        gid = grp->gr_gid;
     139                    }
    162140                }
    163                 munmap(conf, len);
     141                if (field == 2) {
     142                    /* mode */
     143
     144                    mode = strtoul(pos, &pos, 8);
     145                    if (pos != end2) break;
     146                }
     147                if (ENABLE_FEATURE_MDEV_EXEC && field == 3) {
     148                    // Command to run
     149                    const char *s = "@$*";
     150                    const char *s2;
     151                    s2 = strchr(s, *pos++);
     152                    if (!s2) {
     153                        // Force error
     154                        field = 1;
     155                        break;
     156                    }
     157                    if ((s2-s+1) & (1<<delete))
     158                        command = xstrndup(pos, end-pos);
     159                }
     160
     161                pos = end2;
    164162            }
    165             close(fd);
     163
     164            /* Did everything parse happily? */
     165
     166            if (field > 2) break;
     167            if (field) bb_error_msg_and_die("bad line %d",line);
     168
     169            /* Next line */
     170            pos = ++end;
    166171        }
     172        munmap(conf, len);
     173 end_parse: /* nothing */ ;
    167174    }
    168175
     
    171178        if (sscanf(temp, "%d:%d", &major, &minor) != 2) return;
    172179        if (mknod(device_name, mode | type, makedev(major, minor)) && errno != EEXIST)
    173             bb_perror_msg_and_die("mknod %s failed", device_name);
    174 
    175         if (major == bbg.root_major && minor == bbg.root_minor)
     180            bb_perror_msg_and_die("mknod %s", device_name);
     181
     182        if (major == root_major && minor == root_minor)
    176183            symlink(device_name, "root");
    177    
     184
    178185        if (ENABLE_FEATURE_MDEV_CONF) chown(device_name, uid, gid);
    179186    }
    180187    if (command) {
    181         int rc;
    182         char *s;
    183        
    184         s=bb_xasprintf("MDEV=%s",device_name);
     188        /* setenv will leak memory, so use putenv */
     189        char *s = xasprintf("MDEV=%s", device_name);
    185190        putenv(s);
    186         rc = system(command);
    187         s[4]=0;
    188         putenv(s);
     191        if (system(command) == -1)
     192            bb_perror_msg_and_die("cannot run %s", command);
     193        s[4] = '\0';
     194        unsetenv(s);
    189195        free(s);
    190196        free(command);
    191         if (rc == -1) bb_perror_msg_and_die("Couldn't run %s", command);
    192197    }
    193198    if (delete) unlink(device_name);
    194199}
    195200
    196 /* Recursive search of /sys/block or /sys/class.  path must be a writeable
    197  * buffer of size PATH_MAX containing the directory string to start at. */
    198 
    199 static void find_dev(char *path)
    200 {
    201     DIR *dir;
    202     size_t len = strlen(path);
    203     struct dirent *entry;
    204 
    205     if ((dir = opendir(path)) == NULL)
    206         return;
    207 
    208     while ((entry = readdir(dir)) != NULL) {
    209         struct stat st;
    210 
    211         /* Skip "." and ".." (also skips hidden files, which is ok) */
    212 
    213         if (entry->d_name[0] == '.')
    214             continue;
    215 
    216         // uClibc doesn't fill out entry->d_type reliably. so we use lstat().
    217 
    218         snprintf(path+len, PATH_MAX-len, "/%s", entry->d_name);
    219         if (!lstat(path, &st) && S_ISDIR(st.st_mode)) find_dev(path);
    220         path[len] = 0;
    221 
    222         /* If there's a dev entry, mknod it */
    223 
    224         if (!strcmp(entry->d_name, "dev")) make_device(path, 0);
    225     }
    226 
    227     closedir(dir);
    228 }
    229 
    230 int mdev_main(int argc, char *argv[])
     201/* File callback for /sys/ traversal */
     202static int fileAction(const char *fileName, struct stat *statbuf,
     203                      void *userData, int depth)
     204{
     205    size_t len = strlen(fileName) - 4;
     206    char *scratch = userData;
     207
     208    if (strcmp(fileName + len, "/dev"))
     209        return FALSE;
     210
     211    strcpy(scratch, fileName);
     212    scratch[len] = 0;
     213    make_device(scratch, 0);
     214
     215    return TRUE;
     216}
     217
     218/* Directory callback for /sys/ traversal */
     219static int dirAction(const char *fileName, struct stat *statbuf,
     220                      void *userData, int depth)
     221{
     222    return (depth >= MAX_SYSFS_DEPTH ? SKIP : TRUE);
     223}
     224
     225/* For the full gory details, see linux/Documentation/firmware_class/README
     226 *
     227 * Firmware loading works like this:
     228 * - kernel sets FIRMWARE env var
     229 * - userspace checks /lib/firmware/$FIRMWARE
     230 * - userspace waits for /sys/$DEVPATH/loading to appear
     231 * - userspace writes "1" to /sys/$DEVPATH/loading
     232 * - userspace copies /lib/firmware/$FIRMWARE into /sys/$DEVPATH/data
     233 * - userspace writes "0" (worked) or "-1" (failed) to /sys/$DEVPATH/loading
     234 * - kernel loads firmware into device
     235 */
     236static void load_firmware(const char *const firmware, const char *const sysfs_path)
     237{
     238    int cnt;
     239    int firmware_fd, loading_fd, data_fd;
     240
     241    /* check for $FIRMWARE from kernel */
     242    /* XXX: dont bother: open(NULL) works same as open("no-such-file")
     243     * if (!firmware)
     244     *  return;
     245     */
     246
     247    /* check for /lib/firmware/$FIRMWARE */
     248    xchdir("/lib/firmware");
     249    firmware_fd = xopen(firmware, O_RDONLY);
     250
     251    /* in case we goto out ... */
     252    data_fd = -1;
     253
     254    /* check for /sys/$DEVPATH/loading ... give 30 seconds to appear */
     255    xchdir(sysfs_path);
     256    for (cnt = 0; cnt < 30; ++cnt) {
     257        loading_fd = open("loading", O_WRONLY);
     258        if (loading_fd == -1)
     259            sleep(1);
     260        else
     261            break;
     262    }
     263    if (loading_fd == -1)
     264        goto out;
     265
     266    /* tell kernel we're loading by `echo 1 > /sys/$DEVPATH/loading` */
     267    if (write(loading_fd, "1", 1) != 1)
     268        goto out;
     269
     270    /* load firmware by `cat /lib/firmware/$FIRMWARE > /sys/$DEVPATH/data */
     271    data_fd = open("data", O_WRONLY);
     272    if (data_fd == -1)
     273        goto out;
     274    cnt = bb_copyfd_eof(firmware_fd, data_fd);
     275
     276    /* tell kernel result by `echo [0|-1] > /sys/$DEVPATH/loading` */
     277    if (cnt > 0)
     278        write(loading_fd, "0", 1);
     279    else
     280        write(loading_fd, "-1", 2);
     281
     282 out:
     283    if (ENABLE_FEATURE_CLEAN_UP) {
     284        close(firmware_fd);
     285        close(loading_fd);
     286        close(data_fd);
     287    }
     288}
     289
     290int mdev_main(int argc, char **argv);
     291int mdev_main(int argc, char **argv)
    231292{
    232293    char *action;
     
    234295    RESERVE_CONFIG_BUFFER(temp,PATH_MAX);
    235296
    236     bb_xchdir(DEV_PATH);
     297    xchdir("/dev");
    237298
    238299    /* Scan */
     
    241302        struct stat st;
    242303
    243         stat("/", &st);  // If this fails, we have bigger problems.
    244         bbg.root_major=major(st.st_dev);
    245         bbg.root_minor=minor(st.st_dev);
    246         strcpy(temp,"/sys/block");
    247         find_dev(temp);
    248         strcpy(temp,"/sys/class");
    249         find_dev(temp);
     304        xstat("/", &st);
     305        root_major = major(st.st_dev);
     306        root_minor = minor(st.st_dev);
     307
     308        recursive_action("/sys/block",
     309            ACTION_RECURSE | ACTION_FOLLOWLINKS,
     310            fileAction, dirAction, temp, 0);
     311
     312        recursive_action("/sys/class",
     313            ACTION_RECURSE | ACTION_FOLLOWLINKS,
     314            fileAction, dirAction, temp, 0);
    250315
    251316    /* Hotplug */
     
    254319        action = getenv("ACTION");
    255320        env_path = getenv("DEVPATH");
    256         if (!action || !env_path)
     321        if (!action || !env_path)
    257322            bb_show_usage();
    258323
    259324        sprintf(temp, "/sys%s", env_path);
    260         if (!strcmp(action, "add")) make_device(temp,0);
    261         else if (!strcmp(action, "remove")) make_device(temp,1);
     325        if (!strcmp(action, "remove"))
     326            make_device(temp, 1);
     327        else if (!strcmp(action, "add")) {
     328            make_device(temp, 0);
     329
     330            if (ENABLE_FEATURE_MDEV_LOAD_FIRMWARE)
     331                load_firmware(getenv("FIRMWARE"), temp);
     332        }
    262333    }
    263334
Note: See TracChangeset for help on using the changeset viewer.