OSDN Git Service

Add sync and an incomplete version of mdev.
authorRob Landley <rob@landley.net>
Mon, 23 Apr 2007 19:45:55 +0000 (15:45 -0400)
committerRob Landley <rob@landley.net>
Mon, 23 Apr 2007 19:45:55 +0000 (15:45 -0400)
lib/xregcomp.c [new file with mode: 0644]
lib/xregcomp.h [new file with mode: 0644]
toys.h
toys/Config.in
toys/mdev.c [new file with mode: 0644]
toys/sync.c [new file with mode: 0644]
toys/toylist.h
www/design.html

diff --git a/lib/xregcomp.c b/lib/xregcomp.c
new file mode 100644 (file)
index 0000000..60446ef
--- /dev/null
@@ -0,0 +1,23 @@
+/* vi: set ts=4:
+ *  Call regcomp() and handle errors.
+ *
+ * Copyright 2007 Rob Landley <rob@landley.net>
+ *
+ * This is a separate file so environments that haven't got regular expression
+ * support can configure this out and avoid a build break.
+ */
+
+#include "toys.h"
+#include "xregcomp.h"
+
+void xregcomp(regex_t *preg, char *rexec, int cflags)
+{
+       int rc = regcomp(preg, rexec, cflags);
+
+       if (rc) {
+               char msg[256];
+               regerror(rc, preg, msg, 255);
+               msg[255]=0;
+               error_exit("xregcomp: %s", msg);
+       }
+}
diff --git a/lib/xregcomp.h b/lib/xregcomp.h
new file mode 100644 (file)
index 0000000..fa929fa
--- /dev/null
@@ -0,0 +1,6 @@
+/* This is a separate file so libc doesn't always need regex support. */
+
+#include <sys/types.h>
+#include <regex.h>
+
+void xregcomp(regex_t *preg, char *rexec, int cflags);
diff --git a/toys.h b/toys.h
index 3c6cec9..372944e 100644 (file)
--- a/toys.h
+++ b/toys.h
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <grp.h>
 #include <inttypes.h>
 #include <limits.h>
+#include <pwd.h>
 #include <setjmp.h>
 #include <stdarg.h>
 #include <stdint.h>
@@ -24,6 +26,7 @@
 #include <string.h>
 #include <strings.h>
 #include <sys/ioctl.h>
+#include <sys/mman.h>
 #include <sys/mount.h>
 #include <sys/stat.h>
 #include <sys/statvfs.h>
index 7768ec8..5634436 100644 (file)
@@ -83,6 +83,28 @@ config HELLO
        help
          A hello world program.  You don't need this.
 
+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 n
+       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.
+
 config MKE2FS
        bool "mke2fs"
        default n
@@ -172,6 +194,14 @@ config PWD
 
          The print working directory command prints the current directory.
 
+config SYNC
+       bool "sync"
+       default n
+       help
+         usage: sync
+
+         Write pending cached data to disk (synchronize), blocking until done.
+
 config TOUCH
        bool "touch"
        default n
diff --git a/toys/mdev.c b/toys/mdev.c
new file mode 100644 (file)
index 0000000..53be23e
--- /dev/null
@@ -0,0 +1,196 @@
+/* vi:set ts=4:
+ * 
+ * mdev - Mini udev for busybox
+ * 
+ * Copyright 2005 Rob Landley <rob@landley.net>
+ * Copyright 2005 Frank Sorenson <frank@tuxrocks.com>
+ */
+
+#include "toys.h"
+#include "lib/xregcomp.h"
+
+// 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 = path+strlen(path);
+       strcpy(temp, "/dev");
+       fd = open(path, O_RDONLY);
+       *temp=0;
+       temp++;
+       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 = lseek(fd, 0, SEEK_END);
+                       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 = strndupa(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);
+                                                               
+                                                               // 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;
+                                                                       pass = getpwnam(strndupa(pos, s-pos));
+                                                                       if (!pass) goto end_line;
+                                                                       uid = pass->pw_uid;
+                                                               }
+                                                               s++;
+                                                               // parse GID
+                                                               gid = strtoul(s,&s2,10);
+                                                               if (end2!=s2) {
+                                                                       struct group *grp;
+                                                                       grp = getgrnam(strndupa(s, end2-s));
+                                                                       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);
+       umask(0);
+       if (mknod(temp, mode | type, makedev(major, minor)) && errno != EEXIST)
+               perror_exit("mknod %s failed", temp);
+
+       if (CFG_MDEV_CONF) chown(temp, uid, gid);
+}
+
+// Recursive search of /sys/block or /sys/class.  path must be a writeable
+// buffer of size PATH_MAX containing the directory string to start at.
+
+static void find_dev(char *path)
+{
+       DIR *dir;
+       int len=strlen(path);
+
+       if (!(dir = opendir(path)))
+               perror_exit("No %s",path);
+
+       for (;;) {
+               struct dirent *entry = readdir(dir);
+               
+               if (!entry) break;
+
+               // Skip "." and ".." (also skips hidden files, which is ok)
+
+               if (entry->d_name[0]=='.') continue;
+
+               if (entry->d_type == DT_DIR) {
+                       snprintf(path+len, sizeof(toybuf)-len, "/%s", entry->d_name);
+                       find_dev(path);
+                       path[len] = 0;
+               }
+               
+               // If there's a dev entry, mknod it
+               
+               if (strcmp(entry->d_name, "dev")) make_device(path);
+       }
+       
+       closedir(dir);
+}
+
+int mdev_main(int argc, char *argv[])
+{
+       if (toys.optflags) {
+               strcpy(toybuf, "/sys/block");
+               find_dev(toybuf);
+               strcpy(toybuf, "/sys/class");
+               find_dev(toybuf);
+               return 0;
+       } 
+       
+       // hotplug support goes here
+       
+       return 0;
+}
diff --git a/toys/sync.c b/toys/sync.c
new file mode 100644 (file)
index 0000000..4918dc4
--- /dev/null
@@ -0,0 +1,12 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * sync.c - Write all pending data to disk.
+ */
+
+#include "toys.h"
+
+int sync_main(void)
+{
+       sync();
+       return 0;
+}
index b212215..d686877 100644 (file)
@@ -95,6 +95,7 @@ USE_MKE2FS(NEWTOY(mke2fs, MKE2FS_OPTSTRING, TOYFLAG_SBIN))
 USE_ONEIT(NEWTOY(oneit, "+<1p", TOYFLAG_SBIN))
 USE_PWD(NEWTOY(pwd, NULL, TOYFLAG_BIN))
 USE_TOYSH(OLDTOY(sh, toysh, "c:i", TOYFLAG_BIN))
+USE_SYNC(NEWTOY(sync, NULL, TOYFLAG_BIN))
 USE_TOUCH(NEWTOY(touch, "l#t:r:mca", TOYFLAG_BIN))
 USE_TOYSH(NEWTOY(toysh, "c:i", TOYFLAG_BIN))
 USE_WHICH(NEWTOY(which, "a", TOYFLAG_USR|TOYFLAG_BIN))
index 458d12f..0fe2b1a 100644 (file)
@@ -208,7 +208,7 @@ are always the same size (on both 32 and 64 bit).  Pointer and int are _not_
 the same size on 64 bit systems, but pointer and long are.</p>
 
 <p>This is guaranteed by the LP64 memory model, a Unix standard (which Linux
-and MacOS X implements).  See
+and MacOS X both implement).  See
 <a href=http://www.unix.org/whitepapers/64bit.html>the LP64 standard</a> and
 <a href=http://www.unix.org/version2/whatsnew/lp64_wp.html>the LP64
 rationale</a> for details.</p>