/* mkmisc - make misc device nodes with dynamic minor number * * Copyright (C) 2011 Antonio Ospite * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ /* A misc device is a character device node which can have a dynamic minor * number, see: * http://www.linux.it/~rubini/docs/misc/misc.html */ #include #include #include #include #include #include #include #include #include static int verbose = 0; static int force = 0; static unsigned int mode = 0664; static int misc_get_major(void) { FILE *fp; char line[256]; int major; char name[64]; fp = fopen("/proc/devices", "r"); if (fp == NULL) { perror("/proc/devices"); return -1; } while (fgets(line, sizeof(line) - 1, fp)) { if(sscanf(line, "%d %64s", &major, name) == 2) if (strcmp(name, "misc") == 0) { fclose(fp); return major; } } fclose(fp); return -1; } static int misc_get_minor(char *device) { FILE *fp; int minor; char name[64]; char *path; char *node; fp = fopen("/proc/misc", "r"); if (fp == NULL) { perror("/proc/misc"); return -1; } path = strdup(device); node = basename(path); while (fscanf(fp, "%d %64s", &minor, name) == 2) { if (strcmp(name, node) == 0) { free(path); fclose(fp); return minor; } } free(path); fclose(fp); return -1; } static int mkmisc(char *device) { int major; int minor; dev_t dev; int ret; major = misc_get_major(); if (major < 0) { fprintf(stderr, "Cannot get misc major number\n"); return major; } minor = misc_get_minor(device); if (minor < 0) { fprintf(stderr, "Cannot get misc minor for %s\n", device); return minor; } if (verbose) printf("Creating device: %s, major: %d, minor: %d\n", device, major, minor); if (force) { ret = unlink(device); if (ret < 0) { perror("unlink"); /* return ret; */ } } dev = makedev(major, minor); mode |= S_IFCHR; ret = mknod(device, mode, dev); if (ret < 0) { perror("mknod"); return ret; } return 0; } static void usage(void) { printf("Usage: mkmisc [OPTION]... NAME\n"); printf("Create the special file NAME as a misc device with a dynamic minor number.\n"); printf("\n"); printf("OPTION can be any of:\n"); printf(" -f force creation even if the file already exists\n"); printf(" -m MODE set file permission bits to MODE, not a=rw - umask\n"); printf(" -v verbose output\n"); printf(" -h display this help and exit\n"); } static void parse_options(int argc, char *argv[]) { int c; int ret; while ((c = getopt (argc, argv, "fm:vh")) != -1) switch (c) { case 'f': force = 1; break; case 'm': ret = sscanf(optarg, "0%o", &mode); if (ret != 1) { fprintf(stderr, "mode must be octal (e.g 0664)\n"); exit(EXIT_FAILURE); } break; case 'v': verbose = 1; break; case 'h': usage(); exit(0); case '?': /* skip known options with missing arguments */ if (optopt != 'm') { if(isprint(optopt)) fprintf (stderr, "Unknown option `-%c'.\n", optopt); else fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt); } default: usage(); exit(EXIT_FAILURE); } } int main(int argc, char *argv[]) { int ret; char *device = NULL; parse_options(argc, argv); if (optind >= argc) { fprintf(stderr, "Missing argument NAME\n\n"); usage(); exit(EXIT_FAILURE); } else if ((argc - optind) > 1) { fprintf(stderr, "Too many arguments\n\n"); usage(); exit(EXIT_FAILURE); } device = strdup(argv[optind]); ret = mkmisc(device); if (ret < 0) fprintf(stderr, "Cannot create %s\n", device); free(device); return ret; }