]> git.ipfire.org Git - people/teissler/ipfire-2.x.git/blobdiff - src/nash/name_to_dev_t.c
GD-Graph fuer Maniac eingebaut
[people/teissler/ipfire-2.x.git] / src / nash / name_to_dev_t.c
diff --git a/src/nash/name_to_dev_t.c b/src/nash/name_to_dev_t.c
new file mode 100644 (file)
index 0000000..e882804
--- /dev/null
@@ -0,0 +1,139 @@
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+static dev_t try_name(char *name, int part)
+{
+       char path[64];
+       char buf[32];
+       int range;
+       dev_t res;
+       char *s;
+       int len;
+       int fd;
+       unsigned int maj, min;
+
+       /* read device number from .../dev */
+
+       sprintf(path, "/sys/block/%s/dev", name);
+       fd = open(path, O_RDONLY);
+       if (fd < 0)
+               goto fail;
+       len = read(fd, buf, 32);
+       close(fd);
+       if (len <= 0 || len == 32 || buf[len - 1] != '\n')
+               goto fail;
+       buf[len - 1] = '\0';
+       if (sscanf(buf, "%u:%u", &maj, &min) != 2)
+               goto fail;
+       res = makedev(maj, min);
+       if (maj != major(res) || min != minor(res))
+               goto fail;
+
+       /* if it's there and we are not looking for a partition - that's it */
+       if (!part)
+               return res;
+
+       /* otherwise read range from .../range */
+       snprintf(path, 64, "/sys/block/%s/range", name);
+       fd = open(path, O_RDONLY);
+       if (fd < 0)
+               goto fail;
+       len = read(fd, buf, 32);
+       close(fd);
+       if (len <= 0 || len == 32 || buf[len - 1] != '\n')
+               goto fail;
+       buf[len - 1] = '\0';
+       range = strtoul(buf, &s, 10);
+       if (*s)
+               goto fail;
+
+       /* if partition is within range - we got it */
+       if (part < range)
+               return res + part;
+fail:
+       return 0;
+}
+
+/*
+ *     Convert a name into device number.  We accept the following variants:
+ *
+ *     1) device number in hexadecimal represents itself
+ *     2) /dev/nfs represents Root_NFS (0xff)
+ *     3) /dev/<disk_name> represents the device number of disk
+ *     4) /dev/<disk_name><decimal> represents the device number
+ *         of partition - device number of disk plus the partition number
+ *     5) /dev/<disk_name>p<decimal> - same as the above, that form is
+ *        used when disk name of partitioned disk ends on a digit.
+ *
+ *     If name doesn't have fall into the categories above, we return 0.
+ *     sysfs is used to check if something is a disk name - it has
+ *     all known disks under bus/block/devices.  If the disk name
+ *     contains slashes, name of driverfs node has them replaced with
+ *     bangs.  try_name() does the actual checks, assuming that sysfs
+ *     is mounted on /sys.
+ *
+ *     Note that cases (1) and (2) are already handled by the kernel,
+ *     so we can ifdef them out, provided that we check real-root-dev
+ *     first.
+ */
+
+dev_t name_to_dev_t(char *name)
+{
+       char s[32];
+       char *p;
+       dev_t res = 0;
+       int part;
+
+       if (strncmp(name, "/dev/", 5) != 0) {
+#if 1 /* kernel used to do this */
+               unsigned maj, min;
+
+               if (sscanf(name, "%u:%u", &maj, &min) == 2) {
+                       res = makedev(maj, min);
+                       if (maj != major(res) || min != minor(res))
+                               return 0;
+               } else {
+                       res = strtoul(name, &p, 16);
+                       if (*p)
+                               return 0;
+               }
+#endif
+               return res;
+       }
+
+       name += 5;
+
+#if 1 /* kernel used to do this */
+       if (strcmp(name, "nfs") == 0)
+               return makedev(0, 255);
+#endif
+
+       if (strlen(name) > 31)
+               return 0;
+       strcpy(s, name);
+       for (p = s; *p; p++)
+               if (*p == '/')
+                       *p = '!';
+       res = try_name(s, 0);
+       if (res)
+               return res;
+
+       while (p > s && isdigit(p[-1]))
+               p--;
+       if (p == s || !*p || *p == '0')
+               return 0;
+       part = strtoul(p, NULL, 10);
+       *p = '\0';
+       res = try_name(s, part);
+       if (res)
+               return res;
+
+       if (p < s + 2 || !isdigit(p[-2]) || p[-1] != 'p')
+               return 0;
+       p[-1] = '\0';
+       return try_name(s, part);
+}