1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 #include <errno.h> 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <unistd.h> 31 32 #include <libzutil.h> 33 34 /* Substring from after the last slash, or the string itself if none */ 35 const char * 36 zfs_basename(const char *path) 37 { 38 const char *bn = strrchr(path, '/'); 39 return (bn ? bn + 1 : path); 40 } 41 42 /* Return index of last slash or -1 if none */ 43 ssize_t 44 zfs_dirnamelen(const char *path) 45 { 46 const char *end = strrchr(path, '/'); 47 return (end ? end - path : -1); 48 } 49 50 /* 51 * Given a shorthand device name check if a file by that name exists in any 52 * of the 'zpool_default_import_path' or ZPOOL_IMPORT_PATH directories. If 53 * one is found, store its fully qualified path in the 'path' buffer passed 54 * by the caller and return 0, otherwise return an error. 55 */ 56 int 57 zfs_resolve_shortname(const char *name, char *path, size_t len) 58 { 59 int i, error = -1; 60 char *dir, *env, *envdup, *tmp = NULL; 61 62 env = getenv("ZPOOL_IMPORT_PATH"); 63 errno = ENOENT; 64 65 if (env) { 66 envdup = strdup(env); 67 for (dir = strtok_r(envdup, ":", &tmp); 68 dir != NULL && error != 0; 69 dir = strtok_r(NULL, ":", &tmp)) { 70 (void) snprintf(path, len, "%s/%s", dir, name); 71 error = access(path, F_OK); 72 } 73 free(envdup); 74 } else { 75 const char * const *zpool_default_import_path; 76 size_t count; 77 78 zpool_default_import_path = zpool_default_search_paths(&count); 79 80 for (i = 0; i < count && error < 0; i++) { 81 (void) snprintf(path, len, "%s/%s", 82 zpool_default_import_path[i], name); 83 error = access(path, F_OK); 84 } 85 } 86 87 return (error ? ENOENT : 0); 88 } 89 90 /* 91 * Given a shorthand device name look for a match against 'cmp_name'. This 92 * is done by checking all prefix expansions using either the default 93 * 'zpool_default_import_paths' or the ZPOOL_IMPORT_PATH environment 94 * variable. Proper partition suffixes will be appended if this is a 95 * whole disk. When a match is found 0 is returned otherwise ENOENT. 96 */ 97 static int 98 zfs_strcmp_shortname(const char *name, const char *cmp_name, int wholedisk) 99 { 100 int path_len, cmp_len, i = 0, error = ENOENT; 101 char *dir, *env, *envdup = NULL, *tmp = NULL; 102 char path_name[MAXPATHLEN]; 103 const char * const *zpool_default_import_path = NULL; 104 size_t count; 105 106 cmp_len = strlen(cmp_name); 107 env = getenv("ZPOOL_IMPORT_PATH"); 108 109 if (env) { 110 envdup = strdup(env); 111 dir = strtok_r(envdup, ":", &tmp); 112 } else { 113 zpool_default_import_path = zpool_default_search_paths(&count); 114 dir = (char *)zpool_default_import_path[i]; 115 } 116 117 while (dir) { 118 /* Trim trailing directory slashes from ZPOOL_IMPORT_PATH */ 119 if (env) { 120 while (dir[strlen(dir)-1] == '/') 121 dir[strlen(dir)-1] = '\0'; 122 } 123 124 path_len = snprintf(path_name, MAXPATHLEN, "%s/%s", dir, name); 125 if (wholedisk) 126 path_len = zfs_append_partition(path_name, MAXPATHLEN); 127 128 if ((path_len == cmp_len) && strcmp(path_name, cmp_name) == 0) { 129 error = 0; 130 break; 131 } 132 133 if (env) { 134 dir = strtok_r(NULL, ":", &tmp); 135 } else if (++i < count) { 136 dir = (char *)zpool_default_import_path[i]; 137 } else { 138 dir = NULL; 139 } 140 } 141 142 if (env) 143 free(envdup); 144 145 return (error); 146 } 147 148 /* 149 * Given either a shorthand or fully qualified path name look for a match 150 * against 'cmp'. The passed name will be expanded as needed for comparison 151 * purposes and redundant slashes stripped to ensure an accurate match. 152 */ 153 int 154 zfs_strcmp_pathname(const char *name, const char *cmp, int wholedisk) 155 { 156 int path_len, cmp_len; 157 char path_name[MAXPATHLEN]; 158 char cmp_name[MAXPATHLEN]; 159 char *dir, *tmp = NULL; 160 161 /* Strip redundant slashes if they exist due to ZPOOL_IMPORT_PATH */ 162 cmp_name[0] = '\0'; 163 (void) strlcpy(path_name, cmp, sizeof (path_name)); 164 for (dir = strtok_r(path_name, "/", &tmp); 165 dir != NULL; 166 dir = strtok_r(NULL, "/", &tmp)) { 167 strlcat(cmp_name, "/", sizeof (cmp_name)); 168 strlcat(cmp_name, dir, sizeof (cmp_name)); 169 } 170 171 if (name[0] != '/') 172 return (zfs_strcmp_shortname(name, cmp_name, wholedisk)); 173 174 (void) strlcpy(path_name, name, MAXPATHLEN); 175 path_len = strlen(path_name); 176 cmp_len = strlen(cmp_name); 177 178 if (wholedisk) { 179 path_len = zfs_append_partition(path_name, MAXPATHLEN); 180 if (path_len == -1) 181 return (ENOMEM); 182 } 183 184 if ((path_len != cmp_len) || strcmp(path_name, cmp_name)) 185 return (ENOENT); 186 187 return (0); 188 } 189