/* * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. * * U.S. Government Rights - Commercial software. Government users are subject * to the Sun Microsystems, Inc. standard license agreement and applicable * provisions of the FAR and its supplements. * * * This distribution may include materials developed by third parties. Sun, * Sun Microsystems, the Sun logo and Solaris are trademarks or registered * trademarks of Sun Microsystems, Inc. in the U.S. and other countries. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include typedef struct nms { char *dsk; int dnum; char *dty; char *real; int devtype; struct nms *next; } nms_t; typedef struct list_of_disks { char *dtype; int dnum; char *dsk; char *dpart[NDKMAP]; struct list_of_disks *next; } disk_list_t; static nms_t *rummage_dev_dsk(void); static void do_snm(char *, char *); static int look_up_name(const char *, nms_t *); static void make_an_entry(char *, const char *, nms_t **, int); static char *trim(char *); static void rummage_path_to_inst(nms_t *); static nms_t *find_str(const char *, nms_t *); static int pline(char *, nms_t *); static void insert_dlist_ent(const char *, const int, const char *, int, disk_list_t **); static void mk_list_of_disks(nms_t *, disk_list_t **); static int str_is_digit(char *); extern void *build_disk_list(void *); extern char *lookup_ks_name(char *, void *); #define DISK 0 #define TAPE 1 #define MAX_TYPES 2 /* * Build a list of disks attached to the system. if a previous list is passed * in, delete that list before building the new list. */ void * build_disk_list(void *v) { nms_t *list; nms_t *t; disk_list_t *rv=NULL; disk_list_t *p; int i; p = (disk_list_t *)v; if (p != (disk_list_t *)NULL) { disk_list_t *t; while (p) { (void) free(p->dtype); (void) free(p->dsk); for (i = 0; i < NDKMAP; i++) (void) free(p->dpart[i]); t = p; p = p->next; (void) free(t); } } /* * Build the list of devices connected to the system. */ list = rummage_dev_dsk(); rummage_path_to_inst(list); mk_list_of_disks(list, &rv); t = list; while (t) { nms_t *f; (void) free(t->real); f = t; t = t->next; if (t != list) { (void) free(f); } } return (rv); } /* * Currently it isn't necessary to look below the cntndn level.... */ static nms_t * rummage_dev_dsk(void) { nms_t *list = (nms_t *)0; DIR *dskp; int i; for (i = 0; i < MAX_TYPES; i++) { switch (i) { case DISK: dskp = opendir("/dev/dsk"); break; case TAPE: dskp = opendir("/dev/rmt"); break; default: dskp = NULL; break; } if (dskp != NULL) { struct dirent *bpt; while ((bpt = readdir(dskp)) != NULL) { struct stat sbuf; char dnmbuf[1025]; char snm[256]; char lnm[256]; char *npt; char nmbuf[1025]; if (bpt->d_name[0] == '.') continue; if (i == DISK) { (void) strcpy(lnm, bpt->d_name); do_snm(bpt->d_name, snm); } else { /* * don't want all rewind/etc * devices for a tape */ if (!str_is_digit(bpt->d_name)) continue; (void) sprintf(snm, "rmt/%s", bpt->d_name); (void) sprintf(lnm, "rmt/%s", bpt->d_name); } if (look_up_name(snm, list) != 0) continue; if (i == DISK) { (void) sprintf(dnmbuf, "/dev/dsk/%s", bpt->d_name); } else { (void) sprintf(dnmbuf, "/dev/rmt/%s", bpt->d_name); } if (lstat(dnmbuf, &sbuf) != -1) { int cnt; if ((sbuf.st_mode & S_IFMT) == S_IFLNK) { nmbuf[0] = '\0'; if ((cnt = readlink(dnmbuf, nmbuf, sizeof (nmbuf))) != 1) { nmbuf[cnt] = '\0'; npt = nmbuf; } else npt = (char *)0; } else npt = lnm; if (npt) make_an_entry(npt, snm, &list, i); } } (void) closedir(dskp); } } return (list); } static int look_up_name(const char *nm, nms_t *list) { int rv = 0; while (list != (nms_t *)NULL) { if (strcmp(list->dsk, nm) != 0) list = list->next; else { rv++; break; } } return (rv); } static void do_snm(char *orig, char *shortnm) { while (*orig != 's' && *orig != 'p') *shortnm++ = *orig++; *shortnm = '\0'; } static void make_an_entry(char *lname, const char *shortnm, nms_t **list, int devtype) { nms_t *entry; entry = (nms_t *)malloc(sizeof (nms_t)); if (entry != (nms_t *)NULL) { int len; char *nlnm; nlnm = trim(lname); len = strlen(nlnm); len++; entry->real = (char *)malloc(len); if (entry->real) { (void) strcpy(entry->real, nlnm); len = strlen(shortnm); len++; entry->dsk = (char *)malloc(len); if (entry->dsk) { (void) strcpy(entry->dsk, shortnm); entry->dnum = -1; entry->dty = (char *)NULL; entry->next = (nms_t *)NULL; entry->devtype = devtype; if (*list != (nms_t *)NULL) { entry->next = *list; *list = entry; } else *list = entry; } else { (void) free(entry->real); (void) free(entry); } } else (void) free(entry); } } static char * trim(char *fnm) { char *ptr; char *lname = "../../devices"; while (*lname == *fnm) { lname++; fnm++; } if ((ptr = strrchr(fnm, (int)':')) != (char *)NULL) *ptr = '\0'; return (fnm); } static void rummage_path_to_inst(nms_t *list) { FILE *inpt; inpt = fopen("/etc/path_to_inst", "r"); if (inpt) { char ibuf[1024]; while (fgets(ibuf, sizeof (ibuf), inpt) != (char *)NULL) { if (ibuf[0] != '#') { (void) pline(ibuf, list); } } (void) fclose(inpt); } } /* * Process an /etc/path_to_inst line. The line is of the format: * "/pathname/device@unit,instance" devicenumber We want to extract the * devicenumber and the device from this string if it is one of the ones in * /dev/dsk. */ static int pline(char *ib, nms_t *list) { char *rpt; char *bpt; nms_t *entry; int rv = 0; int done; int len; char *v; /* * Skip over any stuff at the beginning of the line before a leading * '/' If we don't find a '/', the line is malformed and we just skip * it. */ while (*ib) { if (*ib != '/') ib++; else break; } if (!(*ib)) goto done; /* * Find the trailing '"' in the line. If not found, we just * skip the line. */ rpt = strchr(ib, (int)'""'); if (rpt != NULL) rpt = strchr(rpt, (int)'""'); /* * Find a matching entry in the list of names from /dev/dsk. * If no match, we're not interested. */ if (!rpt) goto done; *rpt = '\0'; if ((entry = find_str(ib, list)) == (nms_t *)NULL) goto done; bpt = rpt; /* * Extract the device number at the end of * the line. We expect whitespace followed by * the beginning of the currently numeric * device id string; */ rpt++; done = 0; while (!done) { if (*rpt) { if (*rpt != '\n') { if (isspace((int)*rpt)) rpt++; else done++; } else done++; } else done++; } /* * Should now be at the beginning of the * device number. Point entry->dn at the * string. */ if (*rpt) { v = rpt; len = 0; while (v) { if (*v != '\n') { v++; len++; } else { *v = '\0'; v = (char *)NULL; } } if (len) { entry->dnum = atoi(rpt); while (bpt > ib) { if (*bpt != '@') bpt--; else break; } if (bpt > ib) { *bpt-- = '\0'; len = 0; while (bpt > ib) { if (*bpt != '/') { bpt--; len++; } else break; } if (bpt > ib) { bpt++; len++; entry->dty = (char *)malloc(len); if (entry->dty) { (void) strcpy(entry->dty, bpt); rv++; } } } } } done: return (rv); } static nms_t * find_str(const char *inbuf, nms_t *list) { while (list) { if (strcmp(inbuf, list->real) != 0) list = list->next; else break; } return (list); } static void mk_list_of_disks(nms_t *list, disk_list_t **hd) { while (list) { insert_dlist_ent(list->dsk, list->dnum, list->dty, list->devtype, hd); list = list->next; } } /* * Determine if a name is already in the list of disks. If not, insert the * name in the list. */ static void insert_dlist_ent(const char *nm, const int dn, const char *dty, int devtype, disk_list_t ** hd) { disk_list_t *stuff; int i, len; if (dty == NULL) return; stuff = *hd; while (stuff) { if (strcmp(nm, stuff->dsk) != 0) stuff = stuff->next; else break; } if (!stuff) { disk_list_t *entry; int mv; entry = (disk_list_t *)malloc( sizeof (disk_list_t)); if (entry) { entry->dnum = dn; entry->dsk = (char *)nm; entry->dtype = (char *)dty; len = strlen(nm) + 4; for (i = 0; i < NDKMAP; i++) { if (devtype == DISK) { entry->dpart[i] = (char *)malloc(len); if (entry->dpart[i]) { (void) sprintf(entry->dpart[i], "%ss%d\0", nm, i); } } else entry->dpart[i] = NULL; } /* * Figure out where to insert the name. The list is * ostensibly in sorted order. */ if (*hd != (disk_list_t *)NULL) { disk_list_t *follw; stuff = *hd; /* * Look through the list. While the strcmp * value is less than the current value, */ while (stuff) { if ((mv = strcmp(entry->dtype, stuff->dtype)) < 0) { follw = stuff; stuff = stuff->next; } else break; } if (mv == 0) { while (stuff) { if (strcmp(entry->dtype, stuff->dtype) != 0) break; if (dn > stuff->dnum) { follw = stuff; stuff = stuff->next; } else break; } } /* * We should now be ready to insert an * entry... */ if (mv >= 0) { if (stuff == *hd) { entry->next = stuff; *hd = entry; } else { entry->next = follw->next; follw->next = entry; } } else { /* * insert at the end of the * list */ follw->next = entry; entry->next = (disk_list_t *)NULL; } } else { *hd = entry; entry->next = (disk_list_t *)NULL; } } } } char * lookup_ks_name(char *dev_nm, void *val) { char *rv = (char *)0; int dv; char *device; int len; char cmpbuf[1024]; struct list_of_disks *list; char nmbuf[1024]; char *tmpnm; char *nm; int partition; tmpnm = nm = nmbuf; while ((*dev_nm) && (*dev_nm != ',')) { *tmpnm++ = *dev_nm++; } *tmpnm = '\0'; if (*dev_nm == ',') { dev_nm++; partition = (int)(*dev_nm - 'a'); if ((partition < 0) || (partition > NDKMAP)) partition = -1; } else partition = -1; list = (disk_list_t *)val; device = nm; len = 0; while (*nm) { if (isalpha((int)*nm)) { nm++; len++; } else break; } (void) strncpy(cmpbuf, device, len); cmpbuf[len] = '\0'; if (*nm) { int mv; dv = atoi(nm); while (list) { if ((mv = strcmp(cmpbuf, list->dtype)) < 0) list = list->next; else break; } if (mv == 0) { while (list) { if (list->dnum < dv) list = list->next; else break; } if(list) { if (list->dnum == dv) { if ((partition != -1) && (list->dpart[partition] != NULL)) rv = list->dpart[partition]; else rv = list->dsk; } } } } return (rv); } static int str_is_digit(char *str) { int i; int j = 0; for (i = 0; i < (int)strlen(str); i++) { if (isdigit(str[i])) j++; } if (j == strlen(str)) return (1); else return (0); }