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