changeset 114:ce6956dfc0cf

Add sync and an incomplete version of mdev.
author Rob Landley <rob@landley.net>
date Mon, 23 Apr 2007 15:45:55 -0400
parents 1f7dcdef245c
children 19b5567f0a1b
files lib/xregcomp.c lib/xregcomp.h toys.h toys/Config.in toys/mdev.c toys/sync.c toys/toylist.h www/design.html
diffstat 8 files changed, 272 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/xregcomp.c	Mon Apr 23 15:45:55 2007 -0400
@@ -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);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/xregcomp.h	Mon Apr 23 15:45:55 2007 -0400
@@ -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);
--- a/toys.h	Wed Apr 18 21:41:38 2007 -0400
+++ b/toys.h	Mon Apr 23 15:45:55 2007 -0400
@@ -14,8 +14,10 @@
 #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>
--- a/toys/Config.in	Wed Apr 18 21:41:38 2007 -0400
+++ b/toys/Config.in	Mon Apr 23 15:45:55 2007 -0400
@@ -83,6 +83,28 @@
 	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 @@
 
 	  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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/toys/mdev.c	Mon Apr 23 15:45:55 2007 -0400
@@ -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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/toys/sync.c	Mon Apr 23 15:45:55 2007 -0400
@@ -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;
+}
--- a/toys/toylist.h	Wed Apr 18 21:41:38 2007 -0400
+++ b/toys/toylist.h	Mon Apr 23 15:45:55 2007 -0400
@@ -95,6 +95,7 @@
 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))
--- a/www/design.html	Wed Apr 18 21:41:38 2007 -0400
+++ b/www/design.html	Mon Apr 23 15:45:55 2007 -0400
@@ -208,7 +208,7 @@
 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>