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