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 *
getfullname(char * path)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
test_if_blk(char * new_path,dev_t raw_dev)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
test_if_raw(char * new_path,dev_t blk_dev)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 *
getblkcomplete(char * cp,struct stat64 * dat)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 *
getrawcomplete(char * cp,struct stat64 * dat)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 *
getvfsspecial(char * path,int raw_special)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 *
getfullblkname(char * cp)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 *
getfullrawname(char * cp)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