/* * miniudev - implement a small udev that can run at bootup * Copyright Frank Sorenson 2005 * * Permission is hereby granted to copy, modify and redistribute this code * in terms of the GNU Library General Public License, Version 2 or later, * at your option. * * Alright then.. * Next version. daemonize and read conf file. -solar * */ #include #include #include #include #include #include #include #include #include #include #include #define DEV_PATH "/dev" #define DEV_MODE 0700 int get_device_info(const char *path, int *major, int *minor) { char buf[512]; int fd; int ret; char *chr; char got_colon = 0; int tempval = 0; sprintf(buf, "%s/dev", path); fd = open(buf, O_RDONLY); ret = read(fd, buf, 1024); buf[ret - 1] = '\0'; if (ret == 0) return -1; close(fd); chr = buf; while (*chr != '\0') { if (*chr == ':') { *major = tempval; tempval = 0; got_colon ++; } else { tempval *= 10; tempval += (*chr - '0'); } chr ++; } *minor = tempval; return 0; } int make_device(const char *path, int type) { char buf[512]; const char *device_name; int major; int minor; int ret; int local_errno; device_name = path; while (*device_name != '\0') device_name ++; while ((*(device_name - 1) != '/') && (device_name > path)) { device_name --; } get_device_info(path, &major, &minor); sprintf(buf, "%s/%s", DEV_PATH, device_name); ret = mknod(buf, DEV_MODE | type, makedev(major, minor)); if (ret != 0) local_errno = errno; return 0; } char cmp(const char *s1, const char *s2) { int n = 0; while (s1[n] == s2[n]) { if (s1[n] == '\0') return 1; n++; } return 0; } int find_dev(const char *path, int type) { DIR *dir; struct dirent *entry; char temp_path[512]; int local_errno; dir = opendir(path); if (dir == NULL) { printf("Could not open path %s: error %d\n", path, local_errno); exit(-1); } do { entry = readdir(dir); if (entry == NULL) break; if (cmp(entry->d_name, ".")) continue; if (cmp(entry->d_name, "..")) continue; if (entry->d_type == DT_DIR) { sprintf(temp_path, "%s/%s", path, entry->d_name); find_dev(temp_path, type); } if (cmp(entry->d_name, "dev")) { make_device(path, type); } } while (entry != NULL); closedir(dir); return 0; } void do_perm(char *path, int mode, int uid, int gid) { if ((chmod(path, mode)) != 0) chown(name, uid, gid); } int filter_hidden(const struct dirent *dentry) { if (dentry->d_name[0] == '.') return 0; return 1; } int set_perms(char *conf) { int sleep_time = 1; char buf[_POSIX_PATH_MAX]; FILE *fp; if ((fp = fopen(conf, "r")) == NULL) return 1; chdir(DEV_PATH); while ((fgets(buf, sizeof(buf), fp)) != NULL) { char name[_POSIX_PATH_MAX] = ""; char *p; int uid, gid; int mode = 0; uid = gid = 0; if (buf[0] == '#') continue; if ((p = strchr(buf, '\n')) != NULL) *p = 0; if ((strncmp(buf, "SLEEP=", 6)) == 0) { sleep_time = atoi(&buf[6]); continue; } if ((strstr(buf, "->")) != NULL) { char oldpath[_POSIX_PATH_MAX]; char newpath[_POSIX_PATH_MAX]; if ((sscanf(buf, "%s -> %s", &newpath, &oldpath)) == 2) { if ((access(oldpath, R_OK)) == 0) symlink(oldpath, newpath); } continue; } if ((sscanf(buf, "%s %d:%d %o", &name, &uid, &gid, &mode)) != 4) continue; // printf("%s %d %d %4o\n", name, uid, gid, mode & 07777); if ((p = strchr(name, '*')) != NULL) { struct dirent **devices; int d, i; *p = 0; if ((d = scandir(".", &devices, filter_hidden, alphasort)) < 0) continue; for (i = 0 ; i < d; i++) { if ((strncmp(name, devices[i]->d_name, strlen(name))) == 0) do_perm(devices[i]->d_name, mode, uid, gid); } while(d--) free(devices[d]); continue; } do_perm(name, mode, uid, gid); } fclose(fp); return sleep_time; } int main(int argc, char **argv) { while(1) { mkdir(DEV_PATH, 0755); mkdir(DEV_PATH "/shm", 0755); mkdir(DEV_PATH "/pts", 0755); find_dev("/sys/block", S_IFBLK); find_dev("/sys/class", S_IFCHR); sleep(set_perms(argc > 1 ? argv[1] : "/etc/mdev.conf")); } return 0; }