From 6507240b2fcfebaacc0f92f997dad76922e1d8c0 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Wed, 5 Aug 2009 19:37:53 -0700 Subject: [PATCH] DEVTAB - Add mountroot & fstab support for serial numbers, and devtab. * The vfs.root.mountfrom /boot/loader.conf variable may now specify devfs aliases, allowing it to specify root mounts by serial number. Here is an example: vfs.root.mountfrom="hammer:serno/L41JYE0G.s1d" Note that vfs.root.mountfrom may NOT currently specify /etc/devtab labels. * /etc/fstab may now specify devfs relative paths (such as serial numbers) as well as /etc/devtab labels. A ".suffix" may be used to extend the translation so /etc/devtab only needs to specify the base label. Example /etc/fstab: # Device Mountpoint FStype Options Dump Pass # driveA.s1d / hammer rw 1 1 driveA.s1b none swap sw 0 0 driveA.s1a /boot ufs rw 1 1 serno/L41JYE0G.s1d /fubar hammer rw 1 1 /etc/devtab: driveA serno L41JYE0G --- include/fstab.h | 5 +++ lib/libc/gen/Makefile.inc | 4 +- lib/libc/gen/fstab.c | 16 ++++++- lib/{libutil => libc/gen}/getdevpath.3 | 4 +- lib/{libutil => libc/gen}/getdevpath.c | 62 +++++++++++++++++++++----- lib/libutil/Makefile | 6 +-- lib/libutil/libutil.h | 5 --- sbin/getdevpath/Makefile | 1 - sbin/getdevpath/getdevpath.c | 2 +- share/man/man5/fstab.5 | 7 ++- sys/boot/common/loader.8 | 3 ++ sys/kern/vfs_conf.c | 51 +-------------------- sys/vfs/devfs/devfs_core.c | 17 +++++-- 13 files changed, 101 insertions(+), 82 deletions(-) rename lib/{libutil => libc/gen}/getdevpath.3 (99%) rename lib/{libutil => libc/gen}/getdevpath.c (79%) diff --git a/include/fstab.h b/include/fstab.h index 258078d9bf..9b450193ce 100644 --- a/include/fstab.h +++ b/include/fstab.h @@ -68,6 +68,10 @@ struct fstab { int fs_passno; /* pass number on parallel fsck */ }; +/* getdevpath(3) */ +#define _HAVE_GETDEVPATH 1 /* allow code conditionalization */ +#define GETDEVPATH_RAWDEV 0x0001 + #include __BEGIN_DECLS @@ -78,6 +82,7 @@ struct fstab *getfsspec(const char *); const char *getfstab(void); int setfsent(void); void setfstab(const char *); +char *getdevpath(const char *devname, int flags); __END_DECLS #endif /* !_FSTAB_H_ */ diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc index c0483a5bff..3c1c162a9c 100644 --- a/lib/libc/gen/Makefile.inc +++ b/lib/libc/gen/Makefile.inc @@ -12,7 +12,8 @@ SRCS+= _pthread_stubs.c _rand48.c _spinlock_stub.c _thread_init.c \ dlfcn.c dlfunc.c drand48.c erand48.c err.c errlst.c exec.c \ fdevname.c fmtcheck.c fmtmsg.c fnmatch.c fpclassifyd.c fpclassifyf.c \ frexp.c fstab.c ftok.c fts.c ftw.c getbootfile.c getbsize.c \ - getcap.c getcwd.c getdomainname.c getgrent.c getgrouplist.c \ + getcap.c getcwd.c getdevpath.c getdomainname.c \ + getgrent.c getgrouplist.c \ gethostname.c getloadavg.c getlogin.c getmntinfo.c getmntvinfo.c \ getnetgrent.c getobjformat.c getosreldate.c getpagesize.c \ getpeereid.c getprogname.c getpwent.c getttyent.c \ @@ -53,6 +54,7 @@ MAN+= alarm.3 arc4random.3 clock.3 \ err.3 exec.3 fdevname.3 \ fmtcheck.3 fmtmsg.3 fnmatch.3 fpclassify.3 frexp.3 ftok.3 fts.3 ftw.3 \ getbootfile.3 getbsize.3 getcap.3 getcontext.3 getcwd.3 \ + getdevpath.3 \ getdiskbyname.3 getdisktabbyname.3 getdomainname.3 getfsent.3 \ getgrent.3 getgrouplist.3 gethostname.3 getloadavg.3 \ getmntinfo.3 getnetgrent.3 getobjformat.3 getosreldate.3 \ diff --git a/lib/libc/gen/fstab.c b/lib/libc/gen/fstab.c index 9d7bea1b5a..e057b8eb4b 100644 --- a/lib/libc/gen/fstab.c +++ b/lib/libc/gen/fstab.c @@ -46,6 +46,7 @@ #include "un-namespace.h" static FILE *_fs_fp; +static char *_fs_spec; /* allocated via getdevpath() */ static struct fstab _fs_fstab; static int LineNo = 0; static char *path_fstab; @@ -55,6 +56,7 @@ static int fsp_set = 0; static void error(int); static void fixfsfile(void); static int fstabscan(void); +static char *gdplookup(char *spec); void setfstab(const char *file) @@ -120,7 +122,7 @@ fstabscan(void) if (*line == '#' || *line == '\n') continue; if (!strpbrk(p, " \t")) { - _fs_fstab.fs_spec = strsep(&p, ":\n"); + _fs_fstab.fs_spec = gdplookup(strsep(&p, ":\n")); _fs_fstab.fs_file = strsep(&p, ":\n"); fixfsfile(); _fs_fstab.fs_type = strsep(&p, ":\n"); @@ -147,6 +149,7 @@ fstabscan(void) _fs_fstab.fs_spec = cp; if (!_fs_fstab.fs_spec || *_fs_fstab.fs_spec == '#') continue; + _fs_fstab.fs_spec = gdplookup(_fs_fstab.fs_spec); while ((cp = strsep(&p, " \t\n")) != NULL && *cp == '\0') ; _fs_fstab.fs_file = cp; @@ -270,6 +273,17 @@ endfsent(void) fsp_set = 0; } +static char * +gdplookup(char *spec) +{ + if (_fs_spec) + free(_fs_spec); + _fs_spec = getdevpath(spec, 0); + if (strcmp(_fs_spec, spec) != 0) + spec = _fs_spec; + return(spec); +} + static void error(int err) { diff --git a/lib/libutil/getdevpath.3 b/lib/libc/gen/getdevpath.3 similarity index 99% rename from lib/libutil/getdevpath.3 rename to lib/libc/gen/getdevpath.3 index fa746207ac..11d2468205 100644 --- a/lib/libutil/getdevpath.3 +++ b/lib/libc/gen/getdevpath.3 @@ -38,10 +38,10 @@ .Nm getdevpath .Nd retrieve device path given name or label .Sh LIBRARY -.Lb libutil +.Lb libc .Sh SYNOPSIS .In sys/types.h -.In libutil.h +.In fstab.h .Ft char * .Fn getdevpath "const char *devname" "int flags" .Sh DESCRIPTION diff --git a/lib/libutil/getdevpath.c b/lib/libc/gen/getdevpath.c similarity index 79% rename from lib/libutil/getdevpath.c rename to lib/libc/gen/getdevpath.c index b2f7c5250d..62f0def920 100644 --- a/lib/libutil/getdevpath.c +++ b/lib/libc/gen/getdevpath.c @@ -63,16 +63,14 @@ getdevpath(const char *devname, int flags) if (devname[0] == '/' || devname[0] == '.') { asprintf(&path, "%s", devname); - } else if ((ptr = strchr(devname, ':')) != NULL) { - asprintf(&path, "/dev/%*.*s/%s", - ptr - devname, ptr - devname, devname, - ptr + 1); } else { asprintf(&path, "/dev/%s", devname); if (lstat(path, &st) < 0) { free(path); path = NULL; finddevlabel(&path, devname); + if (path == NULL) + asprintf(&path, "%s", devname); } else { stgood = 1; } @@ -104,25 +102,65 @@ finddevlabel(char **pathp, const char *devname) { const char *prefix = _PATH_DEVTAB_PATHS; const char *ptr1; - const char *ptr2; + const char *trailer; + char *label; + char *ptr2; char *ptr3; char *dtpath; char *bufp; char buf[256]; FILE *fp; - size_t len; + size_t len; /* directory prefix length */ + size_t dlen; /* devname length */ + size_t tlen; /* devname length without trailer */ + + dlen = strlen(devname); + if ((trailer = strrchr(devname, '.')) != NULL) + tlen = trailer - devname; + else + tlen = 0; while (*prefix && *pathp == NULL) { + /* + * Directory search path + */ ptr1 = strchr(prefix, ':'); len = (ptr1) ? (size_t)(ptr1 - prefix) : strlen(prefix); asprintf(&dtpath, "%*.*s/devtab", len, len, prefix); + + /* + * Each devtab file + */ if ((fp = fopen(dtpath, "r")) != NULL) { while (fgets(buf, sizeof(buf), fp) != NULL) { - ptr1 = strtok_r(buf, " \t\r\n", &bufp); - if (ptr1 == NULL || *ptr1 == 0 || *ptr1 == '#') + /* + * Extract label field, check degenerate + * cases. + */ + label = strtok_r(buf, " \t\r\n", &bufp); + if (label == NULL || *label == 0 || + *label == '#') { continue; - if (strcmp(devname, ptr1) != 0) + } + + /* + * Match label, with or without the + * trailer (aka ".s1a"). The trailer + * is tacked on if the match is without + * the trailer. + */ + if (strcmp(devname, label) == 0) { + trailer = ""; + } else if (tlen && strlen(label) == tlen && + strncmp(devname, label, tlen) == 0) { + trailer = devname + tlen; + } else { continue; + } + + /* + * Match, extract and process remaining fields. + */ ptr2 = strtok_r(NULL, " \t\r\n", &bufp); ptr3 = strtok_r(NULL, " \t\r\n", &bufp); if (ptr2 == NULL || ptr3 == NULL) @@ -131,10 +169,10 @@ finddevlabel(char **pathp, const char *devname) continue; ptr3 = dodequote(ptr3); if (strcmp(ptr2, "path") == 0) { - asprintf(pathp, "%s", ptr3); + asprintf(pathp, "%s%s", ptr3, trailer); } else { - asprintf(pathp, "/dev/%s/%s", - ptr2, ptr3); + asprintf(pathp, "/dev/%s/%s%s", + ptr2, ptr3, trailer); } break; } diff --git a/lib/libutil/Makefile b/lib/libutil/Makefile index 9d033c5d8d..9f8db8ee57 100644 --- a/lib/libutil/Makefile +++ b/lib/libutil/Makefile @@ -10,8 +10,7 @@ SRCS= flopen.c login.c login_tty.c logout.c logwtmp.c pty.c \ login_cap.c login_class.c login_auth.c login_times.c login_ok.c \ login_crypt.c _secure_path.c uucplock.c property.c auth.c \ realhostname.c fparseln.c stub.c pidfile.c trimdomain.c \ - dehumanize_number.c humanize_number.c pw_util.c \ - getdevpath.c + dehumanize_number.c humanize_number.c pw_util.c INCS= libutil.h login_cap.h WARNS?= 3 @@ -21,8 +20,7 @@ MAN+= flopen.3 login.3 login_auth.3 login_tty.3 logout.3 logwtmp.3 pty.3 \ login_cap.3 login_class.3 login_times.3 login_ok.3 \ _secure_path.3 uucplock.3 property.3 auth.3 realhostname.3 \ realhostname_sa.3 trimdomain.3 fparseln.3 pidfile.3 \ - humanize_number.3 \ - getdevpath.3 + humanize_number.3 MAN+= login.conf.5 auth.conf.5 MLINKS+= property.3 properties_read.3 property.3 properties_free.3 MLINKS+= property.3 property_find.3 diff --git a/lib/libutil/libutil.h b/lib/libutil/libutil.h index b90d7d2226..e00676c37d 100644 --- a/lib/libutil/libutil.h +++ b/lib/libutil/libutil.h @@ -103,7 +103,6 @@ struct passwd *pw_scan(const char *_line, int _flags); const char *pw_tempname(void); int pw_tmp(int _mfd); #endif -char *getdevpath(const char *devname, int flags); __END_DECLS #define UU_LOCK_INUSE (1) @@ -141,8 +140,4 @@ __END_DECLS #define HN_GETSCALE 0x10 #define HN_AUTOSCALE 0x20 -/* getdevpath(3) */ -#define _HAVE_GETDEVPATH 1 /* allow code conditionalization */ -#define GETDEVPATH_RAWDEV 0x0001 - #endif /* !_LIBUTIL_H_ */ diff --git a/sbin/getdevpath/Makefile b/sbin/getdevpath/Makefile index 82922e52cd..e19b1524ea 100644 --- a/sbin/getdevpath/Makefile +++ b/sbin/getdevpath/Makefile @@ -1,7 +1,6 @@ # Makefile for getdevpath # PROG= getdevpath -LDADD= -lutil MAN= getdevpath.8 .include diff --git a/sbin/getdevpath/getdevpath.c b/sbin/getdevpath/getdevpath.c index 126b7b71a1..359c258e85 100644 --- a/sbin/getdevpath/getdevpath.c +++ b/sbin/getdevpath/getdevpath.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include static void usage(void); diff --git a/share/man/man5/fstab.5 b/share/man/man5/fstab.5 index b3ddd0ce4b..d419442a03 100644 --- a/share/man/man5/fstab.5 +++ b/share/man/man5/fstab.5 @@ -66,7 +66,12 @@ doing their thing. The first field, .Pq Fa fs_spec , describes the special file or -remote file system to be mounted. +remote file system to be mounted. This may be a /dev/, a label +from a devtab (typically /etc/devtab), or a host:path for NFS. +Note that devtab labels maybe augmented with a ".suffix" trailer. For +example "mydisk.s1a". +Also note /dev based paths can mount serial numbers similar to devtab +labels by using the path "/dev/serno/SERIALNO[.suffix]". .Pp The second field, .Pq Fa fs_file , diff --git a/sys/boot/common/loader.8 b/sys/boot/common/loader.8 index 82be916382..b74adce63d 100644 --- a/sys/boot/common/loader.8 +++ b/sys/boot/common/loader.8 @@ -545,6 +545,9 @@ for kernel root file system. Used with boot-only partition, which is typically mounted on root file system as .Pa /boot . Example: "hammer:da8s1a" +.Pp +You may not specify devtab labels here but you can specify paths available +to devfs such as "hammer:serno/L41JYE0G.s1d". .El .Ss BUILTIN PARSER When a builtin command is executed, the rest of the line is taken diff --git a/sys/kern/vfs_conf.c b/sys/kern/vfs_conf.c index f03ccca41d..4a6d81817c 100644 --- a/sys/kern/vfs_conf.c +++ b/sys/kern/vfs_conf.c @@ -547,8 +547,6 @@ cdev_t kgetdiskbyname(const char *name) { char *cp; - int nlen; - int unit, slice, part; cdev_t rdev; /* @@ -557,58 +555,11 @@ kgetdiskbyname(const char *name) if (strncmp(name, __SYS_PATH_DEV, sizeof(__SYS_PATH_DEV) - 1) == 0) name += sizeof(__SYS_PATH_DEV) - 1; cp = __DECONST(char *, name); - while (*cp == '/') - ++cp; - while (*cp >= 'a' && *cp <= 'z') - ++cp; - if (cp == name) { - kprintf("missing device name\n"); - return (NULL); - } - nlen = cp - name; - - /* - * Get the unit. - */ - unit = strtol(cp, &cp, 10); - if (name + nlen == (const char *)cp || unit < 0 || unit >= DKMAXUNITS) { - kprintf("bad unit: %d\n", unit); - return (NULL); - } - - /* - * Get the slice. Note that if no partition or partition 'a' is - * specified, and no slice is specified, we will try both 'ad0a' - * (which is what you get when slice is 0), and also 'ad0' (the - * whole-disk partition, slice == 1). - */ - if (*cp == 's') { - slice = cp[1] - '0'; - if (slice >= 1) - ++slice; - cp += 2; - } else { - slice = 0; - } - - /* - * Get the partition. - */ - if (*cp >= 'a' && *cp <= 'p') { - part = *cp - 'a'; - ++cp; - } else { - part = 0; - } - - if (*cp != '\0') { - kprintf("junk after name: %s\n", cp); - return (NULL); - } /* * Locate the device */ + kprintf("tryroot %s\n", name); rdev = devfs_find_device_by_name(name); if (rdev == NULL) { kprintf("no disk named '%s'\n", name); diff --git a/sys/vfs/devfs/devfs_core.c b/sys/vfs/devfs/devfs_core.c index c87ef056eb..324cd377fa 100644 --- a/sys/vfs/devfs/devfs_core.c +++ b/sys/vfs/devfs/devfs_core.c @@ -1401,15 +1401,24 @@ devfs_chandler_del_worker(char *name) static int devfs_find_device_by_name_worker(devfs_msg_t devfs_msg) { - cdev_t dev, dev1; + struct devfs_alias *alias; + cdev_t dev; cdev_t found = NULL; - TAILQ_FOREACH_MUTABLE(dev, &devfs_dev_list, link, dev1) { - if (!strcmp(devfs_msg->mdv_name, dev->si_name)) { + TAILQ_FOREACH(dev, &devfs_dev_list, link) { + if (strcmp(devfs_msg->mdv_name, dev->si_name) == 0) { found = dev; break; } } + if (found == NULL) { + TAILQ_FOREACH(alias, &devfs_alias_list, link) { + if (strcmp(devfs_msg->mdv_name, alias->name) == 0) { + found = alias->dev_target; + break; + } + } + } devfs_msg->mdv_cdev = found; return 0; @@ -1450,7 +1459,7 @@ devfs_make_alias_worker(struct devfs_alias *alias) int found = 0; TAILQ_FOREACH(alias2, &devfs_alias_list, link) { - if (!memcmp(alias->name, alias2->name, len)) { + if (!memcmp(alias->name, alias2->name, len)) { /* XXX */ found = 1; break; } -- 2.41.0