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 /* Have we created the files? Should we remove them? */ 35 static int umid_owned = 0; 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 87 static void __init create_pid_file(void) 88 { 89 char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")]; 90 char pid[sizeof("nnnnn\0")]; 91 int fd, n; 92 93 if(umid_file_name("pid", file, sizeof(file))) 94 return; 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)); 101 return; 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); 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]; 152 if (!umid_owned) 153 return; 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 { 161 if(only_if_set && umid_is_random) 162 return NULL; 163 return umid; 164 } 165 166 static int not_dead_yet(char *dir) 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 } 200 if(!dead) 201 return(1); 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 } 240 strlcat(dir, uml_dir, sizeof(dir)); 241 len = strlen(dir); 242 if (len > 0 && dir[len - 1] != '/') 243 strlcat(dir, "/", sizeof(dir)); 244 245 uml_dir = malloc(strlen(dir) + 1); 246 if (uml_dir == NULL) { 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); 291 umid_owned = 0; 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 302 umid_owned = 1; 303 return 0; 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); 316 create_pid_file(); 317 return 0; 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 */ 331