diff options
Diffstat (limited to 'arch/um/os-Linux')
-rw-r--r-- | arch/um/os-Linux/Makefile | 4 | ||||
-rw-r--r-- | arch/um/os-Linux/umid.c | 292 |
2 files changed, 294 insertions, 2 deletions
diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile index b83ac8e21c35..11e30b13e318 100644 --- a/arch/um/os-Linux/Makefile +++ b/arch/um/os-Linux/Makefile | |||
@@ -4,11 +4,11 @@ | |||
4 | # | 4 | # |
5 | 5 | ||
6 | obj-y = aio.o elf_aux.o file.o helper.o main.o mem.o process.o signal.o \ | 6 | obj-y = aio.o elf_aux.o file.o helper.o main.o mem.o process.o signal.o \ |
7 | start_up.o time.o tt.o tty.o uaccess.o user_syms.o drivers/ \ | 7 | start_up.o time.o tt.o tty.o uaccess.o umid.o user_syms.o drivers/ \ |
8 | sys-$(SUBARCH)/ | 8 | sys-$(SUBARCH)/ |
9 | 9 | ||
10 | USER_OBJS := aio.o elf_aux.o file.o helper.o main.o mem.o process.o signal.o \ | 10 | USER_OBJS := aio.o elf_aux.o file.o helper.o main.o mem.o process.o signal.o \ |
11 | start_up.o time.o tt.o tty.o uaccess.o | 11 | start_up.o time.o tt.o tty.o uaccess.o umid.o |
12 | 12 | ||
13 | elf_aux.o: $(ARCH_DIR)/kernel-offsets.h | 13 | elf_aux.o: $(ARCH_DIR)/kernel-offsets.h |
14 | CFLAGS_elf_aux.o += -I$(objtree)/arch/um | 14 | CFLAGS_elf_aux.o += -I$(objtree)/arch/um |
diff --git a/arch/um/os-Linux/umid.c b/arch/um/os-Linux/umid.c new file mode 100644 index 000000000000..77d69a348cf4 --- /dev/null +++ b/arch/um/os-Linux/umid.c | |||
@@ -0,0 +1,292 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <unistd.h> | ||
3 | #include <stdlib.h> | ||
4 | #include <string.h> | ||
5 | #include <errno.h> | ||
6 | #include <signal.h> | ||
7 | #include <dirent.h> | ||
8 | #include <sys/stat.h> | ||
9 | #include <sys/param.h> | ||
10 | #include "init.h" | ||
11 | #include "os.h" | ||
12 | #include "user.h" | ||
13 | #include "mode.h" | ||
14 | |||
15 | #define UML_DIR "~/.uml/" | ||
16 | |||
17 | #define UMID_LEN 64 | ||
18 | |||
19 | /* Changed by set_umid, which is run early in boot */ | ||
20 | char umid[UMID_LEN] = { 0 }; | ||
21 | |||
22 | /* Changed by set_uml_dir and make_uml_dir, which are run early in boot */ | ||
23 | static char *uml_dir = UML_DIR; | ||
24 | |||
25 | static int __init make_uml_dir(void) | ||
26 | { | ||
27 | char dir[512] = { '\0' }; | ||
28 | int len; | ||
29 | |||
30 | if(*uml_dir == '~'){ | ||
31 | char *home = getenv("HOME"); | ||
32 | |||
33 | if(home == NULL){ | ||
34 | printf("make_uml_dir : no value in environment for " | ||
35 | "$HOME\n"); | ||
36 | exit(1); | ||
37 | } | ||
38 | strlcpy(dir, home, sizeof(dir)); | ||
39 | uml_dir++; | ||
40 | } | ||
41 | strlcat(dir, uml_dir, sizeof(dir)); | ||
42 | len = strlen(dir); | ||
43 | if (len > 0 && dir[len - 1] != '/') | ||
44 | strlcat(dir, "/", sizeof(dir)); | ||
45 | |||
46 | uml_dir = malloc(strlen(dir) + 1); | ||
47 | if (uml_dir == NULL) { | ||
48 | printf("make_uml_dir : malloc failed, errno = %d\n", errno); | ||
49 | exit(1); | ||
50 | } | ||
51 | strcpy(uml_dir, dir); | ||
52 | |||
53 | if((mkdir(uml_dir, 0777) < 0) && (errno != EEXIST)){ | ||
54 | printf("Failed to mkdir '%s': %s\n", uml_dir, strerror(errno)); | ||
55 | return(-1); | ||
56 | } | ||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | static int actually_do_remove(char *dir) | ||
61 | { | ||
62 | DIR *directory; | ||
63 | struct dirent *ent; | ||
64 | int len; | ||
65 | char file[256]; | ||
66 | |||
67 | directory = opendir(dir); | ||
68 | if(directory == NULL){ | ||
69 | printk("actually_do_remove : couldn't open directory '%s', " | ||
70 | "errno = %d\n", dir, errno); | ||
71 | return(1); | ||
72 | } | ||
73 | while((ent = readdir(directory)) != NULL){ | ||
74 | if(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) | ||
75 | continue; | ||
76 | len = strlen(dir) + sizeof("/") + strlen(ent->d_name) + 1; | ||
77 | if(len > sizeof(file)){ | ||
78 | printk("Not deleting '%s' from '%s' - name too long\n", | ||
79 | ent->d_name, dir); | ||
80 | continue; | ||
81 | } | ||
82 | sprintf(file, "%s/%s", dir, ent->d_name); | ||
83 | if(unlink(file) < 0){ | ||
84 | printk("actually_do_remove : couldn't remove '%s' " | ||
85 | "from '%s', errno = %d\n", ent->d_name, dir, | ||
86 | errno); | ||
87 | return(1); | ||
88 | } | ||
89 | } | ||
90 | if(rmdir(dir) < 0){ | ||
91 | printk("actually_do_remove : couldn't rmdir '%s', " | ||
92 | "errno = %d\n", dir, errno); | ||
93 | return(1); | ||
94 | } | ||
95 | return(0); | ||
96 | } | ||
97 | |||
98 | extern int tracing_pid; | ||
99 | |||
100 | static int not_dead_yet(char *dir) | ||
101 | { | ||
102 | char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")]; | ||
103 | char pid[sizeof("nnnnn\0")], *end; | ||
104 | int dead, fd, p, n; | ||
105 | |||
106 | sprintf(file, "%s/pid", dir); | ||
107 | dead = 0; | ||
108 | fd = os_open_file(file, of_read(OPENFLAGS()), 0); | ||
109 | if(fd < 0){ | ||
110 | if(fd != -ENOENT){ | ||
111 | printk("not_dead_yet : couldn't open pid file '%s', " | ||
112 | "err = %d\n", file, -fd); | ||
113 | return(1); | ||
114 | } | ||
115 | dead = 1; | ||
116 | } | ||
117 | if(fd > 0){ | ||
118 | n = os_read_file(fd, pid, sizeof(pid)); | ||
119 | if(n < 0){ | ||
120 | printk("not_dead_yet : couldn't read pid file '%s', " | ||
121 | "err = %d\n", file, -n); | ||
122 | return(1); | ||
123 | } | ||
124 | p = strtoul(pid, &end, 0); | ||
125 | if(end == pid){ | ||
126 | printk("not_dead_yet : couldn't parse pid file '%s', " | ||
127 | "errno = %d\n", file, errno); | ||
128 | dead = 1; | ||
129 | } | ||
130 | if(((kill(p, 0) < 0) && (errno == ESRCH)) || | ||
131 | (p == CHOOSE_MODE(tracing_pid, os_getpid()))) | ||
132 | dead = 1; | ||
133 | } | ||
134 | if(!dead) | ||
135 | return(1); | ||
136 | return(actually_do_remove(dir)); | ||
137 | } | ||
138 | |||
139 | static void __init create_pid_file(void) | ||
140 | { | ||
141 | char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")]; | ||
142 | char pid[sizeof("nnnnn\0")]; | ||
143 | int fd, n; | ||
144 | |||
145 | if(umid_file_name("pid", file, sizeof(file))) | ||
146 | return; | ||
147 | |||
148 | fd = os_open_file(file, of_create(of_excl(of_rdwr(OPENFLAGS()))), | ||
149 | 0644); | ||
150 | if(fd < 0){ | ||
151 | printf("Open of machine pid file \"%s\" failed: %s\n", | ||
152 | file, strerror(-fd)); | ||
153 | return; | ||
154 | } | ||
155 | |||
156 | sprintf(pid, "%d\n", os_getpid()); | ||
157 | n = os_write_file(fd, pid, strlen(pid)); | ||
158 | if(n != strlen(pid)) | ||
159 | printf("Write of pid file failed - err = %d\n", -n); | ||
160 | os_close_file(fd); | ||
161 | } | ||
162 | |||
163 | int __init set_umid(char *name, int (*printer)(const char *fmt, ...)) | ||
164 | { | ||
165 | if(strlen(name) > UMID_LEN - 1) | ||
166 | (*printer)("Unique machine name is being truncated to %d " | ||
167 | "characters\n", UMID_LEN); | ||
168 | strlcpy(umid, name, sizeof(umid)); | ||
169 | |||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | static int umid_setup = 0; | ||
174 | |||
175 | int __init make_umid(int (*printer)(const char *fmt, ...)) | ||
176 | { | ||
177 | int fd, err; | ||
178 | char tmp[256]; | ||
179 | |||
180 | make_uml_dir(); | ||
181 | |||
182 | if(*umid == '\0'){ | ||
183 | strlcpy(tmp, uml_dir, sizeof(tmp)); | ||
184 | strcat(tmp, "XXXXXX"); | ||
185 | fd = mkstemp(tmp); | ||
186 | if(fd < 0){ | ||
187 | (*printer)("make_umid - mkstemp(%s) failed: %s\n", | ||
188 | tmp,strerror(errno)); | ||
189 | return(1); | ||
190 | } | ||
191 | |||
192 | os_close_file(fd); | ||
193 | /* There's a nice tiny little race between this unlink and | ||
194 | * the mkdir below. It'd be nice if there were a mkstemp | ||
195 | * for directories. | ||
196 | */ | ||
197 | unlink(tmp); | ||
198 | set_umid(&tmp[strlen(uml_dir)], printer); | ||
199 | } | ||
200 | |||
201 | sprintf(tmp, "%s%s", uml_dir, umid); | ||
202 | err = mkdir(tmp, 0777); | ||
203 | if(err < 0){ | ||
204 | if(errno == EEXIST){ | ||
205 | if(not_dead_yet(tmp)) | ||
206 | return -EEXIST; | ||
207 | err = mkdir(tmp, 0777); | ||
208 | } | ||
209 | } | ||
210 | if(err < 0){ | ||
211 | (*printer)("Failed to create %s - errno = %d\n", umid, errno); | ||
212 | return(-1); | ||
213 | } | ||
214 | |||
215 | umid_setup = 1; | ||
216 | |||
217 | create_pid_file(); | ||
218 | |||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | static int __init make_umid_init(void) | ||
223 | { | ||
224 | make_umid(printk); | ||
225 | |||
226 | return(0); | ||
227 | } | ||
228 | |||
229 | __initcall(make_umid_init); | ||
230 | |||
231 | int __init umid_file_name(char *name, char *buf, int len) | ||
232 | { | ||
233 | int n, err; | ||
234 | |||
235 | if(!umid_setup){ | ||
236 | err = make_umid(printk); | ||
237 | if(err) | ||
238 | return err; | ||
239 | } | ||
240 | |||
241 | n = strlen(uml_dir) + strlen(umid) + strlen("/") + strlen(name) + 1; | ||
242 | if(n > len){ | ||
243 | printk("umid_file_name : buffer too short\n"); | ||
244 | return(-1); | ||
245 | } | ||
246 | |||
247 | sprintf(buf, "%s%s/%s", uml_dir, umid, name); | ||
248 | return(0); | ||
249 | } | ||
250 | |||
251 | extern int umid_is_random; | ||
252 | |||
253 | char *get_umid(int only_if_set) | ||
254 | { | ||
255 | if(only_if_set && umid_is_random) | ||
256 | return NULL; | ||
257 | return umid; | ||
258 | } | ||
259 | |||
260 | static int __init set_uml_dir(char *name, int *add) | ||
261 | { | ||
262 | if((strlen(name) > 0) && (name[strlen(name) - 1] != '/')){ | ||
263 | uml_dir = malloc(strlen(name) + 2); | ||
264 | if(uml_dir == NULL){ | ||
265 | printf("Failed to malloc uml_dir - error = %d\n", | ||
266 | errno); | ||
267 | uml_dir = name; | ||
268 | /* Return 0 here because do_initcalls doesn't look at | ||
269 | * the return value. | ||
270 | */ | ||
271 | return(0); | ||
272 | } | ||
273 | sprintf(uml_dir, "%s/", name); | ||
274 | } | ||
275 | else uml_dir = name; | ||
276 | return(0); | ||
277 | } | ||
278 | |||
279 | __uml_setup("uml_dir=", set_uml_dir, | ||
280 | "uml_dir=<directory>\n" | ||
281 | " The location to place the pid and umid files.\n\n" | ||
282 | ); | ||
283 | |||
284 | static void remove_umid_dir(void) | ||
285 | { | ||
286 | char dir[strlen(uml_dir) + UMID_LEN + 1]; | ||
287 | |||
288 | sprintf(dir, "%s%s", uml_dir, umid); | ||
289 | actually_do_remove(dir); | ||
290 | } | ||
291 | |||
292 | __uml_exitcall(remove_umid_dir); | ||