1 /* $NetBSD: devpath.c,v 1.2 2026/07/04 18:27:17 kre Exp $ */ 2 3 /* 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 14 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26 #include <sys/cdefs.h> 27 #ifndef lint 28 __RCSID("$NetBSD: devpath.c,v 1.2 2026/07/04 18:27:17 kre Exp $"); 29 #endif /* not lint */ 30 31 #include <sys/queue.h> 32 33 #include <err.h> 34 #include <assert.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include <util.h> 39 40 #include "defs.h" 41 #include "devpath.h" 42 #include "devpath1.h" 43 #include "devpath2.h" 44 #include "devpath3.h" 45 #include "devpath4.h" 46 #include "devpath5.h" 47 48 #define easprintf (size_t)easprintf 49 50 typedef SIMPLEQ_HEAD(devpath_head, devpath_blk) devpath_head_t; 51 52 typedef struct devpath_blk { 53 devpath_elm_t path; 54 devpath_elm_t dbg; 55 SIMPLEQ_ENTRY(devpath_blk) entry; 56 } devpath_blk_t; 57 58 static void 59 devpath_end(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) 60 { 61 62 assert(dp->Type == 0x7f); 63 assert(dp->Length == 4); 64 65 switch (dp->SubType) { 66 case 1: 67 path->cp = estrdup(""); /* end of devpath instance */ 68 path->sz = 1; 69 break; 70 case 0xff: 71 path->cp = NULL; /* end of entire devpath */ 72 path->sz = 0; 73 break; 74 default: 75 path->sz = easprintf(&path->cp, 76 "unknown device path end subtype: %u\n", dp->SubType); 77 break; 78 } 79 80 if (dbg != NULL) 81 devpath_hdr(dp, dbg); 82 } 83 84 static char * 85 collapse_list(devpath_head_t *head, size_t plen, char **dmsg, size_t dlen) 86 { 87 devpath_blk_t *blk, *next; 88 char *bp, *path; 89 90 bp = path = emalloc(plen + 1); 91 SIMPLEQ_FOREACH_SAFE(blk, head, entry, next) { 92 if (blk->path.cp == NULL) { 93 if (next == NULL) { 94 *bp = '\0'; 95 break; 96 } 97 // *bp++=';'; /* just nothing should be OK, or ??? */ 98 continue; 99 } 100 else if (*blk->path.cp == '\0') { 101 *bp++ = ':'; 102 next = SIMPLEQ_NEXT(blk, entry); 103 } 104 else { 105 bp = stpcpy(bp, blk->path.cp); 106 if (next->path.cp != NULL && *next->path.cp != '\0') 107 *bp++ = '/'; 108 } 109 free(blk->path.cp); 110 } 111 if (dmsg) { 112 bp = *dmsg = emalloc(dlen + 1); 113 SIMPLEQ_FOREACH_SAFE(blk, head, entry, next) { 114 bp = stpcpy(bp, blk->dbg.cp); 115 free(blk->dbg.cp); 116 } 117 } 118 return path; 119 } 120 121 static void 122 devpath_parse_core(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) 123 { 124 125 switch (dp->Type) { 126 case DEVPATH_TYPE_HW: devpath_hw(dp, path, dbg); return; /* Type 1 */ 127 case DEVPATH_TYPE_ACPI: devpath_acpi(dp, path, dbg); return; /* Type 2 */ 128 case DEVPATH_TYPE_MSG: devpath_msg(dp, path, dbg); return; /* Type 3 */ 129 case DEVPATH_TYPE_MEDIA: devpath_media(dp, path, dbg); return; /* Type 4 */ 130 case DEVPATH_TYPE_BIOS: devpath_bios(dp, path, dbg); return; /* Type 5 */ 131 case DEVPATH_TYPE_END: devpath_end(dp, path, dbg); return; /* Type 0x7F */ 132 default: devpath_unsupported(dp, path, dbg); return; 133 } 134 } 135 136 PUBLIC char * 137 devpath_parse(devpath_t *dp, size_t dplen, char **dmsg) 138 { 139 devpath_head_t head = SIMPLEQ_HEAD_INITIALIZER(head); 140 devpath_blk_t *blk; 141 union { 142 char *cp; 143 devpath_t *dp; 144 } u; 145 size_t dlen = 0, plen = 0; 146 char *ep; 147 148 if (dmsg) 149 *dmsg = NULL; 150 151 u.dp = dp; 152 ep = u.cp + dplen; 153 for (/*EMPTY*/; u.cp < ep; u.cp += u.dp->Length) { 154 blk = ecalloc(1, sizeof(*blk)); 155 devpath_parse_core(u.dp, &blk->path, dmsg ? &blk->dbg : NULL); 156 plen += blk->path.sz; 157 dlen += blk->dbg.sz; 158 SIMPLEQ_INSERT_TAIL(&head, blk, entry); 159 } 160 161 return collapse_list(&head, plen, dmsg, dlen); 162 } 163