summaryrefslogtreecommitdiffstats
path: root/mount/mount_by_label.c
diff options
context:
space:
mode:
Diffstat (limited to 'mount/mount_by_label.c')
-rw-r--r--mount/mount_by_label.c143
1 files changed, 143 insertions, 0 deletions
diff --git a/mount/mount_by_label.c b/mount/mount_by_label.c
new file mode 100644
index 000000000..a48c9de19
--- /dev/null
+++ b/mount/mount_by_label.c
@@ -0,0 +1,143 @@
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "sundries.h" /* for xstrdup */
+#include "linux_fs.h"
+#include "mount_by_label.h"
+
+#define PROC_PARTITIONS "/proc/partitions"
+#define DEVLABELDIR "/dev"
+
+static FILE *procpt;
+
+static void
+procptclose(void) {
+ if (procpt)
+ fclose (procpt);
+ procpt = 0;
+}
+
+static int
+procptopen(void) {
+ return ((procpt = fopen(PROC_PARTITIONS, "r")) != NULL);
+}
+
+static char *
+procptnext(void) {
+ char line[100];
+ char *s;
+ int ma, mi, sz;
+ static char ptname[100];
+
+ while (fgets(line, sizeof(line), procpt)) {
+ if (sscanf (line, " %d %d %d %[^\n]\n", &ma, &mi, &sz, ptname) != 4)
+ continue;
+
+ /* skip extended partitions (heuristic: size 1) */
+ if (sz == 1)
+ continue;
+
+ /* skip entire disk (minor 0, 64, ... on ide; 0, 16, ... on sd) */
+ /* heuristic: partition name ends in a digit */
+ for(s = ptname; *s; s++);
+ if (isdigit(s[-1]))
+ return ptname;
+ }
+ return 0;
+}
+
+#define UUID 1
+#define VOL 2
+
+/* for now, only ext2 is supported */
+static int
+has_right_label(const char *device, int n, const char *label) {
+
+ /* start with a test for ext2, taken from mount_guess_fstype */
+ /* should merge these later */
+ int fd;
+ char *s;
+ struct ext2_super_block e2sb;
+
+ fd = open(device, O_RDONLY);
+ if (fd < 0)
+ return 0;
+
+ if (lseek(fd, 1024, SEEK_SET) != 1024
+ || read(fd, (char *) &e2sb, sizeof(e2sb)) != sizeof(e2sb)
+ || (ext2magic(e2sb) != EXT2_SUPER_MAGIC)) {
+ close(fd);
+ return 0;
+ }
+
+ close(fd);
+
+ /* superblock is ext2 - now what is its label? */
+ s = ((n == UUID) ? e2sb.s_uuid : e2sb.s_volume_name);
+ return (strncmp(s, label, 16) == 0);
+}
+
+static char *
+get_spec_by_x(int n, const char *t) {
+ char *pt;
+ char device[110];
+
+ if(!procptopen())
+ return NULL;
+ while((pt = procptnext()) != NULL) {
+ /* Note: this is a heuristic only - there is no reason
+ why these devices should live in /dev.
+ Perhaps this directory should be specifiable by option.
+ One might for example have /devlabel with links to /dev
+ for the devices that may be accessed in this way.
+ (This is useful, if the cdrom on /dev/hdc must not
+ be accessed.)
+ */
+ sprintf(device, "%s/%s", DEVLABELDIR, pt);
+ if (has_right_label(device, n, t)) {
+ procptclose();
+ return xstrdup(device);
+ }
+ }
+ procptclose();
+ return NULL;
+}
+
+static u_char
+fromhex(char c) {
+ if (isdigit(c))
+ return (c - '0');
+ else if (islower(c))
+ return (c - 'a' + 10);
+ else
+ return (c - 'A' + 10);
+}
+
+char *
+get_spec_by_uuid(const char *s) {
+ u_char uuid[16];
+ int i;
+
+ if (strlen(s) != 36 ||
+ s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-')
+ goto bad_uuid;
+ for (i=0; i<16; i++) {
+ if (*s == '-') s++;
+ if (!isxdigit(s[0]) || !isxdigit(s[1]))
+ goto bad_uuid;
+ uuid[i] = ((fromhex(s[0])<<4) | fromhex(s[1]));
+ s += 2;
+ }
+ return get_spec_by_x(UUID, uuid);
+
+ bad_uuid:
+ die(EX_USAGE, "mount: bad UUID");
+}
+
+char *
+get_spec_by_volume_label(const char *s) {
+ return get_spec_by_x(VOL, s);
+}
+