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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 /*LINTLIBRARY*/ 29 30 #include <sys/types.h> 31 #include <stdio.h> 32 #include <errno.h> 33 #include <string.h> 34 #include <unistd.h> 35 #include <stdlib.h> 36 #include <sys/param.h> 37 #include <sys/stat.h> 38 #include <sys/sysmacros.h> 39 #include <sys/vfstab.h> 40 #include <sys/lofi.h> 41 #include <sys/ramdisk.h> 42 #include <sys/fssnap_if.h> 43 #include "libadm.h" 44 45 /* 46 * Globals: 47 * getfullrawname - returns a fully-qualified raw device name 48 * getfullblkname - returns a fully-qualified block device name 49 * 50 * These two routines take a device pathname and return corresponding 51 * the raw or block device name. 52 * 53 * First the device name is fully qualified: 54 * If the device name does not start with a '/' or starts with 55 * './' then the current working directory is added to the beginning 56 * of the pathname. 57 * 58 * If the device name starts with a '../' then all but the last 59 * sub-directory of the current working directory is added to the 60 * the beginning of the pathname. 61 * 62 * Second if the fully-qualified device name given is the raw/block 63 * device that is being asked for then the fully-qualified device name is 64 * returned. 65 * 66 * Third if an entry is found in /etc/vfstab which matches the given name 67 * then the corresponding raw/block device is returned. This allows 68 * non-standard names to be converted (.i.e., block device "/dev/joe" can 69 * be converted to raw device "/dev/fred", via this mechanism). 70 * 71 * Last standard names are converted. Standard names are those 72 * with a '/dsk/' for block or '/rdsk/' for raw sub-directory components 73 * in the device name. Or, the filename component has an 'r' for raw or 74 * no 'r' for block (e.g., rsd0a <=> sd0a). 75 * 76 * Caveat: 77 * It is assumed that the block and raw devices have the 78 * same device number, and this is used to verify the conversion 79 * happened corretly. If this happens not to be true, due to mapping 80 * of minor numbers or sometheing, then entries can be put in the 81 * the '/etc/vfstab' file to over-ride this checking. 82 * 83 * 84 * Return Values: 85 * raw/block device name - (depending on which routine is used) 86 * null string - When the conversion failed 87 * null pointer - malloc problems 88 * 89 * It is up to the user of these routines to free the memory, of 90 * the device name or null string returned by these library routines, 91 * when appropriate by the application. 92 */ 93 #define GET_BLK 0 94 #define GET_RAW 1 95 96 static int test_if_blk(char *, dev_t); 97 static int test_if_raw(char *, dev_t); 98 static char *getblkcomplete(char *, struct stat64 *); 99 static char *getrawcomplete(char *, struct stat64 *); 100 101 /* 102 * getfullname() - Builds a fully qualified pathname. 103 * This handles . and .. as well. 104 * NOTE: This is different from realpath(3C) because 105 * it does not follow links. 106 */ 107 static char * 108 getfullname(char *path) 109 { 110 char cwd[MAXPATHLEN]; 111 char *c; 112 char *wa; 113 size_t len; 114 115 if (*path == '/') 116 return (strdup(path)); 117 118 if (getcwd(cwd, sizeof (cwd)) == NULL) 119 return (strdup("")); 120 121 /* handle . and .. */ 122 if (strncmp(path, "./", 2) == 0) { 123 /* strip the ./ from the given path */ 124 path += 2; 125 } else if (strncmp(path, "../", 3) == 0) { 126 /* strip the last directory component from cwd */ 127 c = strrchr(cwd, '/'); 128 *c = '\0'; 129 130 /* strip the ../ from the given path */ 131 path += 3; 132 } 133 134 /* 135 * Adding 2 takes care of slash and null terminator. 136 */ 137 len = strlen(cwd) + strlen(path) + 2; 138 if ((wa = malloc(len)) == NULL) 139 return (NULL); 140 141 (void) strcpy(wa, cwd); 142 (void) strcat(wa, "/"); 143 (void) strcat(wa, path); 144 145 return (wa); 146 } 147 148 /* 149 * test the path/fname to see if is blk special 150 */ 151 static int 152 test_if_blk(char *new_path, dev_t raw_dev) 153 { 154 struct stat64 buf; 155 156 /* check if we got a char special file */ 157 if (stat64(new_path, &buf) != 0) 158 return (0); 159 160 if (!S_ISBLK(buf.st_mode)) 161 return (0); 162 163 if (raw_dev != buf.st_rdev) 164 return (0); 165 166 return (1); 167 } 168 169 /* 170 * test the path/fname to see if is char special 171 */ 172 static int 173 test_if_raw(char *new_path, dev_t blk_dev) 174 { 175 struct stat64 buf; 176 177 /* check if we got a char special file */ 178 if (stat64(new_path, &buf) != 0) 179 return (0); 180 181 if (!S_ISCHR(buf.st_mode)) 182 return (0); 183 184 if (blk_dev != buf.st_rdev) 185 return (0); 186 187 return (1); 188 } 189 190 /* 191 * complete getblkrawname() for blk->raw to handle volmgt devices 192 */ 193 194 static char * 195 getblkcomplete(char *cp, struct stat64 *dat) 196 { 197 char *dp; 198 char *new_path; 199 char c; 200 201 /* ok, so we either have a bad device or a floppy */ 202 203 /* try the rfd# form */ 204 if ((dp = strstr(cp, "/rfd")) != NULL) { 205 if ((new_path = malloc(strlen(cp))) == NULL) 206 return (NULL); 207 208 c = *++dp; /* save the 'r' */ 209 *dp = '\0'; /* replace it with a null */ 210 (void) strcpy(new_path, cp); /* save first part of it */ 211 *dp++ = c; /* give the 'r' back */ 212 (void) strcat(new_path, dp); /* copy, skipping the 'r' */ 213 214 if (test_if_blk(new_path, dat->st_rdev)) 215 return (new_path); 216 217 free(new_path); 218 return (strdup("")); 219 } 220 221 /* try the rdiskette form */ 222 if ((dp = strstr(cp, "/rdiskette")) != NULL) { 223 if ((new_path = malloc(strlen(cp))) == NULL) 224 return (NULL); 225 226 c = *++dp; /* save the 'r' */ 227 *dp = '\0'; /* replace it with a null */ 228 (void) strcpy(new_path, cp); /* save first part of it */ 229 *dp++ = c; /* give the 'r' back */ 230 (void) strcat(new_path, dp); /* copy, skipping the 'r' */ 231 232 if (test_if_blk(new_path, dat->st_rdev)) 233 return (new_path); 234 235 free(new_path); 236 return (strdup("")); 237 } 238 239 /* no match found */ 240 return (strdup("")); 241 } 242 243 /* 244 * complete getfullrawname() for raw->blk to handle volmgt devices 245 */ 246 247 static char * 248 getrawcomplete(char *cp, struct stat64 *dat) 249 { 250 char *dp; 251 char *new_path; 252 char c; 253 254 /* ok, so we either have a bad device or a floppy */ 255 256 /* try the fd# form */ 257 if ((dp = strstr(cp, "/fd")) != NULL) { 258 /* malloc path for new_path to hold raw */ 259 if ((new_path = malloc(strlen(cp)+2)) == NULL) 260 return (NULL); 261 262 c = *++dp; /* save the 'f' */ 263 *dp = '\0'; /* replace it with a null */ 264 (void) strcpy(new_path, cp); /* save first part of it */ 265 *dp = c; /* put the 'f' back */ 266 (void) strcat(new_path, "r"); /* insert an 'r' */ 267 (void) strcat(new_path, dp); /* copy the rest */ 268 269 if (test_if_raw(new_path, dat->st_rdev)) 270 return (new_path); 271 272 free(new_path); 273 } 274 275 /* try the diskette form */ 276 if ((dp = strstr(cp, "/diskette")) != NULL) { 277 /* malloc path for new_path to hold raw */ 278 if ((new_path = malloc(strlen(cp)+2)) == NULL) 279 return (NULL); 280 281 c = *++dp; /* save at 'd' */ 282 *dp = '\0'; /* replace it with a null */ 283 (void) strcpy(new_path, cp); /* save first part */ 284 *dp = c; /* put the 'd' back */ 285 (void) strcat(new_path, "r"); /* insert an 'r' */ 286 (void) strcat(new_path, dp); /* copy the rest */ 287 288 if (test_if_raw(new_path, dat->st_rdev)) 289 return (new_path); 290 291 free(new_path); 292 return (strdup("")); 293 } 294 295 /* failed to build raw name, return null string */ 296 return (strdup("")); 297 298 299 300 } 301 302 static char * 303 getvfsspecial(char *path, int raw_special) 304 { 305 FILE *fp; 306 struct vfstab vp; 307 struct vfstab ref_vp; 308 309 if ((fp = fopen("/etc/vfstab", "r")) == NULL) 310 return (NULL); 311 312 (void) memset(&ref_vp, 0, sizeof (struct vfstab)); 313 314 if (raw_special) 315 ref_vp.vfs_special = path; 316 else 317 ref_vp.vfs_fsckdev = path; 318 319 if (getvfsany(fp, &vp, &ref_vp)) { 320 (void) fclose(fp); 321 return (NULL); 322 } 323 324 (void) fclose(fp); 325 326 if (raw_special) 327 return (vp.vfs_fsckdev); 328 329 return (vp.vfs_special); 330 } 331 332 /* 333 * change the device name to a block device name 334 */ 335 char * 336 getfullblkname(char *cp) 337 { 338 struct stat64 buf; 339 char *dp; 340 char *new_path; 341 dev_t raw_dev; 342 343 if (cp == NULL) 344 return (strdup("")); 345 346 /* 347 * Create a fully qualified name. 348 */ 349 if ((cp = getfullname(cp)) == NULL) 350 return (NULL); 351 352 if (*cp == '\0') 353 return (cp); 354 355 if (stat64(cp, &buf) != 0) { 356 free(cp); 357 return (strdup("")); 358 } 359 360 if (S_ISBLK(buf.st_mode)) 361 return (cp); 362 363 if (!S_ISCHR(buf.st_mode)) { 364 free(cp); 365 return (strdup("")); 366 } 367 368 if ((dp = getvfsspecial(cp, GET_BLK)) != NULL) { 369 free(cp); 370 return (strdup(dp)); 371 } 372 373 raw_dev = buf.st_rdev; 374 375 /* 376 * We have a raw device name, go find the block name. 377 */ 378 if ((dp = strstr(cp, "/rdsk/")) == NULL && 379 (dp = strstr(cp, "/" LOFI_CHAR_NAME "/")) == NULL && 380 (dp = strstr(cp, "/" RD_CHAR_NAME "/")) == NULL && 381 (dp = strstr(cp, "/" SNAP_CHAR_NAME "/")) == NULL && 382 (dp = strrchr(cp, '/')) == NULL) { 383 /* this is not really possible */ 384 free(cp); 385 return (strdup("")); 386 } 387 dp++; 388 if (*dp != 'r') { 389 dp = getblkcomplete(cp, &buf); 390 free(cp); 391 return (dp); 392 } 393 if ((new_path = malloc(strlen(cp))) == NULL) { 394 free(cp); 395 return (NULL); 396 } 397 (void) strncpy(new_path, cp, dp - cp); 398 399 /* fill in the rest of the unraw name */ 400 (void) strcpy(new_path + (dp - cp), dp + 1); 401 402 if (test_if_blk(new_path, raw_dev)) { 403 free(cp); 404 /* block name was found, return it here */ 405 return (new_path); 406 } 407 free(new_path); 408 409 dp = getblkcomplete(cp, &buf); 410 free(cp); 411 return (dp); 412 } 413 414 /* 415 * change the device name to a raw devname 416 */ 417 char * 418 getfullrawname(char *cp) 419 { 420 struct stat64 buf; 421 char *dp; 422 char *new_path; 423 dev_t blk_dev; 424 425 if (cp == NULL) 426 return (strdup("")); 427 428 /* 429 * Create a fully qualified name. 430 */ 431 if ((cp = getfullname(cp)) == NULL) 432 return (NULL); 433 434 if (*cp == '\0') 435 return (cp); 436 437 if (stat64(cp, &buf) != 0) { 438 free(cp); 439 return (strdup("")); 440 } 441 442 if (S_ISCHR(buf.st_mode)) 443 return (cp); 444 445 if (!S_ISBLK(buf.st_mode)) { 446 free(cp); 447 return (strdup("")); 448 } 449 450 blk_dev = buf.st_rdev; 451 452 if ((dp = getvfsspecial(cp, GET_RAW)) != NULL) { 453 free(cp); 454 return (strdup(dp)); 455 } 456 457 /* 458 * We have a block device name, go find the raw name. 459 */ 460 if ((dp = strstr(cp, "/dsk/")) == NULL && 461 (dp = strstr(cp, "/" LOFI_BLOCK_NAME "/")) == NULL && 462 (dp = strstr(cp, "/" RD_BLOCK_NAME "/")) == NULL && 463 (dp = strstr(cp, "/" SNAP_BLOCK_NAME "/")) == NULL && 464 (dp = strrchr(cp, '/')) == NULL) { 465 /* this is not really possible */ 466 free(cp); 467 return (strdup("")); 468 } 469 dp++; 470 471 if ((new_path = malloc(strlen(cp)+2)) == NULL) { 472 free(cp); 473 return (NULL); 474 } 475 (void) strncpy(new_path, cp, dp - cp); 476 /* fill in the rest of the raw name */ 477 new_path[dp - cp] = 'r'; 478 (void) strcpy(new_path + (dp - cp) + 1, dp); 479 480 if (test_if_raw(new_path, blk_dev)) { 481 free(cp); 482 return (new_path); 483 } 484 free(new_path); 485 486 dp = getrawcomplete(cp, &buf); 487 free(cp); 488 return (dp); 489 } 490