/* $NetBSD: getfsspecname.c,v 1.8 2018/12/27 21:35:48 alnsn Exp $ */ /*- * Copyright (c) 2012 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Christos Zoulas. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __RCSID("$NetBSD: getfsspecname.c,v 1.8 2018/12/27 21:35:48 alnsn Exp $"); #include #include #include #include #include #include #include #include #include #include #include #include #include #define COMPAT_DKWEDGE /* To be removed */ const char * getfsspecname(char *buf, size_t bufsiz, const char *name) { static const int mib[] = { CTL_HW, HW_DISKNAMES }; static const unsigned int miblen = __arraycount(mib); char *drives, *dk, *p; size_t len; int fd, savee = errno; char *vname; p = drives = vname = NULL; /* * If the name starts with "ROOT.", replace it with "/dev/", * where is the value of the kern.root_device sysctl. Any * characters after the special "ROOT." token are appended to the end * of this path. */ if (strncasecmp(name, "ROOT.", 5) == 0 && strchr(name, ':') == NULL) { static const int mib_root[] = { CTL_KERN, KERN_ROOT_DEVICE }; static const unsigned int mib_rootlen = __arraycount(mib_root); strlcpy(buf, "/dev/", bufsiz); len = bufsiz - 5; if (sysctl(mib_root, mib_rootlen, buf + 5, &len, NULL, 0) == -1) { savee = errno; strlcpy(buf, "sysctl kern.root_device failed", bufsiz); goto out; } strlcat(buf, name + 5, bufsiz); return buf; } if (strncasecmp(name, "NAME=", 5) != 0) { #ifdef COMPAT_DKWEDGE /* * We try to open the disk name, and if we fail with EBUSY * we use the name as the label to find the wedge. */ char rbuf[MAXPATHLEN]; if (name[0] == '/') { if (getdiskrawname(rbuf, sizeof(rbuf), name) != NULL) { if ((fd = open(rbuf, O_RDONLY)) == -1) { if (errno == EBUSY) { name = strrchr(name, '/') + 1; goto search; } } else close(fd); } } #endif strlcpy(buf, name, bufsiz); return buf; } else name += 5; #ifdef COMPAT_DKWEDGE search: #endif vname = malloc(strlen(name) + 1); if (vname == NULL) { savee = errno; strlcpy(buf, "malloc failed", bufsiz); goto out; } strunvis(vname, name); if (sysctl(mib, miblen, NULL, &len, NULL, 0) == -1) { savee = errno; strlcpy(buf, "sysctl hw.disknames failed", bufsiz); goto out; } drives = malloc(len); if (drives == NULL) { savee = errno; strlcpy(buf, "malloc failed", bufsiz); goto out; } if (sysctl(mib, miblen, drives, &len, NULL, 0) == -1) { savee = errno; strlcpy(buf, "sysctl hw.disknames failed", bufsiz); goto out; } for (dk = strtok(drives, " "); dk != NULL; dk = strtok(NULL, " ")) { struct dkwedge_info dkw; if (strncmp(dk, "dk", 2) != 0) continue; fd = opendisk(dk, O_RDONLY, buf, bufsiz, 0); if (fd == -1) continue; if (ioctl(fd, DIOCGWEDGEINFO, &dkw) == -1) { savee = errno; snprintf(buf, bufsiz, "%s: getwedgeinfo", dk); (void)close(fd); goto out; } (void)close(fd); if (strcmp(vname, (char *)dkw.dkw_wname) == 0) { p = strstr(buf, "/rdk"); goto good; } } #ifdef COMPAT_DKWEDGE /* Last ditch effort assuming NAME=label, and label is a disk name */ fd = opendisk(name, O_RDONLY, buf, bufsiz, 0); if (fd != -1) { close(fd); p = strstr(buf, "/r"); goto good; } #endif savee = ESRCH; snprintf(buf, bufsiz, "no match for `%s'", vname); out: buf = NULL; good: if (p++ != NULL) strcpy(p, p + 1); free(drives); free(vname); errno = savee; return buf; }