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