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