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