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