at v2.6.13 137 lines 2.9 kB view raw
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}