16507240bSMatthew Dillon /*
26507240bSMatthew Dillon * Copyright (c) 2009 The DragonFly Project. All rights reserved.
36507240bSMatthew Dillon *
46507240bSMatthew Dillon * This code is derived from software contributed to The DragonFly Project
56507240bSMatthew Dillon * by Matthew Dillon <dillon@backplane.com>
66507240bSMatthew Dillon *
76507240bSMatthew Dillon * Redistribution and use in source and binary forms, with or without
86507240bSMatthew Dillon * modification, are permitted provided that the following conditions
96507240bSMatthew Dillon * are met:
106507240bSMatthew Dillon *
116507240bSMatthew Dillon * 1. Redistributions of source code must retain the above copyright
126507240bSMatthew Dillon * notice, this list of conditions and the following disclaimer.
136507240bSMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright
146507240bSMatthew Dillon * notice, this list of conditions and the following disclaimer in
156507240bSMatthew Dillon * the documentation and/or other materials provided with the
166507240bSMatthew Dillon * distribution.
176507240bSMatthew Dillon * 3. Neither the name of The DragonFly Project nor the names of its
186507240bSMatthew Dillon * contributors may be used to endorse or promote products derived
196507240bSMatthew Dillon * from this software without specific, prior written permission.
206507240bSMatthew Dillon *
216507240bSMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
226507240bSMatthew Dillon * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
236507240bSMatthew Dillon * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
246507240bSMatthew Dillon * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
256507240bSMatthew Dillon * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
266507240bSMatthew Dillon * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
276507240bSMatthew Dillon * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
286507240bSMatthew Dillon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
296507240bSMatthew Dillon * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
306507240bSMatthew Dillon * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
316507240bSMatthew Dillon * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
326507240bSMatthew Dillon * SUCH DAMAGE.
336507240bSMatthew Dillon */
346507240bSMatthew Dillon
356507240bSMatthew Dillon #include <sys/types.h>
366507240bSMatthew Dillon #include <sys/stat.h>
376507240bSMatthew Dillon
386507240bSMatthew Dillon #include <stdio.h>
396507240bSMatthew Dillon #include <stdlib.h>
406507240bSMatthew Dillon #include <string.h>
416507240bSMatthew Dillon #include <unistd.h>
426507240bSMatthew Dillon #include <errno.h>
436507240bSMatthew Dillon #include <paths.h>
446507240bSMatthew Dillon #include <limits.h>
45376ccb5fSMatthew Dillon #include <fstab.h>
466507240bSMatthew Dillon
476507240bSMatthew Dillon static void finddevlabel(char **pathp, const char *devname);
486507240bSMatthew Dillon static int xlatedevpath(char **pathp, struct stat *st);
496507240bSMatthew Dillon static char *dodequote(char *base);
506507240bSMatthew Dillon
516507240bSMatthew Dillon /*
526507240bSMatthew Dillon * Acquire device path.
536507240bSMatthew Dillon *
546507240bSMatthew Dillon */
556507240bSMatthew Dillon char *
getdevpath(const char * devname,int flags)566507240bSMatthew Dillon getdevpath(const char *devname, int flags)
576507240bSMatthew Dillon {
586507240bSMatthew Dillon struct stat st;
596507240bSMatthew Dillon char *path = NULL;
606507240bSMatthew Dillon int stgood = 0;
616507240bSMatthew Dillon
626507240bSMatthew Dillon if (devname[0] == '/' || devname[0] == '.') {
636507240bSMatthew Dillon asprintf(&path, "%s", devname);
646507240bSMatthew Dillon } else {
656507240bSMatthew Dillon asprintf(&path, "/dev/%s", devname);
666507240bSMatthew Dillon if (lstat(path, &st) < 0) {
676507240bSMatthew Dillon free(path);
686507240bSMatthew Dillon path = NULL;
696507240bSMatthew Dillon finddevlabel(&path, devname);
706507240bSMatthew Dillon if (path == NULL)
716507240bSMatthew Dillon asprintf(&path, "%s", devname);
726507240bSMatthew Dillon } else {
736507240bSMatthew Dillon stgood = 1;
746507240bSMatthew Dillon }
756507240bSMatthew Dillon }
766507240bSMatthew Dillon
776507240bSMatthew Dillon /*
786507240bSMatthew Dillon * Translate softlinks if requested. If the lstat() of the
796507240bSMatthew Dillon * pre-translated path fails NULL is expected to be returned.
806507240bSMatthew Dillon * lstat() is not called on the post-translated path.
816507240bSMatthew Dillon */
826507240bSMatthew Dillon if ((flags & GETDEVPATH_RAWDEV) && path) {
836507240bSMatthew Dillon if (stgood == 0 && lstat(path, &st) == 0)
846507240bSMatthew Dillon stgood = 1;
856507240bSMatthew Dillon if (stgood)
866507240bSMatthew Dillon stgood = xlatedevpath(&path, &st);
876507240bSMatthew Dillon if (stgood == 0) {
886507240bSMatthew Dillon free(path);
896507240bSMatthew Dillon path = NULL;
906507240bSMatthew Dillon }
916507240bSMatthew Dillon
926507240bSMatthew Dillon }
936507240bSMatthew Dillon if (path == NULL)
946507240bSMatthew Dillon errno = ENOENT;
956507240bSMatthew Dillon return(path);
966507240bSMatthew Dillon }
976507240bSMatthew Dillon
986507240bSMatthew Dillon static void
finddevlabel(char ** pathp,const char * devname)996507240bSMatthew Dillon finddevlabel(char **pathp, const char *devname)
1006507240bSMatthew Dillon {
1016507240bSMatthew Dillon const char *prefix = _PATH_DEVTAB_PATHS;
1026507240bSMatthew Dillon const char *ptr1;
1036507240bSMatthew Dillon const char *trailer;
1046507240bSMatthew Dillon char *label;
1056507240bSMatthew Dillon char *ptr2;
1066507240bSMatthew Dillon char *ptr3;
1076507240bSMatthew Dillon char *dtpath;
1086507240bSMatthew Dillon char *bufp;
1096507240bSMatthew Dillon char buf[256];
1106507240bSMatthew Dillon FILE *fp;
1116507240bSMatthew Dillon size_t len; /* directory prefix length */
1126507240bSMatthew Dillon size_t tlen; /* devname length without trailer */
1136507240bSMatthew Dillon
1146507240bSMatthew Dillon if ((trailer = strrchr(devname, '.')) != NULL)
1156507240bSMatthew Dillon tlen = trailer - devname;
1166507240bSMatthew Dillon else
1176507240bSMatthew Dillon tlen = 0;
1186507240bSMatthew Dillon
1196507240bSMatthew Dillon while (*prefix && *pathp == NULL) {
1206507240bSMatthew Dillon /*
1216507240bSMatthew Dillon * Directory search path
1226507240bSMatthew Dillon */
1236507240bSMatthew Dillon ptr1 = strchr(prefix, ':');
1246507240bSMatthew Dillon len = (ptr1) ? (size_t)(ptr1 - prefix) : strlen(prefix);
125*0a227237SSascha Wildner asprintf(&dtpath, "%*.*s/devtab", (int)len, (int)len, prefix);
1266507240bSMatthew Dillon
1276507240bSMatthew Dillon /*
1286507240bSMatthew Dillon * Each devtab file
1296507240bSMatthew Dillon */
1306507240bSMatthew Dillon if ((fp = fopen(dtpath, "r")) != NULL) {
1316507240bSMatthew Dillon while (fgets(buf, sizeof(buf), fp) != NULL) {
1326507240bSMatthew Dillon /*
1336507240bSMatthew Dillon * Extract label field, check degenerate
1346507240bSMatthew Dillon * cases.
1356507240bSMatthew Dillon */
1366507240bSMatthew Dillon label = strtok_r(buf, " \t\r\n", &bufp);
1376507240bSMatthew Dillon if (label == NULL || *label == 0 ||
1386507240bSMatthew Dillon *label == '#') {
1396507240bSMatthew Dillon continue;
1406507240bSMatthew Dillon }
1416507240bSMatthew Dillon
1426507240bSMatthew Dillon /*
1436507240bSMatthew Dillon * Match label, with or without the
1446507240bSMatthew Dillon * trailer (aka ".s1a"). The trailer
1456507240bSMatthew Dillon * is tacked on if the match is without
1466507240bSMatthew Dillon * the trailer.
1476507240bSMatthew Dillon */
1486507240bSMatthew Dillon if (strcmp(devname, label) == 0) {
1496507240bSMatthew Dillon trailer = "";
1506507240bSMatthew Dillon } else if (tlen && strlen(label) == tlen &&
1516507240bSMatthew Dillon strncmp(devname, label, tlen) == 0) {
1526507240bSMatthew Dillon trailer = devname + tlen;
1536507240bSMatthew Dillon } else {
1546507240bSMatthew Dillon continue;
1556507240bSMatthew Dillon }
1566507240bSMatthew Dillon
1576507240bSMatthew Dillon /*
1586507240bSMatthew Dillon * Match, extract and process remaining fields.
1596507240bSMatthew Dillon */
1606507240bSMatthew Dillon ptr2 = strtok_r(NULL, " \t\r\n", &bufp);
1616507240bSMatthew Dillon ptr3 = strtok_r(NULL, " \t\r\n", &bufp);
1626507240bSMatthew Dillon if (ptr2 == NULL || ptr3 == NULL)
1636507240bSMatthew Dillon continue;
1646507240bSMatthew Dillon if (*ptr2 == 0 || *ptr3 == 0)
1656507240bSMatthew Dillon continue;
1666507240bSMatthew Dillon ptr3 = dodequote(ptr3);
1676507240bSMatthew Dillon if (strcmp(ptr2, "path") == 0) {
1686507240bSMatthew Dillon asprintf(pathp, "%s%s", ptr3, trailer);
1696507240bSMatthew Dillon } else {
1706507240bSMatthew Dillon asprintf(pathp, "/dev/%s/%s%s",
1716507240bSMatthew Dillon ptr2, ptr3, trailer);
1726507240bSMatthew Dillon }
1736507240bSMatthew Dillon break;
1746507240bSMatthew Dillon }
1756507240bSMatthew Dillon fclose(fp);
1766507240bSMatthew Dillon }
1776507240bSMatthew Dillon free(dtpath);
1786507240bSMatthew Dillon prefix += len;
1796507240bSMatthew Dillon if (*prefix == ':')
1806507240bSMatthew Dillon ++prefix;
1816507240bSMatthew Dillon }
1826507240bSMatthew Dillon }
1836507240bSMatthew Dillon
1846507240bSMatthew Dillon static int
xlatedevpath(char ** pathp,struct stat * st)1856507240bSMatthew Dillon xlatedevpath(char **pathp, struct stat *st)
1866507240bSMatthew Dillon {
1876507240bSMatthew Dillon char *path;
1886507240bSMatthew Dillon int n;
1896507240bSMatthew Dillon int len;
1906507240bSMatthew Dillon
1916507240bSMatthew Dillon /*
1926507240bSMatthew Dillon * If not a softlink return unchanged.
1936507240bSMatthew Dillon */
1946507240bSMatthew Dillon if (!S_ISLNK(st->st_mode))
1956507240bSMatthew Dillon return(1);
1966507240bSMatthew Dillon
1976507240bSMatthew Dillon /*
1986507240bSMatthew Dillon * If the softlink isn't reasonable return bad (0)
1996507240bSMatthew Dillon */
2006507240bSMatthew Dillon len = (int)st->st_size;
2016507240bSMatthew Dillon if (len < 0 || len > PATH_MAX)
2026507240bSMatthew Dillon return(0);
2036507240bSMatthew Dillon
2046507240bSMatthew Dillon /*
2056507240bSMatthew Dillon * Read the link, return if the result is not what we expected.
2066507240bSMatthew Dillon */
2076507240bSMatthew Dillon path = malloc(len + 1);
2086507240bSMatthew Dillon n = readlink(*pathp, path, len);
2096507240bSMatthew Dillon if (n < 0 || n > len) {
2106507240bSMatthew Dillon free(path);
2116507240bSMatthew Dillon return(0);
2126507240bSMatthew Dillon }
2136507240bSMatthew Dillon
2146507240bSMatthew Dillon /*
2156507240bSMatthew Dillon * Success, replace (*pathp).
2166507240bSMatthew Dillon */
2176507240bSMatthew Dillon path[n] = 0;
2186507240bSMatthew Dillon free(*pathp);
2196507240bSMatthew Dillon *pathp = path;
2206507240bSMatthew Dillon return(1);
2216507240bSMatthew Dillon }
2226507240bSMatthew Dillon
2236507240bSMatthew Dillon static char *
dodequote(char * base)2246507240bSMatthew Dillon dodequote(char *base)
2256507240bSMatthew Dillon {
2266507240bSMatthew Dillon int len = strlen(base);
2276507240bSMatthew Dillon
2286507240bSMatthew Dillon if (len && base[0] == '\"' && base[len-1] == '\"') {
2296507240bSMatthew Dillon base[len - 1] = 0;
2306507240bSMatthew Dillon ++base;
2316507240bSMatthew Dillon }
2326507240bSMatthew Dillon return(base);
2336507240bSMatthew Dillon }
234