1 /* $NetBSD: devpath.c,v 1.1 2025/02/24 13:47:56 christos 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.1 2025/02/24 13:47:56 christos 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 *bp = '\0'; 94 assert(next == NULL); 95 break; 96 } 97 else if (*blk->path.cp == '\0') { 98 *bp++ = ':'; 99 next = SIMPLEQ_NEXT(blk, entry); 100 } 101 else { 102 bp = stpcpy(bp, blk->path.cp); 103 if (next->path.cp != NULL && *next->path.cp != '\0') 104 *bp++ = '/'; 105 } 106 free(blk->path.cp); 107 } 108 if (dmsg) { 109 bp = *dmsg = emalloc(dlen + 1); 110 SIMPLEQ_FOREACH_SAFE(blk, head, entry, next) { 111 bp = stpcpy(bp, blk->dbg.cp); 112 free(blk->dbg.cp); 113 } 114 } 115 return path; 116 } 117 118 static void 119 devpath_parse_core(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg) 120 { 121 122 switch (dp->Type) { 123 case DEVPATH_TYPE_HW: devpath_hw(dp, path, dbg); return; /* Type 1 */ 124 case DEVPATH_TYPE_ACPI: devpath_acpi(dp, path, dbg); return; /* Type 2 */ 125 case DEVPATH_TYPE_MSG: devpath_msg(dp, path, dbg); return; /* Type 3 */ 126 case DEVPATH_TYPE_MEDIA: devpath_media(dp, path, dbg); return; /* Type 4 */ 127 case DEVPATH_TYPE_BIOS: devpath_bios(dp, path, dbg); return; /* Type 5 */ 128 case DEVPATH_TYPE_END: devpath_end(dp, path, dbg); return; /* Type 0x7F */ 129 default: devpath_unsupported(dp, path, dbg); return; 130 } 131 } 132 133 PUBLIC char * 134 devpath_parse(devpath_t *dp, size_t dplen, char **dmsg) 135 { 136 devpath_head_t head = SIMPLEQ_HEAD_INITIALIZER(head); 137 devpath_blk_t *blk; 138 union { 139 char *cp; 140 devpath_t *dp; 141 } u; 142 size_t dlen = 0, plen = 0; 143 char *ep; 144 145 if (dmsg) 146 *dmsg = NULL; 147 148 u.dp = dp; 149 ep = u.cp + dplen; 150 for (/*EMPTY*/; u.cp < ep; u.cp += u.dp->Length) { 151 blk = ecalloc(1, sizeof(*blk)); 152 devpath_parse_core(u.dp, &blk->path, dmsg ? &blk->dbg : NULL); 153 plen += blk->path.sz; 154 dlen += blk->dbg.sz; 155 SIMPLEQ_INSERT_TAIL(&head, blk, entry); 156 } 157 158 return collapse_list(&head, plen, dmsg, dlen); 159 } 160