Device table support for makedevs, the previous behaviour can been
authorGlenn L McGrath <bug1@ihug.co.nz>
Sat, 5 Jun 2004 07:54:52 +0000 (07:54 -0000)
committerGlenn L McGrath <bug1@ihug.co.nz>
Sat, 5 Jun 2004 07:54:52 +0000 (07:54 -0000)
selected at configure time.

include/usage.h
miscutils/Config.in
miscutils/makedevs.c
patches/makdevs_table.diff [new file with mode: 0644]

index ce56247..d41780d 100644 (file)
 #define lsmod_full_usage \
        "List the currently loaded kernel modules."
 
+#ifdef CONFIG_FEATURE_MAKEDEVS_LEAF
 #define makedevs_trivial_usage \
        "NAME TYPE MAJOR MINOR FIRST LAST [s]"
 #define makedevs_full_usage \
        "[creates ttyS2-ttyS63]\n" \
        "# makedevs /dev/hda b 3 0 0 8 s\n" \
        "[creates hda,hda1-hda8]\n"
+#endif
+
+#ifdef CONFIG_FEATURE_MAKEDEVS_TABLE
+#define makedevs_trivial_usage \
+       "[-r rootdir] [device_table]"
+#define makedevs_full_usage \
+       "Creates a batch of special files as specified in a device table\n" \
+       "The device table has one line per device group, each group is of\n" \
+       "the format\n" \
+       "\ttype mode user group major minor start increment count\n" \
+       "a '-' may be used for blank entries\n"
+#endif
 
 #ifdef CONFIG_FEATURE_MD5_SHA1_SUM_CHECK
 #define USAGE_MD5_SHA1_SUM_CHECK(a) a
index 7e18c16..320f4c2 100644 (file)
@@ -143,10 +143,32 @@ config CONFIG_MAKEDEVS
        bool "makedevs"
        default n
        help
-         'makedevs' is a utility used and created by the Linux Router Project.
-         It creates a large number of device special files (/dev devices)
-         rather quickly, and can be considerably faster then running mknod a
-         zillion times.
+         'makedevs' is a utility used to create a batch of devices with
+         one command.
+         .
+         There are two choices for command line behaviour, the interface
+         as used by LEAF/Linux Router Project, or a device table file.
+         . 
+         'leaf' is traditionally what busybox follows, it allows multiple
+         devices of a particluar type to be created per command.
+         e.g. /dev/hda[0-9]
+          Device properties are passed as command line arguments.
+         .
+         'table' reads device properties from a file or stdin, allowing
+         a batch of unrelated devices to be makde with one command. 
+          User/group names are allowed as an alternative to uid/gid.
+
+choice
+       prompt "Choose makedevs behaviour"
+       default CONFIG_FEATURE_MAKDEVS_TABLE
+
+config CONFIG_FEATURE_MAKEDEVS_LEAF
+        bool "leaf"
+
+config CONFIG_FEATURE_MAKEDEVS_TABLE
+       bool "table"
+
+endchoice
 
 config CONFIG_MT
        bool "mt"
index 45498bb..57b2d6c 100644 (file)
@@ -1,20 +1,27 @@
 /* vi: set sw=4 ts=4: */
-/*
- * public domain -- Dave 'Kill a Cop' Cinege <dcinege@psychosis.com>
- *
- * makedevs
- * Make ranges of device files quickly.
- * known bugs: can't deal with alpha ranges
- */
 
+#include <sys/types.h>
+
+#include <fcntl.h>
+#include <getopt.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <fcntl.h>
+#include <time.h>
 #include <unistd.h>
-#include <sys/types.h>
+
 #include "busybox.h"
 
