nrelease: Use pw(8) and chpass(1) to setup 'installer' and 'root' users
[dragonfly.git] / sys / kern / vfs_conf.c
1 /*-
2  * Copyright (c) 1999 Michael Smith
3  * All rights reserved.
4  * Copyright (c) 1999 Poul-Henning Kamp
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  *      $FreeBSD: src/sys/kern/vfs_conf.c,v 1.49.2.5 2003/01/07 11:56:53 joerg Exp $
29  */
30
31 /*
32  * Locate and mount the root filesystem.
33  *
34  * The root filesystem is detailed in the kernel environment variable
35  * vfs.root.mountfrom, which is expected to be in the general format
36  *
37  * <vfsname>:[<path>]
38  * vfsname   := the name of a VFS known to the kernel and capable
39  *              of being mounted as root
40  * path      := disk device name or other data used by the filesystem
41  *              to locate its physical store
42  *
43  */
44
45 #include "opt_rootdevname.h"
46
47 #include <sys/param.h>
48 #include <sys/kernel.h>
49 #include <sys/systm.h>
50 #include <sys/proc.h>
51 #include <sys/vnode.h>
52 #include <sys/mount.h>
53 #include <sys/malloc.h>
54 #include <sys/reboot.h>
55 #include <sys/diskslice.h>
56 #include <sys/conf.h>
57 #include <sys/cons.h>
58 #include <sys/kbio.h>
59 #include <sys/device.h>
60 #include <sys/disk.h>
61 #include <sys/namecache.h>
62 #include <sys/paths.h>
63 #include <sys/thread2.h>
64 #include <sys/nlookup.h>
65 #include <sys/devfs.h>
66 #include <sys/sysctl.h>
67
68 #include "opt_ddb.h"
69 #ifdef DDB
70 #include <ddb/ddb.h>
71 #endif
72
73 MALLOC_DEFINE(M_MOUNT, "mount", "vfs mount structure");
74
75 #define ROOTNAME        "root_device"
76
77 struct vnode    *rootvnode;
78 struct nchandle rootnch;
79
80 /* 
81  * The root specifiers we will try if RB_CDROM is specified.  Note that
82  * with DEVFS we do not use the compatibility slice's whole-disk 'c'
83  * partition.  Instead we just use the whole disk, e.g. cd0 or cd0s0.
84  */
85 static char *cdrom_rootdevnames[] = {
86         "cd9660:cd0",   /* SCSI (including AHCI and SILI) */
87         "cd9660:acd0",  /* NATA */
88         "cd9660:cd1",   /* SCSI (including AHCI and SILI) */
89         "cd9660:acd1",  /* NATA */
90         "cd9660:cd8",   /* USB */
91         "cd9660:cd9",   /* USB */
92         NULL
93 };
94
95 int vfs_mountroot_devfs(void);
96 static void     vfs_mountroot(void *junk);
97 static int      vfs_mountroot_try(const char *mountfrom);
98 static int      vfs_mountroot_ask(void);
99 static int      get_line(char *cp, int limit);
100
101 /* legacy find-root code */
102 char            *rootdevnames[2] = {NULL, NULL};
103 static int      setrootbyname(char *name);
104
105 SYSINIT(mountroot, SI_SUB_MOUNT_ROOT, SI_ORDER_SECOND, vfs_mountroot, NULL);
106
107 static int wakedelay = 2;       /* delay before mounting root in seconds */
108 TUNABLE_INT("vfs.root.wakedelay", &wakedelay);
109
110 /*
111  * Find and mount the root filesystem
112  */
113 static void
114 vfs_mountroot(void *junk)
115 {
116         cdev_t  save_rootdev = rootdev;
117         int     i;
118         int     dummy;
119         
120         /*
121          * Make sure all disk devices created so far have also been probed,
122          * and also make sure that the newly created device nodes for
123          * probed disks are ready, too.
124          *
125          * Messages can fly around here so get good synchronization
126          * coverage.
127          *
128          * XXX - Delay some more (default: 2s) to help drivers which pickup
129          *       devices asynchronously and are not caught by CAM's initial
130          *       probe.
131          */
132         sync_devs();
133         tsleep(&dummy, 0, "syncer", hz * wakedelay);
134
135
136         /* 
137          * The root filesystem information is compiled in, and we are
138          * booted with instructions to use it.
139          */
140 #ifdef ROOTDEVNAME
141         if ((boothowto & RB_DFLTROOT) && 
142             !vfs_mountroot_try(ROOTDEVNAME))
143                 return;
144 #endif
145         /* 
146          * We are booted with instructions to prompt for the root filesystem,
147          * or to use the compiled-in default when it doesn't exist.
148          */
149         if (boothowto & (RB_DFLTROOT | RB_ASKNAME)) {
150                 if (!vfs_mountroot_ask())
151                         return;
152         }
153
154         /*
155          * We've been given the generic "use CDROM as root" flag.  This is
156          * necessary because one media may be used in many different
157          * devices, so we need to search for them.
158          */
159         if (boothowto & RB_CDROM) {
160                 for (i = 0; cdrom_rootdevnames[i] != NULL; i++) {
161                         if (!vfs_mountroot_try(cdrom_rootdevnames[i]))
162                                 return;
163                 }
164         }
165
166         /*
167          * Try to use the value read by the loader from /etc/fstab, or
168          * supplied via some other means.  This is the preferred 
169          * mechanism.
170          */
171         if (!vfs_mountroot_try(kgetenv("vfs.root.mountfrom")))
172                 return;
173
174         /*
175          * If a vfs set rootdev, try it (XXX VINUM HACK!)
176          */
177         if (save_rootdev != NULL) {
178                 rootdev = save_rootdev;
179                 if (!vfs_mountroot_try(""))
180                         return;
181         }
182
183         /* 
184          * Try values that may have been computed by the machine-dependant
185          * legacy code.
186          */
187         if (rootdevnames[0] && !vfs_mountroot_try(rootdevnames[0]))
188                 return;
189         if (rootdevnames[1] && !vfs_mountroot_try(rootdevnames[1]))
190                 return;
191
192         /*
193          * If we have a compiled-in default, and haven't already tried it, try
194          * it now.
195          */
196 #ifdef ROOTDEVNAME
197         if (!(boothowto & RB_DFLTROOT))
198                 if (!vfs_mountroot_try(ROOTDEVNAME))
199                         return;
200 #endif
201
202         /* 
203          * Everything so far has failed, prompt on the console if we haven't
204          * already tried that.
205          */
206         if (!(boothowto & (RB_DFLTROOT | RB_ASKNAME)) && !vfs_mountroot_ask())
207                 return;
208         panic("Root mount failed, startup aborted.");
209 }
210
211
212 int
213 vfs_mountroot_devfs(void)
214 {
215         struct vnode *vp;
216         struct nchandle nch;
217         struct nlookupdata nd;
218         struct mount *mp;
219         struct vfsconf *vfsp;
220         int error;
221         struct ucred *cred = proc0.p_ucred;
222         const char *devfs_path, *init_chroot;
223         char *dev_malloced = NULL;
224
225         if ((init_chroot = kgetenv("init_chroot")) != NULL) {
226                 size_t l;
227
228                 l = strlen(init_chroot) + sizeof("/dev");
229                 dev_malloced = kmalloc(l, M_MOUNT, M_WAITOK);
230                 ksnprintf(dev_malloced, l, "%s/dev", init_chroot);
231                 devfs_path = dev_malloced;
232         } else {
233                 devfs_path = "/dev";
234         }
235         /*
236          * Lookup the requested path and extract the nch and vnode.
237          */
238         error = nlookup_init_raw(&nd, devfs_path, UIO_SYSSPACE,
239                                  NLC_FOLLOW, cred, &rootnch);
240
241         if (error == 0) {
242                 devfs_debug(DEVFS_DEBUG_DEBUG,
243                             "vfs_mountroot_devfs: nlookup_init is ok...\n");
244                 if ((error = nlookup(&nd)) == 0) {
245                         devfs_debug(DEVFS_DEBUG_DEBUG,
246                                     "vfs_mountroot_devfs: nlookup is ok...\n");
247                         if (nd.nl_nch.ncp->nc_vp == NULL) {
248                                 devfs_debug(DEVFS_DEBUG_SHOW,
249                                             "vfs_mountroot_devfs: nlookup: "
250                                             "simply not found\n");
251                                 error = ENOENT;
252                         }
253                 }
254         }
255         if (dev_malloced != NULL)
256                 kfree(dev_malloced, M_MOUNT), dev_malloced = NULL;
257         devfs_path = NULL;
258         if (error) {
259                 nlookup_done(&nd);
260                 devfs_debug(DEVFS_DEBUG_SHOW,
261                             "vfs_mountroot_devfs: nlookup failed, error: %d\n",
262                             error);
263                 return (error);
264         }
265
266         /*
267          * Extract the locked+refd ncp and cleanup the nd structure
268          */
269         nch = nd.nl_nch;
270         cache_zero(&nd.nl_nch);
271         nlookup_done(&nd);
272
273         /*
274          * now we have the locked ref'd nch and unreferenced vnode.
275          */
276         vp = nch.ncp->nc_vp;
277         if ((error = vget(vp, LK_EXCLUSIVE)) != 0) {
278                 cache_put(&nch);
279                 devfs_debug(DEVFS_DEBUG_SHOW,
280                             "vfs_mountroot_devfs: vget failed\n");
281                 return (error);
282         }
283         cache_unlock(&nch);
284
285         if ((error = vinvalbuf(vp, V_SAVE, 0, 0)) != 0) {
286                 cache_drop(&nch);
287                 vput(vp);
288                 devfs_debug(DEVFS_DEBUG_SHOW,
289                             "vfs_mountroot_devfs: vinvalbuf failed\n");
290                 return (error);
291         }
292         if (vp->v_type != VDIR) {
293                 cache_drop(&nch);
294                 vput(vp);
295                 devfs_debug(DEVFS_DEBUG_SHOW,
296                             "vfs_mountroot_devfs: vp is not VDIR\n");
297                 return (ENOTDIR);
298         }
299
300         vfsp = vfsconf_find_by_name("devfs");
301
302         /*
303          * Allocate and initialize the filesystem.
304          */
305         mp = kmalloc(sizeof(struct mount), M_MOUNT, M_ZERO|M_WAITOK);
306         mount_init(mp, vfsp->vfc_vfsops);
307         vfs_busy(mp, LK_NOWAIT);
308         mp->mnt_vfc = vfsp;
309         mp->mnt_pbuf_count = nswbuf_kva / NSWBUF_SPLIT;
310         vfsp->vfc_refcount++;
311         mp->mnt_stat.f_type = vfsp->vfc_typenum;
312         mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK;
313         if (vfsp->vfc_flags & VFCF_MPSAFE)
314                 mp->mnt_kern_flag |= MNTK_ALL_MPSAFE;
315         strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN);
316         mp->mnt_stat.f_owner = cred->cr_uid;
317         mp->mnt_ncmounton = nch;
318         vn_unlock(vp);
319
320         /*
321          * Mount the filesystem.
322          */
323         error = VFS_MOUNT(mp, "/dev", NULL, cred);
324         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
325
326         /*
327          * Put the new filesystem on the mount list after root.  The mount
328          * point gets its own mnt_ncmountpt (unless the VFS already set one
329          * up) which represents the root of the mount.  The lookup code
330          * detects the mount point going forward and checks the root of
331          * the mount going backwards.
332          *
333          * It is not necessary to invalidate or purge the vnode underneath
334          * because elements under the mount will be given their own glue
335          * namecache record.
336          */
337         if (!error) {
338                 if (mp->mnt_ncmountpt.ncp == NULL) {
339                         /*
340                          * allocate, then unlock, but leave the ref intact
341                          */
342                         cache_allocroot(&mp->mnt_ncmountpt, mp, NULL);
343                         cache_unlock(&mp->mnt_ncmountpt);
344                 }
345                 vn_unlock(vp);
346                 cache_lock(&nch);
347                 nch.ncp->nc_flag |= NCF_ISMOUNTPT;
348                 cache_unlock(&nch);
349                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
350
351                 /*
352                  * XXX get the root of the fs and
353                  * cache_setvp(mnt_ncmountpt...)
354                  */
355                 mountlist_insert(mp, MNTINS_LAST);
356                 vn_unlock(vp);
357                 //checkdirs(&mp->mnt_ncmounton, &mp->mnt_ncmountpt);
358                 error = vfs_allocate_syncvnode(mp);
359                 if (error) {
360                         devfs_debug(DEVFS_DEBUG_SHOW,
361                                     "vfs_mountroot_devfs: "
362                                     "vfs_allocate_syncvnode failed\n");
363                 }
364                 vfs_unbusy(mp);
365                 error = VFS_START(mp, 0);
366                 vrele(vp);
367         } else {
368                 bzero(&mp->mnt_ncmounton, sizeof(mp->mnt_ncmounton));
369                 vn_syncer_thr_stop(mp);
370                 vfs_rm_vnodeops(mp, NULL, &mp->mnt_vn_coherency_ops);
371                 vfs_rm_vnodeops(mp, NULL, &mp->mnt_vn_journal_ops);
372                 vfs_rm_vnodeops(mp, NULL, &mp->mnt_vn_norm_ops);
373                 vfs_rm_vnodeops(mp, NULL, &mp->mnt_vn_spec_ops);
374                 vfs_rm_vnodeops(mp, NULL, &mp->mnt_vn_fifo_ops);
375                 mp->mnt_vfc->vfc_refcount--;
376                 vfs_unbusy(mp);
377                 kfree(mp, M_MOUNT);
378                 cache_drop(&nch);
379                 vput(vp);
380                 devfs_debug(DEVFS_DEBUG_SHOW,
381                             "vfs_mountroot_devfs: mount failed\n");
382         }
383
384         devfs_debug(DEVFS_DEBUG_DEBUG,
385                     "rootmount_devfs done with error: %d\n", error);
386         return (error);
387 }
388
389
390 /*
391  * Mount (mountfrom) as the root filesystem.
392  */
393 static int
394 vfs_mountroot_try(const char *mountfrom)
395 {
396         struct mount    *mp;
397         char            *vfsname, *devname;
398         int             error;
399         char            patt[32];
400         const char      *cp, *ep;
401         char            *mf;
402         struct proc     *p;
403         struct vnode    *vp;
404
405         vfsname = NULL;
406         devname = NULL;
407         mp      = NULL;
408         error   = EINVAL;
409
410         if (mountfrom == NULL)
411                 return(error);          /* don't complain */
412
413         crit_enter();
414         kprintf("Mounting root from %s\n", mountfrom);
415         crit_exit();
416
417         cp = mountfrom;
418         /* parse vfs name and devname */
419         vfsname = kmalloc(MFSNAMELEN, M_MOUNT, M_WAITOK);
420         devname = kmalloc(MNAMELEN, M_MOUNT, M_WAITOK);
421         mf = kmalloc(MFSNAMELEN+MNAMELEN, M_MOUNT, M_WAITOK);
422         for(;;) {
423                 for (ep = cp; (*ep != 0) && (*ep != ';'); ep++);
424                 bzero(vfsname, MFSNAMELEN);
425                 bzero(devname, MNAMELEN);
426                 bzero(mf, MFSNAMELEN+MNAMELEN);
427                 strncpy(mf, cp, MFSNAMELEN+MNAMELEN);
428
429                 vfsname[0] = devname[0] = 0;
430                 ksprintf(patt, "%%%d[a-z0-9]:%%%ds", MFSNAMELEN, MNAMELEN);
431                 if (ksscanf(mf, patt, vfsname, devname) < 1)
432                         goto end;
433
434                 /* allocate a root mount */
435                 error = vfs_rootmountalloc(vfsname,
436                                 devname[0] != 0 ? devname : ROOTNAME, &mp);
437                 if (error != 0) {
438                         kprintf("Can't allocate root mount for filesystem '%s': %d\n",
439                                vfsname, error);
440                         goto end;
441                 }
442                 mp->mnt_flag |= MNT_ROOTFS;
443
444                 /* do our best to set rootdev (really just for UFS) */
445                 if (strcmp(vfsname, "hammer") != 0 &&
446                     strcmp(vfsname, "hammer2") != 0 &&
447                     (devname[0] != 0) && setrootbyname(devname)) {
448                         kprintf("setrootbyname failed\n");
449                 }
450
451                 /* If the root device is a type "memory disk", mount RW */
452                 if (rootdev != NULL && dev_is_good(rootdev) &&
453                     (dev_dflags(rootdev) & D_MEMDISK)) {
454                         mp->mnt_flag &= ~MNT_RDONLY;
455                 }
456
457                 error = VFS_MOUNT(mp, NULL, NULL, proc0.p_ucred);
458
459                 if (!error)
460                         break;
461 end:
462                 if(*ep == 0)
463                         break;
464                 cp = ep + 1;
465         }
466
467         if (vfsname != NULL)
468                 kfree(vfsname, M_MOUNT);
469         if (devname != NULL)
470                 kfree(devname, M_MOUNT);
471         if (mf != NULL)
472                 kfree(mf, M_MOUNT);
473         if (error == 0) {
474                 /* register with list of mounted filesystems */
475                 mountlist_insert(mp, MNTINS_FIRST);
476
477                 /* sanity check system clock against root fs timestamp */
478                 inittodr(mp->mnt_time);
479
480                 /* Get the vnode for '/'.  Set p->p_fd->fd_cdir to reference it. */
481                 mp = mountlist_boot_getfirst();
482                 if (VFS_ROOT(mp, &vp))
483                         panic("cannot find root vnode");
484                 if (mp->mnt_ncmountpt.ncp == NULL) {
485                         cache_allocroot(&mp->mnt_ncmountpt, mp, vp);
486                         cache_unlock(&mp->mnt_ncmountpt);       /* leave ref intact */
487                 }
488                 p = curproc;
489                 p->p_fd->fd_cdir = vp;
490                 vref(p->p_fd->fd_cdir);
491                 p->p_fd->fd_rdir = vp;
492                 vref(p->p_fd->fd_rdir);
493                 vfs_cache_setroot(vp, cache_hold(&mp->mnt_ncmountpt));
494                 vn_unlock(vp);                  /* leave ref intact */
495                 cache_copy(&mp->mnt_ncmountpt, &p->p_fd->fd_ncdir);
496                 cache_copy(&mp->mnt_ncmountpt, &p->p_fd->fd_nrdir);
497
498                 vfs_unbusy(mp);
499                 if (mp->mnt_syncer == NULL) {
500                         error = vfs_allocate_syncvnode(mp);
501                         if (error)
502                                 kprintf("Warning: no syncer vp for root!\n");
503                         error = 0;
504                 }
505                 VFS_START( mp, 0 );
506         } else {
507                 if (mp != NULL) {
508                         vn_syncer_thr_stop(mp);
509                         vfs_unbusy(mp);
510                         kfree(mp, M_MOUNT);
511                 }
512                 kprintf("Root mount failed: %d\n", error);
513         }
514         return(error);
515 }
516
517
518 static void
519 vfs_mountroot_ask_callback(char *name, cdev_t dev, bool is_alias,
520     void *arg __unused)
521 {
522         if (!is_alias && dev_is_good(dev) && (dev_dflags(dev) & D_DISK))
523                 kprintf(" \"%s\" ", name);
524 }
525
526
527 /*
528  * Spin prompting on the console for a suitable root filesystem
529  */
530 static int
531 vfs_mountroot_ask(void)
532 {
533         char name[128];
534         int llimit = 100;
535
536         kprintf("\nManual root filesystem specification:\n");
537         kprintf("  <fstype>:<device>  Specify root (e.g. ufs:da0s1a)\n");
538         kprintf("  ?                  List valid disk boot devices\n");
539         kprintf("  panic              Just panic\n");
540         kprintf("  abort              Abort manual input\n");
541         while (llimit--) {
542                 kprintf("\nmountroot> ");
543
544                 if (get_line(name, 128) < 0)
545                         break;
546                 if (name[0] == 0) {
547                         ;
548                 } else if (name[0] == '?') {
549                         kprintf("Possibly valid devices for root FS:\n");
550                         //enumerate all disk devices
551                         devfs_scan_callback(vfs_mountroot_ask_callback, NULL);
552                         kprintf("\n");
553                         continue;
554                 } else if (strcmp(name, "panic") == 0) {
555                         panic("panic from console");
556                 } else if (strcmp(name, "abort") == 0) {
557                         break;
558                 } else if (vfs_mountroot_try(name) == 0) {
559                         return(0);
560                 }
561         }
562         return(1);
563 }
564
565
566 static int
567 get_line(char *cp, int limit)
568 {
569         char *lp;
570         int dummy;
571         int c;
572
573         lp = cp;
574         cnpoll(TRUE);
575         for (;;) {
576                 c = cncheckc();
577
578                 switch (c) {
579                 case NOKEY:
580                         tsleep(&dummy, 0, "cnpoll", hz / 25);
581                         break;
582                 case -1:
583                         goto done;
584                 case '\n':
585                 case '\r':
586                         kprintf("\n");
587                         *lp++ = '\0';
588                         c = 0;
589                         goto done;
590                 case '\b':
591                 case '\177':
592                         if (lp > cp) {
593                                 kprintf("\b \b");
594                                 lp--;
595                         } else {
596                                 kprintf("%c", 7);
597                         }
598                         continue;
599                 case '#':
600                         kprintf("#");
601                         lp--;
602                         if (lp < cp)
603                                 lp = cp;
604                         continue;
605                 case 'u' & 037:
606                         /* NOTE: '@' no longer processed here, used for H2 */
607                         lp = cp;
608                         kprintf("%c", '\n');
609                         continue;
610                 default:
611                         if (lp - cp >= limit - 1) {
612                                 kprintf("%c", 7);
613                         } else {
614                                 kprintf("%c", c);
615                                 *lp++ = c;
616                         }
617                         continue;
618                 }
619         }
620 done:
621         cnpoll(FALSE);
622         return c;
623 }
624
625 /*
626  * Convert a given name to the cdev_t of the disk-like device
627  * it refers to.
628  */
629 cdev_t
630 kgetdiskbyname(const char *name) 
631 {
632         cdev_t rdev;
633
634         /*
635          * Get the base name of the device
636          */
637         if (strncmp(name, __SYS_PATH_DEV, sizeof(__SYS_PATH_DEV) - 1) == 0)
638                 name += sizeof(__SYS_PATH_DEV) - 1;
639
640         /*
641          * Locate the device
642          */
643         rdev = devfs_find_device_by_name("%s", name);
644         if (rdev == NULL) {
645                 kprintf("no disk named '%s'\n", name);
646         }
647         /*
648          * FOUND DEVICE
649          */
650         return(rdev);
651 }
652
653 /*
654  * Set rootdev to match (name), given that we expect it to
655  * refer to a disk-like device.
656  */
657 static int
658 setrootbyname(char *name)
659 {
660         cdev_t diskdev;
661
662         diskdev = kgetdiskbyname(name);
663         if (diskdev != NULL) {
664                 rootdev = diskdev;
665                 return (0);
666         }
667         /* set to NULL if kgetdiskbyname() fails so that if the first rootdev is
668          * found by fails to mount and the second one isn't found, mountroot_try
669          * doesn't try again with the first one
670          */
671         rootdev = NULL;
672         return (1);
673 }
674
675 #ifdef DDB
676 DB_SHOW_COMMAND(disk, db_getdiskbyname)
677 {
678         cdev_t dev;
679
680         if (modif[0] == '\0') {
681                 db_error("usage: show disk/devicename");
682                 return;
683         }
684         dev = kgetdiskbyname(modif);
685         if (dev != NULL)
686                 db_printf("cdev_t = %p\n", dev);
687         else
688                 db_printf("No disk device matched.\n");
689 }
690 #endif
691
692 static int
693 vfs_sysctl_real_root(SYSCTL_HANDLER_ARGS)
694 {
695         char *real_root;
696         size_t len;
697         int error;
698
699         real_root = kgetenv("vfs.root.realroot");
700
701         if (real_root == NULL)
702                 real_root = "";
703
704         len = strlen(real_root) + 1;
705
706         error = sysctl_handle_string(oidp, real_root, len, req);
707
708         return error;
709 }
710
711 SYSCTL_PROC(_vfs, OID_AUTO, real_root,
712             CTLTYPE_STRING | CTLFLAG_RD, 0, 0, vfs_sysctl_real_root,
713             "A", "Real root mount string");