dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / cfgadm_plugins / scsi / common / cfga_cvt.c
blobe3e260f9f5c48e059b90936f5b0283cbcd9e4a95
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include "cfga_scsi.h"
28 typedef struct {
29 char *dyncomp;
30 char *devlink;
31 int l_errno;
32 scfga_ret_t ret;
33 } dyn_t;
35 typedef struct {
36 scfga_recur_t (*devlink_to_dyncomp_p)(dyn_t *dyntp);
37 scfga_recur_t (*dyncomp_to_devlink_p)(dyn_t *dyntp);
38 } dynrules_t;
40 typedef struct {
41 dyn_t *dynp;
42 dynrules_t *rule_array;
43 int nrules;
44 } dyncvt_t;
46 typedef struct {
47 const char *hba_phys;
48 const char *dyncomp;
49 char *path;
50 int l_errno;
51 scfga_ret_t ret;
52 } devpath_t;
56 /* Function prototypes */
58 static int drv_to_hba_logid(di_node_t node, di_minor_t minor, void *arg);
59 static scfga_ret_t drv_dyn_to_devpath(const char *hba_phys,
60 const char *dyncomp, char **pathpp, int *l_errnop);
61 static int do_drv_dyn_to_devpath(di_node_t node, void *arg);
62 static scfga_ret_t devlink_dyn_to_devpath(const char *hba_phys,
63 const char *dyncomp, char **pathpp, int *l_errnop);
65 static scfga_recur_t disk_dyncomp_to_devlink(dyn_t *dyntp);
66 static scfga_recur_t tape_dyncomp_to_devlink(dyn_t *dyntp);
67 static scfga_recur_t def_dyncomp_to_devlink(dyn_t *dyntp);
69 static scfga_ret_t devlink_to_dyncomp(char *devlink,
70 char **dyncompp, int *l_errnop);
71 static scfga_recur_t disk_devlink_to_dyncomp(dyn_t *dyntp);
72 static scfga_recur_t tape_devlink_to_dyncomp(dyn_t *dyntp);
73 static scfga_recur_t def_devlink_to_dyncomp(dyn_t *dyntp);
74 static scfga_ret_t drv_to_dyncomp(di_node_t node, const char *phys,
75 char **dyncompp, int *l_errnop);
76 static scfga_ret_t get_hba_devlink(const char *hba_phys,
77 char **hba_logpp, int *l_errnop);
78 static scfga_ret_t path_apid_dyn_to_path(const char *hba_phys, const char *dyn,
79 char **pathpp, int *l_errnop);
82 /* Globals */
85 * Rules for converting between a devlink and logical ap_id and vice-versa
86 * The default rules must be the last entry.
88 static dynrules_t dyncvt_rules[] = {
89 {disk_devlink_to_dyncomp, disk_dyncomp_to_devlink},
90 {tape_devlink_to_dyncomp, tape_dyncomp_to_devlink},
91 {def_devlink_to_dyncomp, def_dyncomp_to_devlink}
94 #define N_DYNRULES (sizeof (dyncvt_rules)/sizeof (dyncvt_rules[0]))
97 * Numbering of disk slices is assumed to be 0 through n - 1
99 typedef struct {
100 char *prefix;
101 int nslices;
102 } slice_t;
104 static slice_t disk_slices[] = {
105 {"s", 16},
106 {"p", 5},
109 #define N_SLICE_TYPES (sizeof (disk_slices) / sizeof (disk_slices[0]))
111 static const char *tape_modes[] = {
113 "b", "bn",
114 "c", "cb", "cbn", "cn",
115 "h", "hb", "hbn", "hn",
116 "l", "lb", "lbn", "ln",
117 "m", "mb", "mbn", "mn",
118 "n",
119 "u", "ub", "ubn", "un"
122 #define N_TAPE_MODES (sizeof (tape_modes) / sizeof (tape_modes[0]))
125 /* Various conversions routines */
128 * Generates the HBA logical ap_id from physical ap_id.
130 scfga_ret_t
131 make_hba_logid(const char *hba_phys, char **hba_logpp, int *l_errnop)
133 walkarg_t u;
134 pathm_t pmt = {NULL};
135 scfga_ret_t ret;
138 if (*hba_logpp != NULL) {
139 return (SCFGA_ERR);
142 /* A devlink for the HBA may or may not exist */
143 if (get_hba_devlink(hba_phys, hba_logpp, l_errnop) == SCFGA_OK) {
144 assert(*hba_logpp != NULL);
145 return (SCFGA_OK);
149 * No devlink based logical ap_id.
150 * Try driver name and instance number.
152 u.minor_args.nodetype = DDI_NT_SCSI_ATTACHMENT_POINT;
153 u.minor_args.fcn = drv_to_hba_logid;
155 pmt.phys = (char *)hba_phys;
156 pmt.ret = SCFGA_APID_NOEXIST;
158 errno = 0;
159 ret = walk_tree(pmt.phys, &pmt, DINFOMINOR | DINFOPROP, &u,
160 SCFGA_WALK_MINOR, &pmt.l_errno);
161 if (ret == SCFGA_OK && (ret = pmt.ret) == SCFGA_OK) {
162 assert(pmt.log != NULL);
163 *hba_logpp = pmt.log;
164 return (SCFGA_OK);
167 /* failed to create logical ap_id */
168 if (pmt.log != NULL) {
169 S_FREE(pmt.log);
173 *l_errnop = pmt.l_errno;
174 return (ret);
177 static scfga_ret_t
178 get_hba_devlink(const char *hba_phys, char **hba_logpp, int *l_errnop)
180 size_t len;
181 scfga_ret_t ret;
182 int match_minor = 1;
184 ret = physpath_to_devlink((char *)hba_phys, hba_logpp,
185 l_errnop, match_minor);
186 if (ret != SCFGA_OK) {
187 return (ret);
190 assert(*hba_logpp != NULL);
192 /* Remove the "/dev/cfg/" prefix */
193 len = strlen(CFGA_DEV_DIR SLASH);
195 (void) memmove(*hba_logpp, *hba_logpp + len,
196 strlen(*hba_logpp + len) + 1);
198 return (SCFGA_OK);
201 /* Make logical name for HBA based on driver and instance */
202 static int
203 drv_to_hba_logid(di_node_t node, di_minor_t minor, void *arg)
205 int inst;
206 char *drv, *mn, *log;
207 pathm_t *ptp;
208 const size_t loglen = MAXPATHLEN;
210 ptp = (pathm_t *)arg;
212 errno = 0;
214 mn = di_minor_name(minor);
215 drv = di_driver_name(node);
216 inst = di_instance(node);
217 log = calloc(1, loglen);
219 if (mn != NULL && drv != NULL && inst != -1 && log != NULL) {
220 /* Count does not include terminating NULL */
221 if (snprintf(log, loglen, "%s%d:%s", drv, inst, mn) < loglen) {
222 ptp->ret = SCFGA_OK;
223 ptp->log = log;
224 return (DI_WALK_TERMINATE);
228 S_FREE(log);
229 return (DI_WALK_CONTINUE);
233 * Given a bus or device ap_id <hba_phys, dyncomp>, returns the physical
234 * path in pathpp.
235 * Returns: SCFGA_APID_NOEXIST if the path does not exist.
238 scfga_ret_t
239 apid_to_path(
240 const char *hba_phys,
241 const char *dyncomp,
242 char **pathpp,
243 int *l_errnop)
245 scfga_ret_t ret;
247 if (*pathpp != NULL) {
248 return (SCFGA_LIB_ERR);
251 /* If a bus, the physical ap_id is the physical path */
252 if (dyncomp == NULL) {
253 if ((*pathpp = strdup(hba_phys)) == NULL) {
254 *l_errnop = errno;
255 return (SCFGA_LIB_ERR);
257 return (SCFGA_OK);
260 /* Dynamic component exists, we have a device */
263 * If the dynamic component has a '/', it was derived from a devlink
264 * Else it was derived from driver name and instance number.
265 * If it is pathinfo instance number based ap id, it will have a format
266 * path#.???.
268 if (strchr(dyncomp, '/') != NULL) {
269 ret = devlink_dyn_to_devpath(hba_phys, dyncomp, pathpp,
270 l_errnop);
271 } else if (strstr(dyncomp, PATH_APID_DYN_SEP) != NULL) {
272 ret = path_apid_dyn_to_path(hba_phys, dyncomp, pathpp,
273 l_errnop);
274 } else {
275 ret = drv_dyn_to_devpath(hba_phys, dyncomp, pathpp, l_errnop);
277 assert(ret != SCFGA_OK || *pathpp != NULL);
280 return (ret);
284 * Get the devfs path of pathinfo node that is associated with
285 * the given dynamic component.
287 * input
288 * hba_phys: physical path of HBA
289 * dyn : bus address of pathinfo node
290 * output:
291 * pathpp: devfs path of the pathinfo node.
293 static scfga_ret_t
294 path_apid_dyn_to_path(
295 const char *hba_phys,
296 const char *dyn,
297 char **pathpp,
298 int *l_errnop)
301 di_node_t root, walk_root;
302 di_path_t pi_node = DI_PATH_NIL;
303 char *root_path, *devpath, *cp;
304 int len;
306 *l_errnop = 0;
308 /* *pathpp should be NULL if pathpp is not NULL. */
309 if ((hba_phys == NULL) || (pathpp != NULL) && (*pathpp != NULL)) {
310 return (SCFGA_LIB_ERR);
313 if ((root_path = strdup(hba_phys)) == NULL) {
314 *l_errnop = errno;
315 return (SCFGA_LIB_ERR);
318 /* Fix up path for di_init() */
319 len = strlen(DEVICES_DIR);
320 if (strncmp(root_path, DEVICES_DIR SLASH,
321 len + strlen(SLASH)) == 0) {
322 cp = root_path + len;
323 (void) memmove(root_path, cp, strlen(cp) + 1);
324 } else if (*root_path != '/') {
325 *l_errnop = 0;
326 S_FREE(root_path);
327 return (SCFGA_ERR);
330 /* Remove dynamic component if any */
331 if ((cp = GET_DYN(root_path)) != NULL) {
332 *cp = '\0';
335 /* Remove minor name if any */
336 if ((cp = strrchr(root_path, ':')) != NULL) {
337 *cp = '\0';
341 * Cached snapshots are always rooted at "/"
344 /* Get a snapshot */
345 if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
346 *l_errnop = errno;
347 S_FREE(root_path);
348 return (SCFGA_ERR);
352 * Lookup the subtree of interest
354 walk_root = di_lookup_node(root, root_path);
356 if (walk_root == DI_NODE_NIL) {
357 *l_errnop = errno;
358 di_fini(root);
359 S_FREE(root_path);
360 return (SCFGA_LIB_ERR);
363 S_FREE(root_path);
365 if ((pi_node = di_path_next_client(walk_root, pi_node)) ==
366 DI_PATH_NIL) {
367 di_fini(root);
368 return (SCFGA_APID_NOEXIST);
372 * now parse the path info node.
374 do {
375 /* check the length first. */
376 if (strlen(di_path_bus_addr(pi_node)) != strlen(dyn)) {
377 continue;
380 if (strcmp(di_path_bus_addr(pi_node), dyn) == 0) {
381 /* get the devfspath of pathinfo node. */
382 devpath = di_path_devfs_path(pi_node);
383 if (devpath == NULL) {
384 *l_errnop = errno;
385 di_fini(root);
386 return (SCFGA_ERR);
389 len = strlen(DEVICES_DIR) + strlen(devpath) + 1;
390 *pathpp = calloc(1, len);
391 if (*pathpp == NULL) {
392 *l_errnop = errno;
393 di_devfs_path_free(devpath);
394 di_fini(root);
395 return (SCFGA_ERR);
396 } else {
397 (void) snprintf(*pathpp, len, "%s%s",
398 DEVICES_DIR, devpath);
399 di_devfs_path_free(devpath);
400 di_fini(root);
401 return (SCFGA_OK);
404 pi_node = di_path_next_client(walk_root, pi_node);
405 } while (pi_node != DI_PATH_NIL);
407 di_fini(root);
408 return (SCFGA_APID_NOEXIST);
411 static scfga_ret_t
412 drv_dyn_to_devpath(
413 const char *hba_phys,
414 const char *dyncomp,
415 char **pathpp,
416 int *l_errnop)
418 walkarg_t u;
419 devpath_t dpt = {NULL};
420 scfga_ret_t ret;
422 /* A device MUST have a dynamic component */
423 if (dyncomp == NULL || *pathpp != NULL) {
424 return (SCFGA_LIB_ERR);
427 u.node_args.flags = DI_WALK_CLDFIRST;
428 u.node_args.fcn = do_drv_dyn_to_devpath;
430 dpt.hba_phys = hba_phys;
431 dpt.dyncomp = dyncomp;
432 dpt.ret = SCFGA_APID_NOEXIST;
434 ret = walk_tree(hba_phys, &dpt, DINFOCPYALL, &u,
435 SCFGA_WALK_NODE, &dpt.l_errno);
437 if (ret == SCFGA_OK && (ret = dpt.ret) == SCFGA_OK) {
438 assert(dpt.path != NULL);
439 *pathpp = dpt.path;
440 return (SCFGA_OK);
443 if (dpt.path != NULL) {
444 S_FREE(dpt.path);
448 *l_errnop = dpt.l_errno;
449 return (ret);
452 /* Converts a driver and instance number based logid into a physical path */
453 static int
454 do_drv_dyn_to_devpath(di_node_t node, void *arg)
456 int inst, rv, match_minor;
457 devpath_t *dptp;
458 char *physpath, *drv;
459 char *drvinst, *devpath;
460 const size_t drvlen = MAXPATHLEN;
461 size_t devlen;
463 dptp = (devpath_t *)arg;
465 assert(dptp->hba_phys != NULL && dptp->dyncomp != NULL);
466 assert(dptp->path == NULL);
469 * Skip stub nodes
471 if (IS_STUB_NODE(node)) {
472 return (DI_WALK_CONTINUE);
475 errno = 0;
477 drv = di_driver_name(node);
478 inst = di_instance(node);
479 physpath = di_devfs_path(node);
480 if (drv == NULL || inst == -1 || physpath == NULL) {
481 rv = DI_WALK_CONTINUE;
482 goto out;
485 devlen = strlen(DEVICES_DIR) + strlen(physpath) + 1;
487 devpath = calloc(1, devlen);
488 drvinst = calloc(1, drvlen);
489 if (devpath == NULL || drvinst == NULL) {
490 dptp->l_errno = errno;
491 dptp->ret = SCFGA_LIB_ERR;
492 rv = DI_WALK_TERMINATE;
493 goto out;
496 (void) snprintf(drvinst, drvlen, "%s%d", drv, inst);
498 /* Create the physical path */
499 (void) snprintf(devpath, devlen, "%s%s", DEVICES_DIR, physpath);
501 /* Skip node if it is the HBA */
502 match_minor = 0;
503 if (!dev_cmp(dptp->hba_phys, devpath, match_minor)) {
504 rv = DI_WALK_CONTINUE;
505 goto out;
508 /* Compare the base and dynamic components */
509 if (!hba_dev_cmp(dptp->hba_phys, devpath) &&
510 strcmp(dptp->dyncomp, drvinst) == 0) {
511 dptp->ret = SCFGA_OK;
512 dptp->path = devpath;
513 rv = DI_WALK_TERMINATE;
514 } else {
515 rv = DI_WALK_CONTINUE;
518 /*FALLTHRU*/
519 out:
520 S_FREE(drvinst);
521 if (physpath != NULL) di_devfs_path_free(physpath);
522 if (dptp->ret != SCFGA_OK) S_FREE(devpath);
523 return (rv);
526 /* readlink wrapper to ensure proper null termination of the results */
527 static int
528 s_readlink(char *link, char *buf, int len)
530 int count;
532 count = readlink(link, buf, len - 1);
533 if (count != -1)
534 buf[count] = '\0';
535 return (count);
538 /* Converts a devlink based dynamic component to a path */
539 static scfga_ret_t
540 devlink_dyn_to_devpath(
541 const char *hba_phys,
542 const char *dyncomp,
543 char **pathpp,
544 int *l_errnop)
546 dyn_t dynt = {NULL};
547 int i;
548 scfga_ret_t ret;
549 char buf[PATH_MAX], *path;
551 if (*pathpp != NULL) {
552 return (SCFGA_LIB_ERR);
555 /* Convert the dynamic component to the corresponding devlink */
556 dynt.dyncomp = (char *)dyncomp;
557 dynt.ret = SCFGA_APID_NOEXIST;
559 for (i = 0; i < N_DYNRULES; i++) {
560 if (dyncvt_rules[i].dyncomp_to_devlink_p(&dynt)
561 != SCFGA_CONTINUE) {
562 break;
566 if (i >= N_DYNRULES) {
567 dynt.ret = SCFGA_APID_NOEXIST;
570 if (dynt.ret != SCFGA_OK) {
571 /* No symlink or error */
572 return (dynt.ret);
575 assert(dynt.devlink != NULL);
578 * Follow devlink to get the physical path
579 * Note: Do not use realpath(). It will stat() device
580 * and stat() fails under devfs if device is offline.
582 errno = 0;
583 if ((s_readlink(dynt.devlink, buf, PATH_MAX) == -1) ||
584 ((path = strstr(buf, "/devices/")) == NULL) ||
585 ((*pathpp = strdup(path)) == NULL)) {
586 *l_errnop = errno;
587 ret = SCFGA_LIB_ERR;
588 goto out;
591 /* Compare base components as well */
592 if (!hba_dev_cmp(hba_phys, path)) {
593 ret = SCFGA_OK;
594 } else {
595 /* Mismatched base and dynamic component */
596 *l_errnop = 0;
597 ret = SCFGA_APID_NOEXIST;
600 /*FALLTHRU*/
601 out:
602 S_FREE(dynt.devlink);
603 if (ret != SCFGA_OK) S_FREE(*pathpp);
604 return (ret);
607 scfga_ret_t
608 make_dyncomp(
609 di_node_t node,
610 const char *physpath,
611 char **dyncompp,
612 int *l_errnop)
614 char *devlink = NULL;
615 scfga_ret_t ret;
616 di_minor_t minor;
617 char *path;
618 char pathbuf[MAXPATHLEN];
619 int match_minor;
621 if (*dyncompp != NULL) {
622 return (SCFGA_LIB_ERR);
625 /* tag on minor name */
626 minor = di_minor_next(node, DI_MINOR_NIL);
627 if (minor == DI_MINOR_NIL) {
628 match_minor = 0;
629 path = (char *)physpath;
630 } else {
631 match_minor = 1;
632 (void) snprintf(pathbuf, MAXPATHLEN, "%s:%s", physpath,
633 di_minor_name(minor));
634 path = pathbuf;
637 /* Get the corresponding devlink from the physical path */
638 ret = physpath_to_devlink(path, &devlink, l_errnop, match_minor);
639 if (ret == SCFGA_OK) {
640 assert(devlink != NULL);
642 /* Create dynamic component. */
643 ret = devlink_to_dyncomp(devlink, dyncompp, l_errnop);
644 S_FREE(devlink);
645 if (ret == SCFGA_OK) {
646 assert(*dyncompp != NULL);
647 return (SCFGA_OK);
651 * Failed to get devlink based dynamic component.
652 * Try driver and instance
656 ret = drv_to_dyncomp(node, physpath, dyncompp, l_errnop);
657 assert(ret != SCFGA_OK || *dyncompp != NULL);
659 return (ret);
663 * Create a dynamic component of path ap_id for the given path info node.
664 * The caller should free the buffer for the dynamic component.
666 scfga_ret_t
667 make_path_dyncomp(
668 di_path_t path,
669 char **dyncompp,
670 int *l_errnop)
672 char *pi_addr;
674 if ((path == DI_PATH_NIL) || (*dyncompp != NULL)) {
675 return (SCFGA_LIB_ERR);
678 if ((pi_addr = di_path_bus_addr(path)) != NULL) {
679 *dyncompp = calloc(1, strlen(pi_addr) + 1);
680 if (*dyncompp == NULL) {
681 *l_errnop = errno;
682 return (SCFGA_LIB_ERR);
684 (void) strncpy(*dyncompp, pi_addr, strlen(pi_addr));
685 } else {
686 return (SCFGA_LIB_ERR);
689 return (SCFGA_OK);
692 /*ARGSUSED*/
693 static scfga_ret_t
694 drv_to_dyncomp(di_node_t node, const char *phys, char **dyncompp, int *l_errnop)
696 char *drv;
697 int inst;
698 const int dynlen = MAXPATHLEN;
699 scfga_ret_t ret;
701 *l_errnop = 0;
703 if ((*dyncompp = calloc(1, dynlen)) == NULL) {
704 *l_errnop = errno;
705 return (SCFGA_LIB_ERR);
708 drv = di_driver_name(node);
709 inst = di_instance(node);
710 if (drv != NULL && inst != -1) {
711 if (snprintf(*dyncompp, dynlen, "%s%d", drv, inst) < dynlen) {
712 return (SCFGA_OK);
713 } else {
714 ret = SCFGA_LIB_ERR;
716 } else {
717 ret = SCFGA_APID_NOEXIST;
720 S_FREE(*dyncompp);
721 return (ret);
724 /* Get a dynamic component from a physical path if possible */
725 static scfga_ret_t
726 devlink_to_dyncomp(char *devlink, char **dyncompp, int *l_errnop)
728 int i;
729 dyn_t dynt = {NULL};
731 *l_errnop = 0;
733 if (*dyncompp != NULL) {
734 return (SCFGA_LIB_ERR);
737 /* Convert devlink to dynamic component */
738 dynt.devlink = devlink;
739 dynt.ret = SCFGA_APID_NOEXIST;
741 for (i = 0; i < N_DYNRULES; i++) {
742 if (dyncvt_rules[i].devlink_to_dyncomp_p(&dynt)
743 != SCFGA_CONTINUE) {
744 break;
748 if (i >= N_DYNRULES) {
749 dynt.ret = SCFGA_APID_NOEXIST;
752 if (dynt.ret == SCFGA_OK) {
753 assert(dynt.dyncomp != NULL);
754 *dyncompp = dynt.dyncomp;
757 return (dynt.ret);
760 /* For disks remove partition information, (s or p) */
761 static scfga_recur_t
762 disk_devlink_to_dyncomp(dyn_t *dyntp)
764 char *cp = NULL, *cp1 = NULL;
766 assert(dyntp->devlink != NULL);
768 dyntp->l_errno = 0;
770 if (dyntp->dyncomp != NULL) {
771 goto lib_err;
774 /* Check if a disk devlink */
775 if (strncmp(dyntp->devlink, DEV_DSK SLASH, strlen(DEV_DSK SLASH)) &&
776 strncmp(dyntp->devlink, DEV_RDSK SLASH, strlen(DEV_RDSK SLASH))) {
777 return (SCFGA_CONTINUE);
780 cp = dyntp->devlink + strlen(DEV_DIR SLASH);
782 if ((dyntp->dyncomp = strdup(cp)) == NULL) {
783 dyntp->l_errno = errno;
784 goto lib_err;
787 /* Get the leaf component from dsk/cXtYdZsN */
788 cp1 = strrchr(dyntp->dyncomp, '/');
790 /* Blank out partition information */
791 dyntp->ret = SCFGA_OK;
792 if ((cp = strchr(cp1 + 1, 's')) != NULL) {
793 *cp = '\0';
794 } else if ((cp = strchr(cp1 + 1, 'p')) != NULL) {
795 *cp = '\0';
796 } else {
797 S_FREE(dyntp->dyncomp);
798 dyntp->ret = SCFGA_ERR;
801 return (SCFGA_TERMINATE);
803 lib_err:
804 dyntp->ret = SCFGA_LIB_ERR;
805 return (SCFGA_TERMINATE);
809 static scfga_recur_t
810 disk_dyncomp_to_devlink(dyn_t *dyntp)
812 char buf[MAXPATHLEN], *cp = NULL;
813 int i, j;
814 size_t len;
815 struct stat sbuf;
817 assert(dyntp->dyncomp != NULL);
819 dyntp->l_errno = 0;
821 if (dyntp->devlink != NULL) {
822 dyntp->ret = SCFGA_LIB_ERR;
823 return (SCFGA_TERMINATE);
826 /* A disk link can only be from DEV_DSK (ignore /dev/rdsk) */
827 if (strncmp(dyntp->dyncomp, DSK_DIR SLASH, strlen(DSK_DIR SLASH)) != 0)
828 return (SCFGA_CONTINUE); /* not a disk link */
830 (void) snprintf(buf, sizeof (buf), "%s%s", DEV_DIR SLASH,
831 dyntp->dyncomp);
833 len = strlen(buf);
834 cp = buf + len;
835 len = sizeof (buf) - len;
837 for (i = 0; i < N_SLICE_TYPES; i++) {
838 for (j = 0; j < disk_slices[i].nslices; j++) {
839 if (snprintf(cp, len, "%s%d", disk_slices[i].prefix, j)
840 >= len) {
841 continue;
844 if (lstat(buf, &sbuf) != -1 && S_ISLNK(sbuf.st_mode)) {
845 if ((dyntp->devlink = strdup(buf)) == NULL) {
846 dyntp->l_errno = errno;
847 dyntp->ret = SCFGA_LIB_ERR;
848 return (SCFGA_TERMINATE);
850 dyntp->ret = SCFGA_OK;
851 return (SCFGA_TERMINATE);
856 dyntp->ret = SCFGA_APID_NOEXIST;
857 return (SCFGA_TERMINATE);
860 /* For tapes, remove mode(minor) information from link */
861 static scfga_recur_t
862 tape_devlink_to_dyncomp(dyn_t *dyntp)
864 char *cp = NULL;
866 assert(dyntp->devlink != NULL);
868 dyntp->l_errno = 0;
870 if (dyntp->dyncomp != NULL) {
871 goto lib_err;
874 if (strncmp(dyntp->devlink, DEV_RMT SLASH, strlen(DEV_RMT SLASH))) {
875 return (SCFGA_CONTINUE); /* not a tape */
878 cp = dyntp->devlink + strlen(DEV_DIR SLASH);
879 if ((dyntp->dyncomp = strdup(cp)) == NULL) {
880 dyntp->l_errno = errno;
881 goto lib_err;
884 /* Get the leaf component from rmt/xyz */
885 cp = strrchr(dyntp->dyncomp, '/');
887 /* Remove the mode part */
888 while (isdigit(*(++cp))) {
890 *cp = '\0';
893 dyntp->ret = SCFGA_OK;
894 return (SCFGA_TERMINATE);
896 lib_err:
897 dyntp->ret = SCFGA_LIB_ERR;
898 return (SCFGA_TERMINATE);
901 static scfga_recur_t
902 tape_dyncomp_to_devlink(dyn_t *dyntp)
904 char buf[MAXPATHLEN], *cp = NULL;
905 int i;
906 size_t len = 0;
907 struct stat sbuf;
909 assert(dyntp->dyncomp != NULL);
911 dyntp->l_errno = 0;
913 if (dyntp->devlink != NULL) {
914 goto lib_err;
917 if (strncmp(dyntp->dyncomp, RMT_DIR SLASH, strlen(RMT_DIR SLASH))) {
918 return (SCFGA_CONTINUE); /* not a tape */
921 /* A tape device */
922 (void) snprintf(buf, sizeof (buf), "%s%s", DEV_DIR SLASH,
923 dyntp->dyncomp);
925 len = strlen(buf);
926 cp = buf + len;
927 len = sizeof (buf) - len;
929 for (i = 0; i < N_TAPE_MODES; i++) {
930 (void) snprintf(cp, len, "%s", tape_modes[i]);
932 if (lstat(buf, &sbuf) != -1 && S_ISLNK(sbuf.st_mode)) {
933 if ((dyntp->devlink = strdup(buf)) == NULL) {
934 dyntp->l_errno = errno;
935 goto lib_err;
937 dyntp->ret = SCFGA_OK;
938 return (SCFGA_TERMINATE);
942 dyntp->ret = SCFGA_APID_NOEXIST;
943 return (SCFGA_TERMINATE);
945 lib_err:
946 dyntp->ret = SCFGA_LIB_ERR;
947 return (SCFGA_TERMINATE);
952 * Default rules
954 static scfga_recur_t
955 def_devlink_to_dyncomp(dyn_t *dyntp)
957 size_t len = 0;
958 char *cp = NULL;
960 assert(dyntp->devlink != NULL);
962 dyntp->l_errno = 0;
964 if (dyntp->dyncomp != NULL) {
965 dyntp->ret = SCFGA_LIB_ERR;
966 return (SCFGA_TERMINATE);
969 /* Is it a link in DEV_DIR directory ? */
970 len = strlen(DEV_DIR SLASH);
971 if (strncmp(dyntp->devlink, DEV_DIR SLASH, len)) {
972 return (SCFGA_CONTINUE);
975 /* Check if this is a top level devlink */
976 if (strchr(dyntp->devlink + len, '/') != NULL) {
977 /* not top level - Remove DEV_DIR SLASH prefix */
978 cp = dyntp->devlink + len;
979 } else {
980 /* top level, leave DEV_DIR SLASH part in */
981 cp = dyntp->devlink;
984 if ((dyntp->dyncomp = strdup(cp)) == NULL) {
985 dyntp->l_errno = errno;
986 dyntp->ret = SCFGA_LIB_ERR;
987 } else {
988 dyntp->ret = SCFGA_OK;
991 return (SCFGA_TERMINATE);
995 static scfga_recur_t
996 def_dyncomp_to_devlink(dyn_t *dyntp)
998 struct stat sbuf;
999 int top;
1000 size_t prelen, linklen;
1002 assert(dyntp->dyncomp != NULL);
1004 dyntp->l_errno = 0;
1006 if (dyntp->devlink != NULL) {
1007 goto lib_err;
1010 prelen = strlen(DEV_DIR SLASH);
1011 linklen = strlen(dyntp->dyncomp) + 1;
1014 * Check if the dynamic component was derived from a top level entry
1015 * in "/dev"
1017 if (strncmp(dyntp->dyncomp, DEV_DIR SLASH, prelen) == 0) {
1018 top = 1;
1019 } else if (*dyntp->dyncomp != '/' && linklen > 1 &&
1020 strchr(dyntp->dyncomp + 1, '/') != NULL) {
1021 top = 0;
1022 linklen += prelen; /* The "/dev/" needs to be prepended */
1023 } else {
1024 /* Not a dynamic component we handle */
1025 return (SCFGA_CONTINUE);
1028 if ((dyntp->devlink = calloc(1, linklen)) == NULL) {
1029 dyntp->l_errno = errno;
1030 goto lib_err;
1033 *dyntp->devlink = '\0';
1034 if (!top) {
1035 (void) strcpy(dyntp->devlink, DEV_DIR SLASH);
1037 (void) strcat(dyntp->devlink, dyntp->dyncomp);
1039 if (lstat(dyntp->devlink, &sbuf) != -1 && S_ISLNK(sbuf.st_mode)) {
1040 dyntp->ret = SCFGA_OK;
1041 return (SCFGA_TERMINATE);
1045 S_FREE(dyntp->devlink);
1046 return (SCFGA_CONTINUE);
1048 lib_err:
1049 dyntp->ret = SCFGA_LIB_ERR;
1050 return (SCFGA_TERMINATE);