|
1 /* |
|
2 * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. |
|
3 * |
|
4 * U.S. Government Rights - Commercial software. Government users are subject |
|
5 * to the Sun Microsystems, Inc. standard license agreement and applicable |
|
6 * provisions of the FAR and its supplements. |
|
7 * |
|
8 * |
|
9 * This distribution may include materials developed by third parties. Sun, |
|
10 * Sun Microsystems, the Sun logo and Solaris are trademarks or registered |
|
11 * trademarks of Sun Microsystems, Inc. in the U.S. and other countries. |
|
12 * |
|
13 */ |
|
14 |
|
15 |
|
16 #include <stdio.h> |
|
17 #include <stdlib.h> |
|
18 #include <unistd.h> |
|
19 #include <dirent.h> |
|
20 #include <sys/types.h> |
|
21 #include <sys/stat.h> |
|
22 #include <limits.h> |
|
23 #include <string.h> |
|
24 #include <ctype.h> |
|
25 #include <fcntl.h> |
|
26 #include <sys/mnttab.h> |
|
27 #include <sys/systeminfo.h> |
|
28 #include <sys/dklabel.h> |
|
29 #include <sys/dkio.h> |
|
30 |
|
31 typedef struct nms { |
|
32 char *dsk; |
|
33 int dnum; |
|
34 char *dty; |
|
35 char *real; |
|
36 int devtype; |
|
37 struct nms *next; |
|
38 } nms_t; |
|
39 |
|
40 typedef struct list_of_disks { |
|
41 char *dtype; |
|
42 int dnum; |
|
43 char *dsk; |
|
44 char *dpart[NDKMAP]; |
|
45 struct list_of_disks *next; |
|
46 } disk_list_t; |
|
47 |
|
48 static nms_t *rummage_dev_dsk(void); |
|
49 static void do_snm(char *, char *); |
|
50 static int look_up_name(const char *, nms_t *); |
|
51 static void make_an_entry(char *, const char *, nms_t **, int); |
|
52 static char *trim(char *); |
|
53 static void rummage_path_to_inst(nms_t *); |
|
54 static nms_t *find_str(const char *, nms_t *); |
|
55 static int pline(char *, nms_t *); |
|
56 static void insert_dlist_ent(const char *, const int, const char *, |
|
57 int, disk_list_t **); |
|
58 static void mk_list_of_disks(nms_t *, disk_list_t **); |
|
59 static int str_is_digit(char *); |
|
60 |
|
61 extern void *build_disk_list(void *); |
|
62 extern char *lookup_ks_name(char *, void *); |
|
63 |
|
64 #define DISK 0 |
|
65 #define TAPE 1 |
|
66 |
|
67 #define MAX_TYPES 2 |
|
68 |
|
69 |
|
70 /* |
|
71 * Build a list of disks attached to the system. if a previous list is passed |
|
72 * in, delete that list before building the new list. |
|
73 */ |
|
74 |
|
75 void * |
|
76 build_disk_list(void *v) |
|
77 { |
|
78 nms_t *list; |
|
79 nms_t *t; |
|
80 disk_list_t *rv=NULL; |
|
81 disk_list_t *p; |
|
82 int i; |
|
83 |
|
84 p = (disk_list_t *)v; |
|
85 if (p != (disk_list_t *)NULL) { |
|
86 disk_list_t *t; |
|
87 while (p) { |
|
88 (void) free(p->dtype); |
|
89 (void) free(p->dsk); |
|
90 for (i = 0; i < NDKMAP; i++) |
|
91 (void) free(p->dpart[i]); |
|
92 t = p; |
|
93 p = p->next; |
|
94 (void) free(t); |
|
95 } |
|
96 } |
|
97 /* |
|
98 * Build the list of devices connected to the system. |
|
99 */ |
|
100 list = rummage_dev_dsk(); |
|
101 rummage_path_to_inst(list); |
|
102 mk_list_of_disks(list, &rv); |
|
103 t = list; |
|
104 while (t) { |
|
105 nms_t *f; |
|
106 (void) free(t->real); |
|
107 f = t; |
|
108 t = t->next; |
|
109 if (t != list) { |
|
110 (void) free(f); |
|
111 } |
|
112 } |
|
113 return (rv); |
|
114 } |
|
115 |
|
116 |
|
117 /* |
|
118 * Currently it isn't necessary to look below the cntndn level.... |
|
119 */ |
|
120 |
|
121 static nms_t * |
|
122 rummage_dev_dsk(void) |
|
123 { |
|
124 nms_t *list = (nms_t *)0; |
|
125 DIR *dskp; |
|
126 int i; |
|
127 |
|
128 for (i = 0; i < MAX_TYPES; i++) { |
|
129 switch (i) { |
|
130 |
|
131 case DISK: |
|
132 dskp = opendir("/dev/dsk"); |
|
133 break; |
|
134 case TAPE: |
|
135 dskp = opendir("/dev/rmt"); |
|
136 break; |
|
137 default: |
|
138 dskp = NULL; |
|
139 break; |
|
140 } |
|
141 |
|
142 if (dskp != NULL) { |
|
143 struct dirent *bpt; |
|
144 while ((bpt = readdir(dskp)) != NULL) { |
|
145 struct stat sbuf; |
|
146 char dnmbuf[1025]; |
|
147 char snm[256]; |
|
148 char lnm[256]; |
|
149 char *npt; |
|
150 char nmbuf[1025]; |
|
151 |
|
152 if (bpt->d_name[0] == '.') |
|
153 continue; |
|
154 |
|
155 if (i == DISK) { |
|
156 (void) strcpy(lnm, bpt->d_name); |
|
157 do_snm(bpt->d_name, snm); |
|
158 } else { |
|
159 /* |
|
160 * don't want all rewind/etc |
|
161 * devices for a tape |
|
162 */ |
|
163 if (!str_is_digit(bpt->d_name)) |
|
164 continue; |
|
165 (void) sprintf(snm, "rmt/%s", |
|
166 bpt->d_name); |
|
167 (void) sprintf(lnm, "rmt/%s", |
|
168 bpt->d_name); |
|
169 } |
|
170 if (look_up_name(snm, list) != 0) |
|
171 continue; |
|
172 |
|
173 if (i == DISK) { |
|
174 (void) sprintf(dnmbuf, |
|
175 "/dev/dsk/%s", bpt->d_name); |
|
176 } else { |
|
177 (void) sprintf(dnmbuf, |
|
178 "/dev/rmt/%s", bpt->d_name); |
|
179 } |
|
180 if (lstat(dnmbuf, &sbuf) != -1) { |
|
181 int cnt; |
|
182 if ((sbuf.st_mode & S_IFMT) |
|
183 == S_IFLNK) { |
|
184 |
|
185 nmbuf[0] = '\0'; |
|
186 if ((cnt = readlink(dnmbuf, nmbuf, sizeof (nmbuf))) != 1) { |
|
187 nmbuf[cnt] = '\0'; |
|
188 npt = nmbuf; |
|
189 } else |
|
190 npt = (char *)0; |
|
191 } else |
|
192 npt = lnm; |
|
193 if (npt) |
|
194 make_an_entry(npt, snm, |
|
195 &list, i); |
|
196 } |
|
197 } |
|
198 (void) closedir(dskp); |
|
199 } |
|
200 } |
|
201 return (list); |
|
202 } |
|
203 |
|
204 |
|
205 static int |
|
206 look_up_name(const char *nm, nms_t *list) |
|
207 { |
|
208 int rv = 0; |
|
209 |
|
210 while (list != (nms_t *)NULL) { |
|
211 if (strcmp(list->dsk, nm) != 0) |
|
212 list = list->next; |
|
213 else { |
|
214 rv++; |
|
215 break; |
|
216 } |
|
217 } |
|
218 return (rv); |
|
219 } |
|
220 |
|
221 |
|
222 static void |
|
223 do_snm(char *orig, char *shortnm) |
|
224 { |
|
225 while (*orig != 's' && *orig != 'p') |
|
226 *shortnm++ = *orig++; |
|
227 *shortnm = '\0'; |
|
228 } |
|
229 |
|
230 |
|
231 static void |
|
232 make_an_entry(char *lname, const char *shortnm, nms_t **list, int devtype) |
|
233 { |
|
234 nms_t *entry; |
|
235 |
|
236 entry = (nms_t *)malloc(sizeof (nms_t)); |
|
237 if (entry != (nms_t *)NULL) { |
|
238 int len; |
|
239 char *nlnm; |
|
240 |
|
241 nlnm = trim(lname); |
|
242 len = strlen(nlnm); |
|
243 len++; |
|
244 entry->real = (char *)malloc(len); |
|
245 if (entry->real) { |
|
246 (void) strcpy(entry->real, nlnm); |
|
247 len = strlen(shortnm); |
|
248 len++; |
|
249 entry->dsk = (char *)malloc(len); |
|
250 if (entry->dsk) { |
|
251 (void) strcpy(entry->dsk, shortnm); |
|
252 entry->dnum = -1; |
|
253 entry->dty = (char *)NULL; |
|
254 entry->next = (nms_t *)NULL; |
|
255 entry->devtype = devtype; |
|
256 if (*list != (nms_t *)NULL) { |
|
257 entry->next = *list; |
|
258 *list = entry; |
|
259 } else |
|
260 *list = entry; |
|
261 } else { |
|
262 (void) free(entry->real); |
|
263 (void) free(entry); |
|
264 } |
|
265 } else |
|
266 (void) free(entry); |
|
267 } |
|
268 } |
|
269 |
|
270 |
|
271 static char * |
|
272 trim(char *fnm) |
|
273 { |
|
274 char *ptr; |
|
275 char *lname = "../../devices"; |
|
276 |
|
277 while (*lname == *fnm) { |
|
278 lname++; |
|
279 fnm++; |
|
280 } |
|
281 if ((ptr = strrchr(fnm, (int)':')) != (char *)NULL) |
|
282 *ptr = '\0'; |
|
283 return (fnm); |
|
284 } |
|
285 |
|
286 |
|
287 static void |
|
288 rummage_path_to_inst(nms_t *list) |
|
289 { |
|
290 FILE *inpt; |
|
291 |
|
292 inpt = fopen("/etc/path_to_inst", "r"); |
|
293 if (inpt) { |
|
294 char ibuf[1024]; |
|
295 |
|
296 while (fgets(ibuf, sizeof (ibuf), inpt) != (char *)NULL) { |
|
297 if (ibuf[0] != '#') { |
|
298 (void) pline(ibuf, list); |
|
299 } |
|
300 } |
|
301 (void) fclose(inpt); |
|
302 } |
|
303 } |
|
304 |
|
305 |
|
306 /* |
|
307 * Process an /etc/path_to_inst line. The line is of the format: |
|
308 * "/pathname/device@unit,instance" devicenumber We want to extract the |
|
309 * devicenumber and the device from this string if it is one of the ones in |
|
310 * /dev/dsk. |
|
311 */ |
|
312 |
|
313 |
|
314 static int |
|
315 pline(char *ib, nms_t *list) |
|
316 { |
|
317 char *rpt; |
|
318 char *bpt; |
|
319 nms_t *entry; |
|
320 int rv = 0; |
|
321 int done; |
|
322 int len; |
|
323 char *v; |
|
324 /* |
|
325 * Skip over any stuff at the beginning of the line before a leading |
|
326 * '/' If we don't find a '/', the line is malformed and we just skip |
|
327 * it. |
|
328 */ |
|
329 while (*ib) { |
|
330 if (*ib != '/') |
|
331 ib++; |
|
332 else |
|
333 break; |
|
334 } |
|
335 if (!(*ib)) |
|
336 goto done; |
|
337 |
|
338 /* |
|
339 * Find the trailing '"' in the line. If not found, we just |
|
340 * skip the line. |
|
341 */ |
|
342 |
|
343 rpt = strchr(ib, (int)'""'); |
|
344 if (rpt != NULL) |
|
345 rpt = strchr(rpt, (int)'""'); |
|
346 |
|
347 /* |
|
348 * Find a matching entry in the list of names from /dev/dsk. |
|
349 * If no match, we're not interested. |
|
350 */ |
|
351 if (!rpt) |
|
352 goto done; |
|
353 |
|
354 *rpt = '\0'; |
|
355 |
|
356 |
|
357 if ((entry = find_str(ib, list)) == (nms_t *)NULL) |
|
358 goto done; |
|
359 |
|
360 bpt = rpt; |
|
361 /* |
|
362 * Extract the device number at the end of |
|
363 * the line. We expect whitespace followed by |
|
364 * the beginning of the currently numeric |
|
365 * device id string; |
|
366 */ |
|
367 rpt++; |
|
368 done = 0; |
|
369 while (!done) { |
|
370 if (*rpt) { |
|
371 if (*rpt != '\n') { |
|
372 if (isspace((int)*rpt)) |
|
373 rpt++; |
|
374 else |
|
375 done++; |
|
376 } else |
|
377 done++; |
|
378 } else |
|
379 done++; |
|
380 } |
|
381 /* |
|
382 * Should now be at the beginning of the |
|
383 * device number. Point entry->dn at the |
|
384 * string. |
|
385 */ |
|
386 if (*rpt) { |
|
387 v = rpt; |
|
388 len = 0; |
|
389 while (v) { |
|
390 if (*v != '\n') { |
|
391 v++; |
|
392 len++; |
|
393 } else { |
|
394 *v = '\0'; |
|
395 v = (char *)NULL; |
|
396 } |
|
397 } |
|
398 if (len) { |
|
399 entry->dnum = atoi(rpt); |
|
400 while (bpt > ib) { |
|
401 if (*bpt != '@') |
|
402 bpt--; |
|
403 else |
|
404 break; |
|
405 } |
|
406 if (bpt > ib) { |
|
407 *bpt-- = '\0'; |
|
408 len = 0; |
|
409 while (bpt > ib) { |
|
410 if (*bpt != '/') { |
|
411 bpt--; |
|
412 len++; |
|
413 } else |
|
414 break; |
|
415 } |
|
416 if (bpt > ib) { |
|
417 bpt++; |
|
418 len++; |
|
419 entry->dty = (char *)malloc(len); |
|
420 if (entry->dty) { |
|
421 (void) strcpy(entry->dty, bpt); |
|
422 rv++; |
|
423 } |
|
424 } |
|
425 } |
|
426 } |
|
427 } |
|
428 done: |
|
429 return (rv); |
|
430 } |
|
431 |
|
432 |
|
433 |
|
434 static nms_t * |
|
435 find_str(const char *inbuf, nms_t *list) |
|
436 { |
|
437 while (list) { |
|
438 if (strcmp(inbuf, list->real) != 0) |
|
439 list = list->next; |
|
440 else |
|
441 break; |
|
442 } |
|
443 return (list); |
|
444 } |
|
445 |
|
446 |
|
447 |
|
448 static void |
|
449 mk_list_of_disks(nms_t *list, disk_list_t **hd) |
|
450 { |
|
451 while (list) { |
|
452 insert_dlist_ent(list->dsk, list->dnum, list->dty, |
|
453 list->devtype, hd); |
|
454 list = list->next; |
|
455 } |
|
456 } |
|
457 |
|
458 |
|
459 |
|
460 /* |
|
461 * Determine if a name is already in the list of disks. If not, insert the |
|
462 * name in the list. |
|
463 */ |
|
464 |
|
465 |
|
466 static void |
|
467 insert_dlist_ent(const char *nm, const int dn, const char *dty, |
|
468 int devtype, disk_list_t ** hd) |
|
469 { |
|
470 disk_list_t *stuff; |
|
471 int i, len; |
|
472 |
|
473 if (dty == NULL) |
|
474 return; |
|
475 |
|
476 stuff = *hd; |
|
477 while (stuff) { |
|
478 if (strcmp(nm, stuff->dsk) != 0) |
|
479 stuff = stuff->next; |
|
480 else |
|
481 break; |
|
482 } |
|
483 if (!stuff) { |
|
484 disk_list_t *entry; |
|
485 int mv; |
|
486 |
|
487 entry = (disk_list_t *)malloc( |
|
488 sizeof (disk_list_t)); |
|
489 if (entry) { |
|
490 entry->dnum = dn; |
|
491 entry->dsk = (char *)nm; |
|
492 entry->dtype = (char *)dty; |
|
493 |
|
494 len = strlen(nm) + 4; |
|
495 for (i = 0; i < NDKMAP; i++) { |
|
496 if (devtype == DISK) { |
|
497 entry->dpart[i] = (char *)malloc(len); |
|
498 if (entry->dpart[i]) { |
|
499 (void) sprintf(entry->dpart[i], |
|
500 "%ss%d\0", nm, i); |
|
501 } |
|
502 } else |
|
503 entry->dpart[i] = NULL; |
|
504 } |
|
505 /* |
|
506 * Figure out where to insert the name. The list is |
|
507 * ostensibly in sorted order. |
|
508 */ |
|
509 if (*hd != (disk_list_t *)NULL) { |
|
510 disk_list_t *follw; |
|
511 stuff = *hd; |
|
512 |
|
513 /* |
|
514 * Look through the list. While the strcmp |
|
515 * value is less than the current value, |
|
516 */ |
|
517 while (stuff) { |
|
518 if ((mv = strcmp(entry->dtype, |
|
519 stuff->dtype)) < 0) { |
|
520 follw = stuff; |
|
521 stuff = stuff->next; |
|
522 } else |
|
523 break; |
|
524 } |
|
525 if (mv == 0) { |
|
526 while (stuff) { |
|
527 if (strcmp(entry->dtype, |
|
528 stuff->dtype) != 0) |
|
529 break; |
|
530 if (dn > stuff->dnum) { |
|
531 follw = stuff; |
|
532 stuff = stuff->next; |
|
533 } else |
|
534 break; |
|
535 } |
|
536 } |
|
537 /* |
|
538 * We should now be ready to insert an |
|
539 * entry... |
|
540 */ |
|
541 if (mv >= 0) { |
|
542 if (stuff == *hd) { |
|
543 entry->next = stuff; |
|
544 *hd = entry; |
|
545 } else { |
|
546 entry->next = follw->next; |
|
547 follw->next = entry; |
|
548 } |
|
549 } else { |
|
550 /* |
|
551 * insert at the end of the |
|
552 * list |
|
553 */ |
|
554 follw->next = entry; |
|
555 entry->next = (disk_list_t *)NULL; |
|
556 } |
|
557 } else { |
|
558 *hd = entry; |
|
559 entry->next = (disk_list_t *)NULL; |
|
560 } |
|
561 } |
|
562 } |
|
563 } |
|
564 |
|
565 |
|
566 |
|
567 char * |
|
568 lookup_ks_name(char *dev_nm, void *val) |
|
569 { |
|
570 char *rv = (char *)0; |
|
571 int dv; |
|
572 char *device; |
|
573 int len; |
|
574 char cmpbuf[1024]; |
|
575 struct list_of_disks *list; |
|
576 char nmbuf[1024]; |
|
577 char *tmpnm; |
|
578 char *nm; |
|
579 int partition; |
|
580 |
|
581 tmpnm = nm = nmbuf; |
|
582 while ((*dev_nm) && (*dev_nm != ',')) { |
|
583 *tmpnm++ = *dev_nm++; |
|
584 } |
|
585 *tmpnm = '\0'; |
|
586 |
|
587 if (*dev_nm == ',') { |
|
588 dev_nm++; |
|
589 partition = (int)(*dev_nm - 'a'); |
|
590 if ((partition < 0) || (partition > NDKMAP)) |
|
591 partition = -1; |
|
592 } else |
|
593 partition = -1; |
|
594 |
|
595 list = (disk_list_t *)val; |
|
596 device = nm; |
|
597 len = 0; |
|
598 while (*nm) { |
|
599 if (isalpha((int)*nm)) { |
|
600 nm++; |
|
601 len++; |
|
602 } else |
|
603 break; |
|
604 } |
|
605 (void) strncpy(cmpbuf, device, len); |
|
606 cmpbuf[len] = '\0'; |
|
607 |
|
608 if (*nm) { |
|
609 int mv; |
|
610 |
|
611 dv = atoi(nm); |
|
612 while (list) { |
|
613 if ((mv = strcmp(cmpbuf, list->dtype)) < 0) |
|
614 list = list->next; |
|
615 else |
|
616 break; |
|
617 } |
|
618 if (mv == 0) { |
|
619 while (list) { |
|
620 if (list->dnum < dv) |
|
621 list = list->next; |
|
622 else |
|
623 break; |
|
624 } |
|
625 if(list) { |
|
626 if (list->dnum == dv) { |
|
627 if ((partition != -1) && |
|
628 (list->dpart[partition] != NULL)) |
|
629 rv = list->dpart[partition]; |
|
630 else |
|
631 rv = list->dsk; |
|
632 } |
|
633 } |
|
634 } |
|
635 } |
|
636 return (rv); |
|
637 } |
|
638 |
|
639 |
|
640 |
|
641 static int |
|
642 str_is_digit(char *str) |
|
643 { |
|
644 int i; |
|
645 int j = 0; |
|
646 |
|
647 for (i = 0; i < (int)strlen(str); i++) { |
|
648 if (isdigit(str[i])) j++; |
|
649 } |
|
650 |
|
651 if (j == strlen(str)) |
|
652 return (1); |
|
653 else |
|
654 return (0); |
|
655 } |
|
656 |