RHEL4/init/do_mounts_devfs.c
<<
>>
Prefs
   1
   2#include <linux/kernel.h>
   3#include <linux/dirent.h>
   4#include <linux/string.h>
   5#include <linux/syscalls.h>
   6
   7#include "do_mounts.h"
   8
   9void __init mount_devfs(void)
  10{
  11        sys_mount("devfs", "/dev", "devfs", 0, NULL);
  12}
  13
  14void __init umount_devfs(char *path)
  15{
  16        sys_umount(path, 0);
  17}
  18
  19/*
  20 * If the dir will fit in *buf, return its length.  If it won't fit, return
  21 * zero.  Return -ve on error.
  22 */
  23static int __init do_read_dir(int fd, void *buf, int len)
  24{
  25        long bytes, n;
  26        char *p = buf;
  27        sys_lseek(fd, 0, 0);
  28
  29        for (bytes = 0; bytes < len; bytes += n) {
  30                n = sys_getdents64(fd, (struct linux_dirent64 *)(p + bytes),
  31                                        len - bytes);
  32                if (n < 0)
  33                        return n;
  34                if (n == 0)
  35                        return bytes;
  36        }
  37        return 0;
  38}
  39
  40/*
  41 * Try to read all of a directory.  Returns the contents at *p, which
  42 * is kmalloced memory.  Returns the number of bytes read at *len.  Returns
  43 * NULL on error.
  44 */
  45static void * __init read_dir(char *path, int *len)
  46{
  47        int size;
  48        int fd = sys_open(path, 0, 0);
  49
  50        *len = 0;
  51        if (fd < 0)
  52                return NULL;
  53
  54        for (size = 1 << 9; size <= (PAGE_SIZE << MAX_ORDER); size <<= 1) {
  55                void *p = kmalloc(size, GFP_KERNEL);
  56                int n;
  57                if (!p)
  58                        break;
  59                n = do_read_dir(fd, p, size);
  60                if (n > 0) {
  61                        sys_close(fd);
  62                        *len = n;
  63                        return p;
  64                }
  65                kfree(p);
  66                if (n == -EINVAL)
  67                        continue;       /* Try a larger buffer */
  68                if (n < 0)
  69                        break;
  70        }
  71        sys_close(fd);
  72        return NULL;
  73}
  74
  75/*
  76 * recursively scan <path>, looking for a device node of type <dev>
  77 */
  78static int __init find_in_devfs(char *path, unsigned dev)
  79{
  80        char *end = path + strlen(path);
  81        int rest = path + 64 - end;
  82        int size;
  83        char *p = read_dir(path, &size);
  84        char *s;
  85
  86        if (!p)
  87                return -1;
  88        for (s = p; s < p + size; s += ((struct linux_dirent64 *)s)->d_reclen) {
  89                struct linux_dirent64 *d = (struct linux_dirent64 *)s;
  90                if (strlen(d->d_name) + 2 > rest)
  91                        continue;
  92                switch (d->d_type) {
  93                        case DT_BLK:
  94                                sprintf(end, "/%s", d->d_name);
  95                                if (bstat(path) != dev)
  96                                        break;
  97                                kfree(p);
  98                                return 0;
  99                        case DT_DIR:
 100                                if (strcmp(d->d_name, ".") == 0)
 101                                        break;
 102                                if (strcmp(d->d_name, "..") == 0)
 103                                        break;
 104                                sprintf(end, "/%s", d->d_name);
 105                                if (find_in_devfs(path, dev) < 0)
 106                                        break;
 107                                kfree(p);
 108                                return 0;
 109                }
 110        }
 111        kfree(p);
 112        return -1;
 113}
 114
 115/*
 116 * create a device node called <name> which points to
 117 * <devfs_name> if possible, otherwise find a device node
 118 * which matches <dev> and make <name> a symlink pointing to it.
 119 */
 120int __init create_dev(char *name, dev_t dev, char *devfs_name)
 121{
 122        char path[64];
 123
 124        sys_unlink(name);
 125        if (devfs_name && devfs_name[0]) {
 126                if (strncmp(devfs_name, "/dev/", 5) == 0)
 127                        devfs_name += 5;
 128                sprintf(path, "/dev/%s", devfs_name);
 129                if (sys_access(path, 0) == 0)
 130                        return sys_symlink(devfs_name, name);
 131        }
 132        if (!dev)
 133                return -1;
 134        strcpy(path, "/dev");
 135        if (find_in_devfs(path, new_encode_dev(dev)) < 0)
 136                return -1;
 137        return sys_symlink(path + 5, name);
 138}
 139