RHEL5/init/do_mounts.c
<<
>>
Prefs
   1#include <linux/module.h>
   2#include <linux/sched.h>
   3#include <linux/ctype.h>
   4#include <linux/fd.h>
   5#include <linux/tty.h>
   6#include <linux/suspend.h>
   7#include <linux/root_dev.h>
   8#include <linux/security.h>
   9#include <linux/delay.h>
  10#include <linux/mount.h>
  11
  12#include <linux/nfs_fs.h>
  13#include <linux/nfs_fs_sb.h>
  14#include <linux/nfs_mount.h>
  15
  16#include "do_mounts.h"
  17
  18extern int get_filesystem_list(char * buf);
  19
  20int __initdata rd_doload;       /* 1 = load RAM disk, 0 = don't load */
  21
  22int root_mountflags = MS_RDONLY | MS_SILENT;
  23char * __initdata root_device_name;
  24static char __initdata saved_root_name[64];
  25
  26dev_t ROOT_DEV;
  27
  28static int __init load_ramdisk(char *str)
  29{
  30        rd_doload = simple_strtol(str,NULL,0) & 3;
  31        return 1;
  32}
  33__setup("load_ramdisk=", load_ramdisk);
  34
  35static int __init readonly(char *str)
  36{
  37        if (*str)
  38                return 0;
  39        root_mountflags |= MS_RDONLY;
  40        return 1;
  41}
  42
  43static int __init readwrite(char *str)
  44{
  45        if (*str)
  46                return 0;
  47        root_mountflags &= ~MS_RDONLY;
  48        return 1;
  49}
  50
  51__setup("ro", readonly);
  52__setup("rw", readwrite);
  53
  54static dev_t try_name(char *name, int part)
  55{
  56        char path[64];
  57        char buf[32];
  58        int range;
  59        dev_t res;
  60        char *s;
  61        int len;
  62        int fd;
  63        unsigned int maj, min;
  64
  65        /* read device number from .../dev */
  66
  67        sprintf(path, "/sys/block/%s/dev", name);
  68        fd = sys_open(path, 0, 0);
  69        if (fd < 0)
  70                goto fail;
  71        len = sys_read(fd, buf, 32);
  72        sys_close(fd);
  73        if (len <= 0 || len == 32 || buf[len - 1] != '\n')
  74                goto fail;
  75        buf[len - 1] = '\0';
  76        if (sscanf(buf, "%u:%u", &maj, &min) == 2) {
  77                /*
  78                 * Try the %u:%u format -- see print_dev_t()
  79                 */
  80                res = MKDEV(maj, min);
  81                if (maj != MAJOR(res) || min != MINOR(res))
  82                        goto fail;
  83        } else {
  84                /*
  85                 * Nope.  Try old-style "0321"
  86                 */
  87                res = new_decode_dev(simple_strtoul(buf, &s, 16));
  88                if (*s)
  89                        goto fail;
  90        }
  91
  92        /* if it's there and we are not looking for a partition - that's it */
  93        if (!part)
  94                return res;
  95
  96        /* otherwise read range from .../range */
  97        sprintf(path, "/sys/block/%s/range", name);
  98        fd = sys_open(path, 0, 0);
  99        if (fd < 0)
 100                goto fail;
 101        len = sys_read(fd, buf, 32);
 102        sys_close(fd);
 103        if (len <= 0 || len == 32 || buf[len - 1] != '\n')
 104                goto fail;
 105        buf[len - 1] = '\0';
 106        range = simple_strtoul(buf, &s, 10);
 107        if (*s)
 108                goto fail;
 109
 110        /* if partition is within range - we got it */
 111        if (part < range)
 112                return res + part;
 113fail:
 114        return 0;
 115}
 116
 117/*
 118 *      Convert a name into device number.  We accept the following variants:
 119 *
 120 *      1) device number in hexadecimal represents itself
 121 *      2) /dev/nfs represents Root_NFS (0xff)
 122 *      3) /dev/<disk_name> represents the device number of disk
 123 *      4) /dev/<disk_name><decimal> represents the device number
 124 *         of partition - device number of disk plus the partition number
 125 *      5) /dev/<disk_name>p<decimal> - same as the above, that form is
 126 *         used when disk name of partitioned disk ends on a digit.
 127 *
 128 *      If name doesn't have fall into the categories above, we return 0.
 129 *      Sysfs is used to check if something is a disk name - it has
 130 *      all known disks under bus/block/devices.  If the disk name
 131 *      contains slashes, name of sysfs node has them replaced with
 132 *      bangs.  try_name() does the actual checks, assuming that sysfs
 133 *      is mounted on rootfs /sys.
 134 */
 135
 136dev_t name_to_dev_t(char *name)
 137{
 138        char s[32];
 139        char *p;
 140        dev_t res = 0;
 141        int part;
 142
 143#ifdef CONFIG_SYSFS
 144        int mkdir_err = sys_mkdir("/sys", 0700);
 145        if (sys_mount("sysfs", "/sys", "sysfs", 0, NULL) < 0)
 146                goto out;
 147#endif
 148
 149        if (strncmp(name, "/dev/", 5) != 0) {
 150                unsigned maj, min;
 151
 152                if (sscanf(name, "%u:%u", &maj, &min) == 2) {
 153                        res = MKDEV(maj, min);
 154                        if (maj != MAJOR(res) || min != MINOR(res))
 155                                goto fail;
 156                } else {
 157                        res = new_decode_dev(simple_strtoul(name, &p, 16));
 158                        if (*p)
 159                                goto fail;
 160                }
 161                goto done;
 162        }
 163        name += 5;
 164        res = Root_NFS;
 165        if (strcmp(name, "nfs") == 0)
 166                goto done;
 167        res = Root_RAM0;
 168        if (strcmp(name, "ram") == 0)
 169                goto done;
 170
 171        if (strlen(name) > 31)
 172                goto fail;
 173        strcpy(s, name);
 174        for (p = s; *p; p++)
 175                if (*p == '/')
 176                        *p = '!';
 177        res = try_name(s, 0);
 178        if (res)
 179                goto done;
 180
 181        while (p > s && isdigit(p[-1]))
 182                p--;
 183        if (p == s || !*p || *p == '0')
 184                goto fail;
 185        part = simple_strtoul(p, NULL, 10);
 186        *p = '\0';
 187        res = try_name(s, part);
 188        if (res)
 189                goto done;
 190
 191        if (p < s + 2 || !isdigit(p[-2]) || p[-1] != 'p')
 192                goto fail;
 193        p[-1] = '\0';
 194        res = try_name(s, part);
 195done:
 196#ifdef CONFIG_SYSFS
 197        sys_umount("/sys", 0);
 198out:
 199        if (!mkdir_err)
 200                sys_rmdir("/sys");
 201#endif
 202        return res;
 203fail:
 204        res = 0;
 205        goto done;
 206}
 207
 208static int __init root_dev_setup(char *line)
 209{
 210        strlcpy(saved_root_name, line, sizeof(saved_root_name));
 211        return 1;
 212}
 213
 214__setup("root=", root_dev_setup);
 215
 216static char * __initdata root_mount_data;
 217static int __init root_data_setup(char *str)
 218{
 219        root_mount_data = str;
 220        return 1;
 221}
 222
 223static char * __initdata root_fs_names;
 224static int __init fs_names_setup(char *str)
 225{
 226        root_fs_names = str;
 227        return 1;
 228}
 229
 230static unsigned int __initdata root_delay;
 231static int __init root_delay_setup(char *str)
 232{
 233        root_delay = simple_strtoul(str, NULL, 0);
 234        return 1;
 235}
 236
 237__setup("rootflags=", root_data_setup);
 238__setup("rootfstype=", fs_names_setup);
 239__setup("rootdelay=", root_delay_setup);
 240
 241static void __init get_fs_names(char *page)
 242{
 243        char *s = page;
 244
 245        if (root_fs_names) {
 246                strcpy(page, root_fs_names);
 247                while (*s++) {
 248                        if (s[-1] == ',')
 249                                s[-1] = '\0';
 250                }
 251        } else {
 252                int len = get_filesystem_list(page);
 253                char *p, *next;
 254
 255                page[len] = '\0';
 256                for (p = page-1; p; p = next) {
 257                        next = strchr(++p, '\n');
 258                        if (*p++ != '\t')
 259                                continue;
 260                        while ((*s++ = *p++) != '\n')
 261                                ;
 262                        s[-1] = '\0';
 263                }
 264        }
 265        *s = '\0';
 266}
 267
 268static int __init do_mount_root(char *name, char *fs, int flags, void *data)
 269{
 270        int err = sys_mount(name, "/root", fs, flags, data);
 271        if (err)
 272                return err;
 273
 274        sys_chdir("/root");
 275        ROOT_DEV = current->fs->pwdmnt->mnt_sb->s_dev;
 276        printk("VFS: Mounted root (%s filesystem)%s.\n",
 277               current->fs->pwdmnt->mnt_sb->s_type->name,
 278               current->fs->pwdmnt->mnt_sb->s_flags & MS_RDONLY ? 
 279               " readonly" : "");
 280        return 0;
 281}
 282
 283void __init mount_block_root(char *name, int flags)
 284{
 285        char *fs_names = __getname();
 286        char *p;
 287        char b[BDEVNAME_SIZE];
 288
 289        get_fs_names(fs_names);
 290retry:
 291        for (p = fs_names; *p; p += strlen(p)+1) {
 292                int err = do_mount_root(name, p, flags, root_mount_data);
 293                switch (err) {
 294                        case 0:
 295                                goto out;
 296                        case -EACCES:
 297                                flags |= MS_RDONLY;
 298                                goto retry;
 299                        case -EINVAL:
 300                                continue;
 301                }
 302                /*
 303                 * Allow the user to distinguish between failed sys_open
 304                 * and bad superblock on root device.
 305                 */
 306                __bdevname(ROOT_DEV, b);
 307                printk("VFS: Cannot open root device \"%s\" or %s\n",
 308                                root_device_name, b);
 309                printk("Please append a correct \"root=\" boot option\n");
 310
 311                panic("VFS: Unable to mount root fs on %s", b);
 312        }
 313
 314        printk("No filesystem could mount root, tried: ");
 315        for (p = fs_names; *p; p += strlen(p)+1)
 316                printk(" %s", p);
 317        printk("\n");
 318        panic("VFS: Unable to mount root fs on %s", __bdevname(ROOT_DEV, b));
 319out:
 320        putname(fs_names);
 321}
 322 
 323#ifdef CONFIG_ROOT_NFS
 324static int __init mount_nfs_root(void)
 325{
 326        void *data = nfs_root_data();
 327
 328        create_dev("/dev/root", ROOT_DEV);
 329        if (data &&
 330            do_mount_root("/dev/root", "nfs", root_mountflags, data) == 0)
 331                return 1;
 332        return 0;
 333}
 334#endif
 335
 336#if defined(CONFIG_BLK_DEV_RAM) || defined(CONFIG_BLK_DEV_FD)
 337void __init change_floppy(char *fmt, ...)
 338{
 339        struct termios termios;
 340        char buf[80];
 341        char c;
 342        int fd;
 343        va_list args;
 344        va_start(args, fmt);
 345        vsprintf(buf, fmt, args);
 346        va_end(args);
 347        fd = sys_open("/dev/root", O_RDWR | O_NDELAY, 0);
 348        if (fd >= 0) {
 349                sys_ioctl(fd, FDEJECT, 0);
 350                sys_close(fd);
 351        }
 352        printk(KERN_NOTICE "VFS: Insert %s and press ENTER\n", buf);
 353        fd = sys_open("/dev/console", O_RDWR, 0);
 354        if (fd >= 0) {
 355                sys_ioctl(fd, TCGETS, (long)&termios);
 356                termios.c_lflag &= ~ICANON;
 357                sys_ioctl(fd, TCSETSF, (long)&termios);
 358                sys_read(fd, &c, 1);
 359                termios.c_lflag |= ICANON;
 360                sys_ioctl(fd, TCSETSF, (long)&termios);
 361                sys_close(fd);
 362        }
 363}
 364#endif
 365
 366void __init mount_root(void)
 367{
 368#ifdef CONFIG_ROOT_NFS
 369        if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) {
 370                if (mount_nfs_root())
 371                        return;
 372
 373                printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n");
 374                ROOT_DEV = Root_FD0;
 375        }
 376#endif
 377#ifdef CONFIG_BLK_DEV_FD
 378        if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {
 379                /* rd_doload is 2 for a dual initrd/ramload setup */
 380                if (rd_doload==2) {
 381                        if (rd_load_disk(1)) {
 382                                ROOT_DEV = Root_RAM1;
 383                                root_device_name = NULL;
 384                        }
 385                } else
 386                        change_floppy("root floppy");
 387        }
 388#endif
 389        create_dev("/dev/root", ROOT_DEV);
 390        mount_block_root("/dev/root", root_mountflags);
 391}
 392
 393/*
 394 * Prepare the namespace - decide what/where to mount, load ramdisks, etc.
 395 */
 396void __init prepare_namespace(void)
 397{
 398        int is_floppy;
 399
 400        if (root_delay) {
 401                printk(KERN_INFO "Waiting %dsec before mounting root device...\n",
 402                       root_delay);
 403                ssleep(root_delay);
 404        }
 405
 406        md_run_setup();
 407
 408        if (saved_root_name[0]) {
 409                root_device_name = saved_root_name;
 410                if (!strncmp(root_device_name, "mtd", 3)) {
 411                        mount_block_root(root_device_name, root_mountflags);
 412                        goto out;
 413                }
 414                ROOT_DEV = name_to_dev_t(root_device_name);
 415                if (strncmp(root_device_name, "/dev/", 5) == 0)
 416                        root_device_name += 5;
 417        }
 418
 419        is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;
 420
 421        if (initrd_load())
 422                goto out;
 423
 424        if (is_floppy && rd_doload && rd_load_disk(0))
 425                ROOT_DEV = Root_RAM0;
 426
 427        mount_root();
 428out:
 429        sys_mount(".", "/", NULL, MS_MOVE, NULL);
 430        sys_chroot(".");
 431        security_sb_post_mountroot();
 432}
 433
 434