diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /init/do_mounts_devfs.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'init/do_mounts_devfs.c')
-rw-r--r-- | init/do_mounts_devfs.c | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/init/do_mounts_devfs.c b/init/do_mounts_devfs.c new file mode 100644 index 000000000000..cc526474690a --- /dev/null +++ b/init/do_mounts_devfs.c | |||
@@ -0,0 +1,137 @@ | |||
1 | |||
2 | #include <linux/kernel.h> | ||
3 | #include <linux/dirent.h> | ||
4 | #include <linux/string.h> | ||
5 | |||
6 | #include "do_mounts.h" | ||
7 | |||
8 | void __init mount_devfs(void) | ||
9 | { | ||
10 | sys_mount("devfs", "/dev", "devfs", 0, NULL); | ||
11 | } | ||
12 | |||
13 | void __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 | */ | ||
22 | static 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 | */ | ||
44 | static 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 | */ | ||
77 | static 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 | */ | ||
119 | int __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 | } | ||