1 /* $NetBSD: devicename.c,v 1.9 2017/06/25 12:04:37 maxv Exp $ */
2
3 /*-
4 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 /* __FBSDID("$FreeBSD: src/sys/boot/ia64/libski/devicename.c,v 1.2 2003/09/08 09:11:32 obrien Exp $"); */
31
32 #include <lib/libsa/stand.h>
33 #include <lib/libsa/loadfile.h>
34 #include <lib/libkern/libkern.h>
35 #include <sys/disklabel.h>
36
37 #include <bootstrap.h>
38 #include "libski.h"
39
40 static int ski_parsedev(struct ski_devdesc **dev, const char *devspec, const char **path);
41
42 /*
43 * Point (dev) at an allocated device specifier for the device matching the
44 * path in (devspec). If it contains an explicit device specification,
45 * use that. If not, use the default device.
46 */
47 int
ski_getdev(void ** vdev,const char * devspec,const char ** path)48 ski_getdev(void **vdev, const char *devspec, const char **path)
49 {
50 struct ski_devdesc **dev = (struct ski_devdesc **)vdev;
51 int rv;
52
53 /*
54 * If it looks like this is just a path and no
55 * device, go with the current device.
56 */
57 if ((devspec == NULL) ||
58 (devspec[0] == '/') ||
59 (strchr(devspec, ':') == NULL)) {
60
61 if (((rv = ski_parsedev(dev, getenv("currdev"), NULL)) == 0) &&
62 (path != NULL))
63 *path = devspec;
64 return(rv);
65 }
66
67 /*
68 * Try to parse the device name off the beginning of the devspec
69 */
70 return(ski_parsedev(dev, devspec, path));
71 }
72
73 /*
74 * Point (dev) at an allocated device specifier matching the string version
75 * at the beginning of (devspec). Return a pointer to the remaining
76 * text in (path).
77 *
78 * In all cases, the beginning of (devspec) is compared to the names
79 * of known devices in the device switch, and then any following text
80 * is parsed according to the rules applied to the device type.
81 *
82 * For disk-type devices, the syntax is:
83 *
84 * disk<unit>[s<slice>][<partition>]:
85 *
86 */
87 static int
ski_parsedev(struct ski_devdesc ** dev,const char * devspec,const char ** path)88 ski_parsedev(struct ski_devdesc **dev, const char *devspec, const char **path)
89 {
90 struct ski_devdesc *idev;
91 struct devsw *dv;
92 int dv_type;
93 int i, unit, slice, partition, err;
94 char *cp = NULL;
95 const char *np;
96
97 /* minimum length check */
98 if (strlen(devspec) < 2)
99 return(EINVAL);
100
101 /* look for a device that matches */
102 for (i = 0, dv = NULL; i < ndevs; i++) {
103 if (!strncmp(devspec, devsw[i].dv_name, strlen(devsw[i].dv_name))) {
104 dv = &devsw[i];
105 break;
106 }
107 }
108
109 if (dv == NULL)
110 return(ENOENT);
111 idev = alloc(sizeof(struct ski_devdesc));
112 err = 0;
113 np = (devspec + strlen(dv->dv_name));
114
115 /* XXX: Fixme */
116 dv_type = DEVT_DISK;
117
118 switch(dv_type) {
119 case DEVT_NONE: /* XXX what to do here? Do we care? */
120 break;
121
122 case DEVT_DISK: /* XXX: Need to fix DEVT_DISK for NetBSD disk conventions. */
123 unit = -1;
124 slice = -1;
125 partition = -1;
126 if (*np && (*np != ':')) {
127 unit = strtol(np, &cp, 10); /* next comes the unit number */
128 if (cp == np) {
129 err = EUNIT;
130 goto fail;
131 }
132 if (*cp == 's') { /* got a slice number */
133 np = cp + 1;
134 slice = strtol(np, &cp, 10);
135 if (cp == np) {
136 err = EPART;
137 goto fail;
138 }
139 }
140 if (*cp && (*cp != ':')) {
141 partition = *cp - 'a'; /* get a partition number */
142 if ((partition < 0) || (partition >= MAXPARTITIONS)) {
143 err = EPART;
144 goto fail;
145 }
146 cp++;
147 }
148 }
149 if (cp == NULL) {
150 err = EINVAL;
151 goto fail;
152 }
153 if (*cp && (*cp != ':')) {
154 err = EINVAL;
155 goto fail;
156 }
157
158 idev->d_kind.skidisk.unit = unit;
159 idev->d_kind.skidisk.slice = slice;
160 idev->d_kind.skidisk.partition = partition;
161
162 if (path != NULL)
163 *path = (*cp == 0) ? cp : cp + 1;
164 break;
165
166 case DEVT_NET:
167 unit = 0;
168
169 if (*np && (*np != ':')) {
170 unit = strtol(np, &cp, 0); /* get unit number if present */
171 if (cp == np) {
172 err = EUNIT;
173 goto fail;
174 }
175 }
176 if (cp == NULL) {
177 err = EINVAL;
178 goto fail;
179 }
180 if (*cp && (*cp != ':')) {
181 err = EINVAL;
182 goto fail;
183 }
184
185 idev->d_kind.netif.unit = unit;
186 if (path != NULL)
187 *path = (*cp == 0) ? cp : cp + 1;
188 break;
189
190 default:
191 err = EINVAL;
192 goto fail;
193 }
194 idev->d_dev = dv;
195 idev->d_type = dv_type;
196 if (dev == NULL) {
197 free(idev);
198 } else {
199 *dev = idev;
200 }
201 return(0);
202
203 fail:
204 free(idev);
205 return(err);
206 }
207
208
209 char *
ski_fmtdev(void * vdev)210 ski_fmtdev(void *vdev)
211 {
212 struct ski_devdesc *dev = (struct ski_devdesc *)vdev;
213 static char buf[128]; /* XXX device length constant? */
214 size_t len, buflen = sizeof(buf);
215
216 switch(dev->d_type) {
217 case DEVT_NONE:
218 strlcpy(buf, "(no device)", buflen);
219 break;
220
221 case DEVT_DISK:
222 len = snprintf(buf, buflen, "%s%d", dev->d_dev->dv_name, dev->d_kind.skidisk.unit);
223 if (len > buflen)
224 len = buflen;
225 if (dev->d_kind.skidisk.slice > 0) {
226 len += snprintf(buf + len, buflen - len, "s%d", dev->d_kind.skidisk.slice);
227 if (len > buflen)
228 len = buflen;
229 }
230 if (dev->d_kind.skidisk.partition >= 0) {
231 len += snprintf(buf + len, buflen - len, "%c", dev->d_kind.skidisk.partition + 'a');
232 if (len > buflen)
233 len = buflen;
234 }
235 strlcat(buf, ":", buflen - len);
236 break;
237
238 case DEVT_NET:
239 snprintf(buf, buflen, "%s%d:", dev->d_dev->dv_name, dev->d_kind.netif.unit);
240 break;
241 }
242 return(buf);
243 }
244
245
246 /*
247 * Set currdev to suit the value being supplied in (value)
248 */
249 int
ski_setcurrdev(struct env_var * ev,int flags,void * value)250 ski_setcurrdev(struct env_var *ev, int flags, void *value)
251 {
252 struct ski_devdesc *ncurr;
253 int rv;
254
255 if ((rv = ski_parsedev(&ncurr, value, NULL)) != 0)
256 return(rv);
257 free(ncurr);
258 env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
259 return(0);
260 }
261
262