devpath.c revision 1.1 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