Mercurial > hg > toybox
view toys/pending/mdev.c @ 1572:da1bf31ed322 draft
Tweak the "ignoring return value" fortify workaround for readlinkat.
We zero the buffer and if the link read fails that's left alone, so
it's ok for the symlink not to be there. Unfortunately, typecasting the
return value to (void) doesn't shut up gcc, and having an if(); with the
semicolon on the same line doesn't shut up llvm. (The semicolon on a new
line would, but C does not have significant whitespace and I'm not going
to humor llvm if it plans to start.)
So far, empty curly brackets consistently get the warning to shut up.
author | Rob Landley <rob@landley.net> |
---|---|
date | Mon, 24 Nov 2014 17:23:23 -0600 |
parents | 63db77909fc8 |
children | da1296acc73e |
line wrap: on
line source
/* mdev.c - Populate /dev directory and handle hotplug events * * Copyright 2005, 2008 Rob Landley <rob@landley.net> * Copyright 2005 Frank Sorenson <frank@tuxrocks.com> USE_MDEV(NEWTOY(mdev, "s", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_UMASK)) config MDEV bool "mdev" default n help usage: mdev [-s] Create devices in /dev using information from /sys. -s Scan all entries in /sys to populate /dev. config MDEV_CONF bool "Configuration file for mdev" default y depends on MDEV help The mdev config file (/etc/mdev.conf) contains lines that look like: hd[a-z][0-9]* 0:3 660 Each line must contain three whitespace separated fields. The first field is a regular expression matching one or more device names, and the second and third fields are uid:gid and file permissions for matching devies. */ #include "toys.h" // todo, open() block devices to trigger partition scanning. // mknod in /dev based on a path like "/sys/block/hda/hda1" static void make_device(char *path) { char *device_name, *s, *temp; int major, minor, type, len, fd; int mode = 0660; uid_t uid = 0; gid_t gid = 0; // Try to read major/minor string temp = strrchr(path, '/'); fd = open(path, O_RDONLY); *temp=0; temp = toybuf; len = read(fd, temp, 64); close(fd); if (len<1) return; temp[len] = 0; // Determine device name, type, major and minor device_name = strrchr(path, '/') + 1; type = path[5]=='c' ? S_IFCHR : S_IFBLK; major = minor = 0; sscanf(temp, "%u:%u", &major, &minor); // If we have a config file, look up permissions for this device if (CFG_MDEV_CONF) { char *conf, *pos, *end; // mmap the config file if (-1!=(fd = open("/etc/mdev.conf", O_RDONLY))) { len = fdlength(fd); conf = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0); if (conf) { int line = 0; // Loop through lines in mmaped file for (pos = conf; pos-conf<len;) { int field; char *end2; line++; // find end of this line for(end = pos; end-conf<len && *end!='\n'; end++); // Three fields: regex, uid:gid, mode for (field = 3; field; field--) { // Skip whitespace while (pos<end && isspace(*pos)) pos++; if (pos==end || *pos=='#') break; for (end2 = pos; end2<end && !isspace(*end2) && *end2!='#'; end2++); switch(field) { // Regex to match this device case 3: { char *regex = strndup(pos, end2-pos); regex_t match; regmatch_t off; int result; // Is this it? xregcomp(&match, regex, REG_EXTENDED); result=regexec(&match, device_name, 1, &off, 0); regfree(&match); free(regex); // If not this device, skip rest of line if (result || off.rm_so || off.rm_eo!=strlen(device_name)) goto end_line; break; } // uid:gid case 2: { char *s2; // Find : for(s = pos; s<end2 && *s!=':'; s++); if (s==end2) goto end_line; // Parse UID uid = strtoul(pos,&s2,10); if (s!=s2) { struct passwd *pass; char *str = strndup(pos, s-pos); pass = getpwnam(str); free(str); if (!pass) goto end_line; uid = pass->pw_uid; } s++; // parse GID gid = strtoul(s,&s2,10); if (end2!=s2) { struct group *grp; char *str = strndup(s, end2-s); grp = getgrnam(str); free(str); if (!grp) goto end_line; gid = grp->gr_gid; } break; } // mode case 1: { mode = strtoul(pos, &pos, 8); if (pos!=end2) goto end_line; goto found_device; } } pos=end2; } end_line: // Did everything parse happily? if (field && field!=3) error_exit("Bad line %d", line); // Next line pos = ++end; } found_device: munmap(conf, len); } close(fd); } } sprintf(temp, "/dev/%s", device_name); if (mknod(temp, mode | type, makedev(major, minor)) && errno != EEXIST) perror_exit("mknod %s failed", temp); if (CFG_MDEV_CONF) mode=chown(temp, uid, gid); } static int callback(struct dirtree *node) { // Entries in /sys/class/block aren't char devices, so skip 'em. (We'll // get block devices out of /sys/block.) if(!strcmp(node->name, "block")) return 0; // Does this directory have a "dev" entry in it? // This is path based because the hotplug callbacks are if (S_ISDIR(node->st.st_mode) || S_ISLNK(node->st.st_mode)) { int len=4; char *dev = dirtree_path(node, &len); strcpy(dev+len, "/dev"); if (!access(dev, R_OK)) make_device(dev); free(dev); } // Circa 2.6.25 the entries more than 2 deep are all either redundant // (mouse#, event#) or unnamed (every usb_* entry is called "device"). return (node->parent && node->parent->parent) ? 0 : DIRTREE_RECURSE; } void mdev_main(void) { // Handle -s if (toys.optflags) { dirtree_read("/sys/class", callback); dirtree_read("/sys/block", callback); } // hotplug support goes here }