+#ifdef CONFIG_FEATURE_MAKEDEVS_LEAF
+
+/*
+ * public domain -- Dave 'Kill a Cop' Cinege <dcinege@psychosis.com>
+ *
+ * makedevs
+ * Make ranges of device files quickly.
+ * known bugs: can't deal with alpha ranges
+ */
 int makedevs_main(int argc, char **argv)
 {
        mode_t mode;
@@ -69,24 +76,153 @@ int makedevs_main(int argc, char **argv)
        return 0;
 }
 
+#elif defined CONFIG_FEATURE_MAKEDEVS_TABLE
+
 /*
-And this is what this program replaces. The shell is too slow!
-
-makedev () {
-local basedev=$1; local S=$2; local E=$3
-local major=$4; local Sminor=$5; local type=$6
-local sbase=$7
-
-       if [ ! "$sbase" = "" ]; then
-               mknod "$basedev" $type $major $Sminor
-               S=`expr $S + 1`
-               Sminor=`expr $Sminor + 1`
-       fi
-
-       while [ $S -le $E ]; do
-               mknod "$basedev$S" $type $major $Sminor
-               S=`expr $S + 1`
-               Sminor=`expr $Sminor + 1`
-       done
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  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 Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+static const struct option makedevs_long_options[] = {
+       {"root", 1, NULL, 'r'},
+       {0, 0, 0, 0}
+};
+
+extern int makedevs_main(int argc, char **argv)
+{
+       FILE *table;
+       int opt;
+       char *rootdir = "./";
+       char *line;
+       int ret = EXIT_SUCCESS;
+
+       bb_opt_complementaly = "d~r";
+       bb_applet_long_options = makedevs_long_options;
+       opt = bb_getopt_ulflags(argc, argv, "d:r:", &rootdir, &rootdir);
+
+       if (optind + 1 == argc) {
+               table = bb_xfopen(argv[optind], "r");
+       } else {
+               table = stdin;
+       }
+
+       if (chdir(rootdir) == -1) {
+               bb_perror_msg_and_die("Couldnt chdor to %s", rootdir);
+       }
+
+       umask(0);
+
+       while ((line = bb_get_chomped_line_from_file(table))) {
+               char type;
+               unsigned int mode = 0755;
+               unsigned int major = 0;
+               unsigned int minor = 0;
+               unsigned int count = 0;
+               unsigned int increment = 0;
+               unsigned int start = 0;
+               char name[41];
+               char user[41];
+               char group[41];
+               char *full_name;
+               uid_t uid;
+               gid_t gid;
+
+               if ((2 > sscanf(line, "%40s %c %o %40s %40s %u %u %u %u %u", name,
+                       &type, &mode, user, group, &major,
+                       &minor, &start, &increment, &count)) ||
+                       ((major | minor | start | count | increment) > 255)) {
+                       bb_error_msg("Ignoring invalid line\n%s\n", line);
+                       ret = EXIT_FAILURE;
+                       continue;
+               }
+               if (name[0] == '#') {
+                       continue;
+               }
+               if (group) {
+                       gid = get_ug_id(group, my_getgrnam);
+               } else {
+                       gid = getgid();
+               }
+               if (user) {
+                       uid = get_ug_id(user, my_getpwnam);
+               } else {
+                       uid = getuid();
+               }
+               full_name = concat_path_file(rootdir, name);
+
+               if (type == 'd') {
+                       bb_make_directory(full_name, mode | S_IFDIR, 0);
+                       if (chown(full_name, uid, gid) == -1) {
+                               bb_perror_msg("chown failed for %s", full_name);
+                               ret = EXIT_FAILURE;
+                               goto loop;
+                       }
+               } else {
+                       dev_t rdev;
+
+                       if (type == 'p') {
+                               mode |= S_IFIFO;
+                       }
+                       else if (type == 'c') {
+                               mode |= S_IFCHR;
+                       }
+                       else if (type == 'b') {
+                               mode |= S_IFBLK;
+                       } else {
+                               bb_error_msg("Unsupported file type %c", type);
+                               ret = EXIT_FAILURE;
+                               goto loop;
+                       }
+
+                       if (count > 0) {
+                               int i;
+                               char *full_name_inc;
+
+                               full_name_inc = xmalloc(strlen(full_name) + 4);
+                               for (i = start; i < count; i++) {
+                                       sprintf(full_name_inc, "%s%d", full_name, i);
+                                       rdev = (major << 8) + minor + (i * increment - start);
+                                       if (mknod(full_name_inc, mode, rdev) == -1) {
+                                               bb_perror_msg("Couldnt create node %s", full_name_inc);
+                                               ret = EXIT_FAILURE;
+                                       }
+                                       else if (chown(full_name_inc, uid, gid) == -1) {
+                                               bb_perror_msg("chown failed for %s", full_name_inc);
+                                               ret = EXIT_FAILURE;
+                                       }
+                               }
+                               free(full_name_inc);
+                       } else {
+                               rdev = (major << 8) + minor;
+                               if (mknod(full_name, mode, rdev) == -1) {
+                                       bb_perror_msg("Couldnt create node %s", full_name);
+                                       ret = EXIT_FAILURE;
+                               }
+                               else if (chown(full_name, uid, gid) == -1) {
+                                       bb_perror_msg("chown failed for %s", full_name);
+                                       ret = EXIT_FAILURE;
+                               }
+                       }
+               }
+loop:
+               free(line);
+               free(full_name);
+       }
+       fclose(table);
+
+       return 0;
 }
-*/
+#else
+# error makdedevs configuration error, either leaf or table must be selected
+#endif
diff --git a/patches/makdevs_table.diff b/patches/makdevs_table.diff
new file mode 100644 (file)
index 0000000..1041608
--- /dev/null
@@ -0,0 +1,294 @@
+Index: include/usage.h
+===================================================================
+RCS file: /var/cvs/busybox/include/usage.h,v
+retrieving revision 1.211
+diff -u -r1.211 usage.h
+--- a/include/usage.h  26 May 2004 22:09:37 -0000      1.211
++++ b/include/usage.h  5 Jun 2004 07:51:26 -0000
+@@ -1536,6 +1536,7 @@
+ #define lsmod_full_usage \
+       "List the currently loaded kernel modules."
++#ifdef CONFIG_FEATURE_MAKEDEVS_LEAF
+ #define makedevs_trivial_usage \
+       "NAME TYPE MAJOR MINOR FIRST LAST [s]"
+ #define makedevs_full_usage \
+@@ -1555,6 +1556,18 @@
+       "[creates ttyS2-ttyS63]\n" \
+       "# makedevs /dev/hda b 3 0 0 8 s\n" \
+       "[creates hda,hda1-hda8]\n"
++#endif
++
++#ifdef CONFIG_FEATURE_MAKEDEVS_TABLE
++#define makedevs_trivial_usage \
++      "[-r rootdir] [device_table]"
++#define makedevs_full_usage \
++      "Creates a batch of special files as specified in a device table\n" \
++      "The device table has one line per device group, each group is of\n" \
++      "the format\n" \
++      "\ttype mode user group major minor start increment count\n" \
++      "a '-' may be used for blank entries\n"
++#endif
+ #ifdef CONFIG_FEATURE_MD5_SHA1_SUM_CHECK
+ #define USAGE_MD5_SHA1_SUM_CHECK(a) a
+Index: miscutils/Config.in
+===================================================================
+RCS file: /var/cvs/busybox/miscutils/Config.in,v
+retrieving revision 1.14
+diff -u -r1.14 Config.in
+--- a/miscutils/Config.in      15 Mar 2004 08:28:46 -0000      1.14
++++ b/miscutils/Config.in      5 Jun 2004 07:51:26 -0000
+@@ -143,10 +143,32 @@
+       bool "makedevs"
+       default n
+       help
+-        'makedevs' is a utility used and created by the Linux Router Project.
+-        It creates a large number of device special files (/dev devices)
+-        rather quickly, and can be considerably faster then running mknod a
+-        zillion times.
++        'makedevs' is a utility used to create a batch of devices with
++        one command.
++        .
++        There are two choices for command line behaviour, the interface
++        as used by LEAF/Linux Router Project, or a device table file.
++        . 
++        'leaf' is traditionally what busybox follows, it allows multiple
++        devices of a particluar type to be created per command.
++        e.g. /dev/hda[0-9]
++          Device properties are passed as command line arguments.
++        .
++        'table' reads device properties from a file or stdin, allowing
++        a batch of unrelated devices to be makde with one command. 
++          User/group names are allowed as an alternative to uid/gid.
++
++choice
++      prompt "Choose makedevs behaviour"
++      default CONFIG_FEATURE_MAKDEVS_TABLE
++
++config CONFIG_FEATURE_MAKEDEVS_LEAF
++        bool "leaf"
++
++config CONFIG_FEATURE_MAKEDEVS_TABLE
++      bool "table"
++
++endchoice
+ config CONFIG_MT
+       bool "mt"
+Index: miscutils/makedevs.c
+===================================================================
+RCS file: /var/cvs/busybox/miscutils/makedevs.c,v
+retrieving revision 1.16
+diff -u -r1.16 makedevs.c
+--- a/miscutils/makedevs.c     15 Mar 2004 08:28:46 -0000      1.16
++++ b/miscutils/makedevs.c     5 Jun 2004 07:51:26 -0000
+@@ -1,20 +1,27 @@
+ /* vi: set sw=4 ts=4: */
+-/*
+- * public domain -- Dave 'Kill a Cop' Cinege <dcinege@psychosis.com>
+- *
+- * makedevs
+- * Make ranges of device files quickly.
+- * known bugs: can't deal with alpha ranges
+- */
++#include <sys/types.h>
++
++#include <fcntl.h>
++#include <getopt.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+-#include <fcntl.h>
++#include <time.h>
+ #include <unistd.h>
+-#include <sys/types.h>
++
+ #include "busybox.h"
++#ifdef CONFIG_FEATURE_MAKEDEVS_LEAF
++
++/*
++ * public domain -- Dave 'Kill a Cop' Cinege <dcinege@psychosis.com>
++ *
++ * makedevs
++ * Make ranges of device files quickly.
++ * known bugs: can't deal with alpha ranges
++ */
++ 
+ int makedevs_main(int argc, char **argv)
+ {
+       mode_t mode;
+@@ -69,24 +76,153 @@
+       return 0;
+ }
++#elif defined CONFIG_FEATURE_MAKEDEVS_TABLE
++
+ /*
+-And this is what this program replaces. The shell is too slow!
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ *
++ *  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 Library General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ */
++
++static const struct option makedevs_long_options[] = {
++      {"root", 1, NULL, 'r'},
++      {0, 0, 0, 0}
++};
+-makedev () {
+-local basedev=$1; local S=$2; local E=$3
+-local major=$4; local Sminor=$5; local type=$6
+-local sbase=$7
+-
+-      if [ ! "$sbase" = "" ]; then
+-              mknod "$basedev" $type $major $Sminor
+-              S=`expr $S + 1`
+-              Sminor=`expr $Sminor + 1`
+-      fi
+-
+-      while [ $S -le $E ]; do
+-              mknod "$basedev$S" $type $major $Sminor
+-              S=`expr $S + 1`
+-              Sminor=`expr $Sminor + 1`
+-      done
++extern int makedevs_main(int argc, char **argv)
++{
++      FILE *table;
++      int opt;
++      char *rootdir = "./";
++      char *line;
++      int ret = EXIT_SUCCESS;
++
++      bb_opt_complementaly = "d~r";
++      bb_applet_long_options = makedevs_long_options;
++      opt = bb_getopt_ulflags(argc, argv, "d:r:", &rootdir, &rootdir);
++
++      if (optind + 1 == argc) {
++              table = bb_xfopen(argv[optind], "r");
++      } else {
++              table = stdin;
++      }
++
++      if (chdir(rootdir) == -1) {
++              bb_perror_msg_and_die("Couldnt chdor to %s", rootdir);
++      }
++
++      umask(0);
++
++      while ((line = bb_get_chomped_line_from_file(table))) {
++              char type;
++              unsigned int mode = 0755;
++              unsigned int major = 0;
++              unsigned int minor = 0;
++              unsigned int count = 0;
++              unsigned int increment = 0;
++              unsigned int start = 0;
++              char name[41];
++              char user[41];
++              char group[41];
++              char *full_name;
++              uid_t uid;
++              gid_t gid;
++
++              if ((2 > sscanf(line, "%40s %c %o %40s %40s %u %u %u %u %u", name,
++                      &type, &mode, user, group, &major,
++                      &minor, &start, &increment, &count)) ||
++                      ((major | minor | start | count | increment) > 255)) {
++                      bb_error_msg("Ignoring invalid line\n%s\n", line);
++                      ret = EXIT_FAILURE;
++                      continue;
++              }
++              if (name[0] == '#') {
++                      continue;
++              }
++              if (group) {
++                      gid = get_ug_id(group, my_getgrnam);
++              } else {
++                      gid = getgid();
++              }
++              if (user) {
++                      uid = get_ug_id(user, my_getpwnam);
++              } else {
++                      uid = getuid();
++              }
++              full_name = concat_path_file(rootdir, name);
++
++              if (type == 'd') {
++                      bb_make_directory(full_name, mode | S_IFDIR, 0);
++                      if (chown(full_name, uid, gid) == -1) {
++                              bb_perror_msg("chown failed for %s", full_name);
++                              ret = EXIT_FAILURE;
++                              goto loop;
++                      }
++              } else {
++                      dev_t rdev;
++
++                      if (type == 'p') {
++                              mode |= S_IFIFO;
++                      }
++                      else if (type == 'c') {
++                              mode |= S_IFCHR;
++                      }
++                      else if (type == 'b') {
++                              mode |= S_IFBLK;
++                      } else {
++                              bb_error_msg("Unsupported file type %c", type);
++                              ret = EXIT_FAILURE;
++                              goto loop;
++                      }
++
++                      if (count > 0) {
++                              int i;
++                              char *full_name_inc;
++
++                              full_name_inc = xmalloc(strlen(full_name) + 4);
++                              for (i = start; i < count; i++) {
++                                      sprintf(full_name_inc, "%s%d", full_name, i);
++                                      rdev = (major << 8) + minor + (i * increment - start);
++                                      if (mknod(full_name_inc, mode, rdev) == -1) {
++                                              bb_perror_msg("Couldnt create node %s", full_name_inc);
++                                              ret = EXIT_FAILURE;
++                                      }
++                                      else if (chown(full_name_inc, uid, gid) == -1) {
++                                              bb_perror_msg("chown failed for %s", full_name_inc);
++                                              ret = EXIT_FAILURE;
++                                      }
++                              }
++                              free(full_name_inc);
++                      } else {
++                              rdev = (major << 8) + minor;
++                              if (mknod(full_name, mode, rdev) == -1) {
++                                      bb_perror_msg("Couldnt create node %s", full_name);
++                                      ret = EXIT_FAILURE;
++                              }
++                              else if (chown(full_name, uid, gid) == -1) {
++                                      bb_perror_msg("chown failed for %s", full_name);
++                                      ret = EXIT_FAILURE;
++                              }
++                      }
++              }
++loop:
++              free(line);
++              free(full_name);
++      }
++      fclose(table);
++
++      return 0;
+ }
+-*/
++#else
++# error makdedevs configuration error, either leaf or table must be selected
++#endif