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 https://opensource.org/licenses/CDDL-1.0. 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 const char *env = getenv("ZPOOL_IMPORT_PATH"); 60 61 if (env) { 62 for (;;) { 63 env += strspn(env, ":"); 64 size_t dirlen = strcspn(env, ":"); 65 if (dirlen) { 66 (void) snprintf(path, len, "%.*s/%s", 67 (int)dirlen, env, name); 68 if (access(path, F_OK) == 0) 69 return (0); 70 71 env += dirlen; 72 } else 73 break; 74 } 75 } else { 76 size_t count; 77 const char *const *zpool_default_import_path = 78 zpool_default_search_paths(&count); 79 80 for (size_t i = 0; i < count; ++i) { 81 (void) snprintf(path, len, "%s/%s", 82 zpool_default_import_path[i], name); 83 if (access(path, F_OK) == 0) 84 return (0); 85 } 86 } 87 88 return (errno = ENOENT); 89 } 90 91 /* 92 * Given a shorthand device name look for a match against 'cmp_name'. This 93 * is done by checking all prefix expansions using either the default 94 * 'zpool_default_import_paths' or the ZPOOL_IMPORT_PATH environment 95 * variable. Proper partition suffixes will be appended if this is a 96 * whole disk. When a match is found 0 is returned otherwise ENOENT. 97 */ 98 static int 99 zfs_strcmp_shortname(const char *name, const char *cmp_name, int wholedisk) 100 { 101 int path_len, cmp_len, i = 0, error = ENOENT; 102 char *dir, *env, *envdup = NULL, *tmp = NULL; 103 char path_name[MAXPATHLEN]; 104 const char *const *zpool_default_import_path = NULL; 105 size_t count; 106 107 cmp_len = strlen(cmp_name); 108 env = getenv("ZPOOL_IMPORT_PATH"); 109 110 if (env) { 111 envdup = strdup(env); 112 dir = strtok_r(envdup, ":", &tmp); 113 } else { 114 zpool_default_import_path = zpool_default_search_paths(&count); 115 dir = (char *)zpool_default_import_path[i]; 116 } 117 118 while (dir) { 119 /* Trim trailing directory slashes from ZPOOL_IMPORT_PATH */ 120 if (env) { 121 while (dir[strlen(dir)-1] == '/') 122 dir[strlen(dir)-1] = '\0'; 123 } 124 125 path_len = snprintf(path_name, MAXPATHLEN, "%s/%s", dir, name); 126 if (wholedisk) 127 path_len = zfs_append_partition(path_name, MAXPATHLEN); 128 129 if ((path_len == cmp_len) && strcmp(path_name, cmp_name) == 0) { 130 error = 0; 131 break; 132 } 133 134 if (env) { 135 dir = strtok_r(NULL, ":", &tmp); 136 } else if (++i < count) { 137 dir = (char *)zpool_default_import_path[i]; 138 } else { 139 dir = NULL; 140 } 141 } 142 143 if (env) 144 free(envdup); 145 146 return (error); 147 } 148 149 /* 150 * Given either a shorthand or fully qualified path name look for a match 151 * against 'cmp'. The passed name will be expanded as needed for comparison 152 * purposes and redundant slashes stripped to ensure an accurate match. 153 */ 154 int 155 zfs_strcmp_pathname(const char *name, const char *cmp, int wholedisk) 156 { 157 int path_len, cmp_len; 158 char path_name[MAXPATHLEN]; 159 char cmp_name[MAXPATHLEN]; 160 char *dir, *tmp = NULL; 161 162 /* Strip redundant slashes if they exist due to ZPOOL_IMPORT_PATH */ 163 cmp_name[0] = '\0'; 164 (void) strlcpy(path_name, cmp, sizeof (path_name)); 165 for (dir = strtok_r(path_name, "/", &tmp); 166 dir != NULL; 167 dir = strtok_r(NULL, "/", &tmp)) { 168 strlcat(cmp_name, "/", sizeof (cmp_name)); 169 strlcat(cmp_name, dir, sizeof (cmp_name)); 170 } 171 172 if (name[0] != '/') 173 return (zfs_strcmp_shortname(name, cmp_name, wholedisk)); 174 175 (void) strlcpy(path_name, name, MAXPATHLEN); 176 path_len = strlen(path_name); 177 cmp_len = strlen(cmp_name); 178 179 if (wholedisk) { 180 path_len = zfs_append_partition(path_name, MAXPATHLEN); 181 if (path_len == -1) 182 return (ENOMEM); 183 } 184 185 if ((path_len != cmp_len) || strcmp(path_name, cmp_name)) 186 return (ENOENT); 187 188 return (0); 189 } 190