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