Home | History | Annotate | Line # | Download | only in efi
      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