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