--- /dev/null
+/* mkmisc - make misc device nodes with dynamic minor number
+ *
+ * Copyright (C) 2011 Antonio Ospite <ospite@studenti.unina.it>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+/* 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libgen.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+
+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 *node)
+{
+ FILE *fp;
+ int minor;
+ char name[64];
+
+ fp = fopen("/proc/misc", "r");
+ if (fp == NULL) {
+ perror("/proc/misc");
+ return -1;
+ }
+
+ while (fscanf(fp, "%d %64s", &minor, name) == 2) {
+ if (strcmp(name, node) == 0) {
+ fclose(fp);
+ return minor;
+ }
+ }
+ fclose(fp);
+
+ return -1;
+}
+
+static int mkmisc(char *device)
+{
+ char *path;
+ char *node;
+ 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;
+ }
+
+ path = strdup(device);
+ node = basename(path);
+
+ minor = misc_get_minor(node);
+ if (minor < 0) {
+ fprintf(stderr, "Cannot get misc minor for %s\n", device);
+ free(path);
+ return minor;
+ }
+ free(path);
+
+ 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;
+}