1 | /* $NetBSD: kern_subr.c,v 1.217 2016/05/12 02:24:16 ozaki-r Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 1997, 1998, 1999, 2002, 2007, 2008 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, |
9 | * NASA Ames Research Center, and by Luke Mewburn. |
10 | * |
11 | * Redistribution and use in source and binary forms, with or without |
12 | * modification, are permitted provided that the following conditions |
13 | * are met: |
14 | * 1. Redistributions of source code must retain the above copyright |
15 | * notice, this list of conditions and the following disclaimer. |
16 | * 2. Redistributions in binary form must reproduce the above copyright |
17 | * notice, this list of conditions and the following disclaimer in the |
18 | * documentation and/or other materials provided with the distribution. |
19 | * |
20 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
22 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
30 | * POSSIBILITY OF SUCH DAMAGE. |
31 | */ |
32 | |
33 | /* |
34 | * Copyright (c) 1982, 1986, 1991, 1993 |
35 | * The Regents of the University of California. All rights reserved. |
36 | * (c) UNIX System Laboratories, Inc. |
37 | * All or some portions of this file are derived from material licensed |
38 | * to the University of California by American Telephone and Telegraph |
39 | * Co. or Unix System Laboratories, Inc. and are reproduced herein with |
40 | * the permission of UNIX System Laboratories, Inc. |
41 | * |
42 | * Copyright (c) 1992, 1993 |
43 | * The Regents of the University of California. All rights reserved. |
44 | * |
45 | * This software was developed by the Computer Systems Engineering group |
46 | * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and |
47 | * contributed to Berkeley. |
48 | * |
49 | * All advertising materials mentioning features or use of this software |
50 | * must display the following acknowledgement: |
51 | * This product includes software developed by the University of |
52 | * California, Lawrence Berkeley Laboratory. |
53 | * |
54 | * Redistribution and use in source and binary forms, with or without |
55 | * modification, are permitted provided that the following conditions |
56 | * are met: |
57 | * 1. Redistributions of source code must retain the above copyright |
58 | * notice, this list of conditions and the following disclaimer. |
59 | * 2. Redistributions in binary form must reproduce the above copyright |
60 | * notice, this list of conditions and the following disclaimer in the |
61 | * documentation and/or other materials provided with the distribution. |
62 | * 3. Neither the name of the University nor the names of its contributors |
63 | * may be used to endorse or promote products derived from this software |
64 | * without specific prior written permission. |
65 | * |
66 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
67 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
68 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
69 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
70 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
71 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
72 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
73 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
74 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
75 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
76 | * SUCH DAMAGE. |
77 | * |
78 | * @(#)kern_subr.c 8.4 (Berkeley) 2/14/95 |
79 | */ |
80 | |
81 | #include <sys/cdefs.h> |
82 | __KERNEL_RCSID(0, "$NetBSD: kern_subr.c,v 1.217 2016/05/12 02:24:16 ozaki-r Exp $" ); |
83 | |
84 | #include "opt_ddb.h" |
85 | #include "opt_md.h" |
86 | #include "opt_tftproot.h" |
87 | |
88 | #include <sys/param.h> |
89 | #include <sys/systm.h> |
90 | #include <sys/proc.h> |
91 | #include <sys/mount.h> |
92 | #include <sys/device.h> |
93 | #include <sys/reboot.h> |
94 | #include <sys/conf.h> |
95 | #include <sys/disk.h> |
96 | #include <sys/disklabel.h> |
97 | #include <sys/queue.h> |
98 | #include <sys/fcntl.h> |
99 | #include <sys/kauth.h> |
100 | #include <sys/stat.h> |
101 | #include <sys/vnode.h> |
102 | #include <sys/module.h> |
103 | |
104 | #include <dev/cons.h> |
105 | |
106 | #include <net/if.h> |
107 | |
108 | /* XXX these should eventually move to subr_autoconf.c */ |
109 | static device_t finddevice(const char *); |
110 | static device_t getdisk(char *, int, int, dev_t *, int); |
111 | static device_t parsedisk(char *, int, int, dev_t *); |
112 | static const char *getwedgename(const char *, int); |
113 | |
114 | #ifdef TFTPROOT |
115 | int tftproot_dhcpboot(device_t); |
116 | #endif |
117 | |
118 | dev_t dumpcdev; /* for savecore */ |
119 | |
120 | static int |
121 | isswap(device_t dv) |
122 | { |
123 | struct dkwedge_info wi; |
124 | struct vnode *vn; |
125 | int error; |
126 | |
127 | if (device_class(dv) != DV_DISK || !device_is_a(dv, "dk" )) |
128 | return 0; |
129 | |
130 | if ((vn = opendisk(dv)) == NULL) |
131 | return 0; |
132 | |
133 | error = VOP_IOCTL(vn, DIOCGWEDGEINFO, &wi, FREAD, NOCRED); |
134 | VOP_CLOSE(vn, FREAD, NOCRED); |
135 | vput(vn); |
136 | if (error) { |
137 | #ifdef DEBUG_WEDGE |
138 | printf("%s: Get wedge info returned %d\n" , device_xname(dv), error); |
139 | #endif |
140 | return 0; |
141 | } |
142 | return strcmp(wi.dkw_ptype, DKW_PTYPE_SWAP) == 0; |
143 | } |
144 | |
145 | /* |
146 | * Determine the root device and, if instructed to, the root file system. |
147 | */ |
148 | |
149 | #ifdef MEMORY_DISK_IS_ROOT |
150 | int md_is_root = 1; |
151 | #else |
152 | int md_is_root = 0; |
153 | #endif |
154 | |
155 | /* |
156 | * The device and partition that we booted from. |
157 | */ |
158 | device_t booted_device; |
159 | int booted_partition; |
160 | daddr_t booted_startblk; |
161 | uint64_t booted_nblks; |
162 | char *bootspec; |
163 | |
164 | /* |
165 | * Use partition letters if it's a disk class but not a wedge. |
166 | * XXX Check for wedge is kinda gross. |
167 | */ |
168 | #define DEV_USES_PARTITIONS(dv) \ |
169 | (device_class((dv)) == DV_DISK && \ |
170 | !device_is_a((dv), "dk")) |
171 | |
172 | void |
173 | setroot(device_t bootdv, int bootpartition) |
174 | { |
175 | device_t dv; |
176 | deviter_t di; |
177 | int len, majdev; |
178 | dev_t nrootdev; |
179 | dev_t ndumpdev = NODEV; |
180 | char buf[128]; |
181 | const char *rootdevname; |
182 | const char *dumpdevname; |
183 | device_t rootdv = NULL; /* XXX gcc -Wuninitialized */ |
184 | device_t dumpdv = NULL; |
185 | struct ifnet *ifp; |
186 | const char *deffsname; |
187 | struct vfsops *vops; |
188 | |
189 | #ifdef TFTPROOT |
190 | if (tftproot_dhcpboot(bootdv) != 0) |
191 | boothowto |= RB_ASKNAME; |
192 | #endif |
193 | |
194 | /* |
195 | * For root on md0 we have to force the attachment of md0. |
196 | */ |
197 | if (md_is_root) { |
198 | int md_major; |
199 | dev_t md_dev; |
200 | |
201 | bootdv = NULL; |
202 | md_major = devsw_name2blk("md" , NULL, 0); |
203 | if (md_major >= 0) { |
204 | md_dev = MAKEDISKDEV(md_major, 0, RAW_PART); |
205 | if (bdev_open(md_dev, FREAD, S_IFBLK, curlwp) == 0) |
206 | bootdv = device_find_by_xname("md0" ); |
207 | } |
208 | if (bootdv == NULL) |
209 | panic("Cannot open \"md0\" (root)" ); |
210 | } |
211 | |
212 | /* |
213 | * Let bootcode augment "rootspec". |
214 | */ |
215 | if (rootspec == NULL) |
216 | rootspec = bootspec; |
217 | |
218 | /* |
219 | * If NFS is specified as the file system, and we found |
220 | * a DV_DISK boot device (or no boot device at all), then |
221 | * find a reasonable network interface for "rootspec". |
222 | */ |
223 | vops = vfs_getopsbyname(MOUNT_NFS); |
224 | if (vops != NULL && strcmp(rootfstype, MOUNT_NFS) == 0 && |
225 | rootspec == NULL && |
226 | (bootdv == NULL || device_class(bootdv) != DV_IFNET)) { |
227 | int s = pserialize_read_enter(); |
228 | IFNET_READER_FOREACH(ifp) { |
229 | if ((ifp->if_flags & |
230 | (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0) |
231 | break; |
232 | } |
233 | if (ifp == NULL) { |
234 | /* |
235 | * Can't find a suitable interface; ask the |
236 | * user. |
237 | */ |
238 | boothowto |= RB_ASKNAME; |
239 | } else { |
240 | /* |
241 | * Have a suitable interface; behave as if |
242 | * the user specified this interface. |
243 | */ |
244 | rootspec = (const char *)ifp->if_xname; |
245 | } |
246 | pserialize_read_exit(s); |
247 | } |
248 | if (vops != NULL) |
249 | vfs_delref(vops); |
250 | |
251 | /* |
252 | * If wildcarded root and we the boot device wasn't determined, |
253 | * ask the user. |
254 | */ |
255 | if (rootspec == NULL && bootdv == NULL) |
256 | boothowto |= RB_ASKNAME; |
257 | |
258 | top: |
259 | if (boothowto & RB_ASKNAME) { |
260 | device_t defdumpdv; |
261 | |
262 | for (;;) { |
263 | printf("root device" ); |
264 | if (bootdv != NULL) { |
265 | printf(" (default %s" , device_xname(bootdv)); |
266 | if (DEV_USES_PARTITIONS(bootdv)) |
267 | printf("%c" , bootpartition + 'a'); |
268 | printf(")" ); |
269 | } |
270 | printf(": " ); |
271 | len = cngetsn(buf, sizeof(buf)); |
272 | if (len == 0 && bootdv != NULL) { |
273 | strlcpy(buf, device_xname(bootdv), sizeof(buf)); |
274 | len = strlen(buf); |
275 | } |
276 | if (len > 0 && buf[len - 1] == '*') { |
277 | buf[--len] = '\0'; |
278 | dv = getdisk(buf, len, 1, &nrootdev, 0); |
279 | if (dv != NULL) { |
280 | rootdv = dv; |
281 | break; |
282 | } |
283 | } |
284 | dv = getdisk(buf, len, bootpartition, &nrootdev, 0); |
285 | if (dv != NULL) { |
286 | rootdv = dv; |
287 | break; |
288 | } |
289 | } |
290 | |
291 | /* |
292 | * Set up the default dump device. If root is on |
293 | * a network device, there is no default dump |
294 | * device, since we don't support dumps to the |
295 | * network. |
296 | */ |
297 | if (DEV_USES_PARTITIONS(rootdv) == 0) |
298 | defdumpdv = NULL; |
299 | else |
300 | defdumpdv = rootdv; |
301 | |
302 | for (;;) { |
303 | printf("dump device" ); |
304 | if (defdumpdv != NULL) { |
305 | /* |
306 | * Note, we know it's a disk if we get here. |
307 | */ |
308 | printf(" (default %sb)" , device_xname(defdumpdv)); |
309 | } |
310 | printf(": " ); |
311 | len = cngetsn(buf, sizeof(buf)); |
312 | if (len == 0) { |
313 | if (defdumpdv != NULL) { |
314 | ndumpdev = MAKEDISKDEV(major(nrootdev), |
315 | DISKUNIT(nrootdev), 1); |
316 | } |
317 | dumpdv = defdumpdv; |
318 | break; |
319 | } |
320 | if (len == 4 && strcmp(buf, "none" ) == 0) { |
321 | dumpdv = NULL; |
322 | break; |
323 | } |
324 | dv = getdisk(buf, len, 1, &ndumpdev, 1); |
325 | if (dv != NULL) { |
326 | dumpdv = dv; |
327 | break; |
328 | } |
329 | } |
330 | |
331 | rootdev = nrootdev; |
332 | dumpdev = ndumpdev; |
333 | |
334 | for (vops = LIST_FIRST(&vfs_list); vops != NULL; |
335 | vops = LIST_NEXT(vops, vfs_list)) { |
336 | if (vops->vfs_mountroot != NULL && |
337 | strcmp(rootfstype, vops->vfs_name) == 0) |
338 | break; |
339 | } |
340 | |
341 | if (vops == NULL) { |
342 | deffsname = "generic" ; |
343 | } else |
344 | deffsname = vops->vfs_name; |
345 | |
346 | for (;;) { |
347 | printf("file system (default %s): " , deffsname); |
348 | len = cngetsn(buf, sizeof(buf)); |
349 | if (len == 0) { |
350 | if (strcmp(deffsname, "generic" ) == 0) |
351 | rootfstype = ROOT_FSTYPE_ANY; |
352 | break; |
353 | } |
354 | if (len == 4 && strcmp(buf, "halt" ) == 0) |
355 | cpu_reboot(RB_HALT, NULL); |
356 | else if (len == 6 && strcmp(buf, "reboot" ) == 0) |
357 | cpu_reboot(0, NULL); |
358 | #if defined(DDB) |
359 | else if (len == 3 && strcmp(buf, "ddb" ) == 0) { |
360 | console_debugger(); |
361 | } |
362 | #endif |
363 | else if (len == 7 && strcmp(buf, "generic" ) == 0) { |
364 | rootfstype = ROOT_FSTYPE_ANY; |
365 | break; |
366 | } |
367 | vops = vfs_getopsbyname(buf); |
368 | if (vops == NULL || vops->vfs_mountroot == NULL) { |
369 | printf("use one of: generic" ); |
370 | for (vops = LIST_FIRST(&vfs_list); |
371 | vops != NULL; |
372 | vops = LIST_NEXT(vops, vfs_list)) { |
373 | if (vops->vfs_mountroot != NULL) |
374 | printf(" %s" , vops->vfs_name); |
375 | } |
376 | if (vops != NULL) |
377 | vfs_delref(vops); |
378 | #if defined(DDB) |
379 | printf(" ddb" ); |
380 | #endif |
381 | printf(" halt reboot\n" ); |
382 | } else { |
383 | /* |
384 | * XXX If *vops gets freed between here and |
385 | * the call to mountroot(), rootfstype will |
386 | * point to something unexpected. But in |
387 | * this case the system will fail anyway. |
388 | */ |
389 | rootfstype = vops->vfs_name; |
390 | vfs_delref(vops); |
391 | break; |
392 | } |
393 | } |
394 | |
395 | } else if (rootspec == NULL) { |
396 | /* |
397 | * Wildcarded root; use the boot device. |
398 | */ |
399 | rootdv = bootdv; |
400 | |
401 | if (bootdv) |
402 | majdev = devsw_name2blk(device_xname(bootdv), NULL, 0); |
403 | else |
404 | majdev = -1; |
405 | if (majdev >= 0) { |
406 | /* |
407 | * Root is on a disk. `bootpartition' is root, |
408 | * unless the device does not use partitions. |
409 | */ |
410 | if (DEV_USES_PARTITIONS(bootdv)) |
411 | rootdev = MAKEDISKDEV(majdev, |
412 | device_unit(bootdv), |
413 | bootpartition); |
414 | else |
415 | rootdev = makedev(majdev, device_unit(bootdv)); |
416 | } |
417 | } else { |
418 | |
419 | /* |
420 | * `root on <dev> ...' |
421 | */ |
422 | |
423 | /* |
424 | * If it's a network interface, we can bail out |
425 | * early. |
426 | */ |
427 | dv = finddevice(rootspec); |
428 | if (dv != NULL && device_class(dv) == DV_IFNET) { |
429 | rootdv = dv; |
430 | goto haveroot; |
431 | } |
432 | |
433 | if (rootdev == NODEV && |
434 | dv != NULL && device_class(dv) == DV_DISK && |
435 | device_is_a(dv, "dk" ) && |
436 | (majdev = devsw_name2blk(device_xname(dv), NULL, 0)) >= 0) |
437 | rootdev = makedev(majdev, device_unit(dv)); |
438 | |
439 | rootdevname = devsw_blk2name(major(rootdev)); |
440 | if (rootdevname == NULL) { |
441 | printf("unknown device major 0x%llx\n" , |
442 | (unsigned long long)rootdev); |
443 | boothowto |= RB_ASKNAME; |
444 | goto top; |
445 | } |
446 | memset(buf, 0, sizeof(buf)); |
447 | snprintf(buf, sizeof(buf), "%s%llu" , rootdevname, |
448 | (unsigned long long)DISKUNIT(rootdev)); |
449 | |
450 | rootdv = finddevice(buf); |
451 | if (rootdv == NULL) { |
452 | printf("device %s (0x%llx) not configured\n" , |
453 | buf, (unsigned long long)rootdev); |
454 | boothowto |= RB_ASKNAME; |
455 | goto top; |
456 | } |
457 | } |
458 | |
459 | haveroot: |
460 | |
461 | root_device = rootdv; |
462 | |
463 | switch (device_class(rootdv)) { |
464 | case DV_IFNET: |
465 | case DV_DISK: |
466 | aprint_normal("root on %s" , device_xname(rootdv)); |
467 | if (DEV_USES_PARTITIONS(rootdv)) |
468 | aprint_normal("%c" , (int)DISKPART(rootdev) + 'a'); |
469 | break; |
470 | |
471 | default: |
472 | printf("can't determine root device\n" ); |
473 | boothowto |= RB_ASKNAME; |
474 | goto top; |
475 | } |
476 | |
477 | /* |
478 | * Now configure the dump device. |
479 | * |
480 | * If we haven't figured out the dump device, do so, with |
481 | * the following rules: |
482 | * |
483 | * (a) We already know dumpdv in the RB_ASKNAME case. |
484 | * |
485 | * (b) If dumpspec is set, try to use it. If the device |
486 | * is not available, punt. |
487 | * |
488 | * (c) If dumpspec is not set, the dump device is |
489 | * wildcarded or unspecified. If the root device |
490 | * is DV_IFNET, punt. Otherwise, use partition b |
491 | * of the root device. |
492 | */ |
493 | |
494 | if (boothowto & RB_ASKNAME) { /* (a) */ |
495 | if (dumpdv == NULL) |
496 | goto nodumpdev; |
497 | } else if (dumpspec != NULL) { /* (b) */ |
498 | if (strcmp(dumpspec, "none" ) == 0 || dumpdev == NODEV) { |
499 | /* |
500 | * Operator doesn't want a dump device. |
501 | * Or looks like they tried to pick a network |
502 | * device. Oops. |
503 | */ |
504 | goto nodumpdev; |
505 | } |
506 | |
507 | dumpdevname = devsw_blk2name(major(dumpdev)); |
508 | if (dumpdevname == NULL) |
509 | goto nodumpdev; |
510 | memset(buf, 0, sizeof(buf)); |
511 | snprintf(buf, sizeof(buf), "%s%llu" , dumpdevname, |
512 | (unsigned long long)DISKUNIT(dumpdev)); |
513 | |
514 | dumpdv = finddevice(buf); |
515 | if (dumpdv == NULL) { |
516 | /* |
517 | * Device not configured. |
518 | */ |
519 | goto nodumpdev; |
520 | } |
521 | } else { /* (c) */ |
522 | if (DEV_USES_PARTITIONS(rootdv) == 0) { |
523 | for (dv = deviter_first(&di, DEVITER_F_ROOT_FIRST); |
524 | dv != NULL; |
525 | dv = deviter_next(&di)) |
526 | if (isswap(dv)) |
527 | break; |
528 | deviter_release(&di); |
529 | if (dv == NULL) |
530 | goto nodumpdev; |
531 | |
532 | majdev = devsw_name2blk(device_xname(dv), NULL, 0); |
533 | if (majdev < 0) |
534 | goto nodumpdev; |
535 | dumpdv = dv; |
536 | dumpdev = makedev(majdev, device_unit(dumpdv)); |
537 | } else { |
538 | dumpdv = rootdv; |
539 | dumpdev = MAKEDISKDEV(major(rootdev), |
540 | device_unit(dumpdv), 1); |
541 | } |
542 | } |
543 | |
544 | dumpcdev = devsw_blk2chr(dumpdev); |
545 | aprint_normal(" dumps on %s" , device_xname(dumpdv)); |
546 | if (DEV_USES_PARTITIONS(dumpdv)) |
547 | aprint_normal("%c" , (int)DISKPART(dumpdev) + 'a'); |
548 | aprint_normal("\n" ); |
549 | return; |
550 | |
551 | nodumpdev: |
552 | dumpdev = NODEV; |
553 | dumpcdev = NODEV; |
554 | aprint_normal("\n" ); |
555 | } |
556 | |
557 | static device_t |
558 | finddevice(const char *name) |
559 | { |
560 | const char *wname; |
561 | |
562 | if ((wname = getwedgename(name, strlen(name))) != NULL) |
563 | return dkwedge_find_by_wname(wname); |
564 | |
565 | return device_find_by_xname(name); |
566 | } |
567 | |
568 | static device_t |
569 | getdisk(char *str, int len, int defpart, dev_t *devp, int isdump) |
570 | { |
571 | device_t dv; |
572 | deviter_t di; |
573 | |
574 | if ((dv = parsedisk(str, len, defpart, devp)) == NULL) { |
575 | printf("use one of:" ); |
576 | for (dv = deviter_first(&di, DEVITER_F_ROOT_FIRST); dv != NULL; |
577 | dv = deviter_next(&di)) { |
578 | if (DEV_USES_PARTITIONS(dv)) |
579 | printf(" %s[a-%c]" , device_xname(dv), |
580 | 'a' + MAXPARTITIONS - 1); |
581 | else if (device_class(dv) == DV_DISK) |
582 | printf(" %s" , device_xname(dv)); |
583 | if (isdump == 0 && device_class(dv) == DV_IFNET) |
584 | printf(" %s" , device_xname(dv)); |
585 | } |
586 | deviter_release(&di); |
587 | dkwedge_print_wnames(); |
588 | if (isdump) |
589 | printf(" none" ); |
590 | #if defined(DDB) |
591 | printf(" ddb" ); |
592 | #endif |
593 | printf(" halt reboot\n" ); |
594 | } |
595 | return dv; |
596 | } |
597 | |
598 | static const char * |
599 | getwedgename(const char *name, int namelen) |
600 | { |
601 | const char *wpfx = "wedge:" ; |
602 | const int wpfxlen = strlen(wpfx); |
603 | |
604 | if (namelen < wpfxlen || strncmp(name, wpfx, wpfxlen) != 0) |
605 | return NULL; |
606 | |
607 | return name + wpfxlen; |
608 | } |
609 | |
610 | static device_t |
611 | parsedisk(char *str, int len, int defpart, dev_t *devp) |
612 | { |
613 | device_t dv; |
614 | const char *wname; |
615 | char *cp, c; |
616 | int majdev, part; |
617 | if (len == 0) |
618 | return (NULL); |
619 | |
620 | if (len == 4 && strcmp(str, "halt" ) == 0) |
621 | cpu_reboot(RB_HALT, NULL); |
622 | else if (len == 6 && strcmp(str, "reboot" ) == 0) |
623 | cpu_reboot(0, NULL); |
624 | #if defined(DDB) |
625 | else if (len == 3 && strcmp(str, "ddb" ) == 0) |
626 | console_debugger(); |
627 | #endif |
628 | |
629 | cp = str + len - 1; |
630 | c = *cp; |
631 | |
632 | if ((wname = getwedgename(str, len)) != NULL) { |
633 | if ((dv = dkwedge_find_by_wname(wname)) == NULL) |
634 | return NULL; |
635 | part = defpart; |
636 | goto gotdisk; |
637 | } else if (c >= 'a' && c <= ('a' + MAXPARTITIONS - 1)) { |
638 | part = c - 'a'; |
639 | *cp = '\0'; |
640 | } else |
641 | part = defpart; |
642 | |
643 | dv = finddevice(str); |
644 | if (dv != NULL) { |
645 | if (device_class(dv) == DV_DISK) { |
646 | gotdisk: |
647 | majdev = devsw_name2blk(device_xname(dv), NULL, 0); |
648 | if (majdev < 0) |
649 | panic("parsedisk" ); |
650 | if (DEV_USES_PARTITIONS(dv)) |
651 | *devp = MAKEDISKDEV(majdev, device_unit(dv), |
652 | part); |
653 | else |
654 | *devp = makedev(majdev, device_unit(dv)); |
655 | } |
656 | |
657 | if (device_class(dv) == DV_IFNET) |
658 | *devp = NODEV; |
659 | } |
660 | |
661 | *cp = c; |
662 | return (dv); |
663 | } |
664 | |