0001
0002
0003
0004
0005
0006 #include <stdio.h>
0007 #include <stdlib.h>
0008 #include <dirent.h>
0009 #include <errno.h>
0010 #include <fcntl.h>
0011 #include <signal.h>
0012 #include <string.h>
0013 #include <unistd.h>
0014 #include <sys/stat.h>
0015 #include <init.h>
0016 #include <os.h>
0017
0018 #define UML_DIR "~/.uml/"
0019
0020 #define UMID_LEN 64
0021
0022
0023 static char umid[UMID_LEN] = { 0 };
0024
0025
0026 static char *uml_dir = UML_DIR;
0027
0028 static int __init make_uml_dir(void)
0029 {
0030 char dir[512] = { '\0' };
0031 int len, err;
0032
0033 if (*uml_dir == '~') {
0034 char *home = getenv("HOME");
0035
0036 err = -ENOENT;
0037 if (home == NULL) {
0038 printk(UM_KERN_ERR
0039 "%s: no value in environment for $HOME\n",
0040 __func__);
0041 goto err;
0042 }
0043 strlcpy(dir, home, sizeof(dir));
0044 uml_dir++;
0045 }
0046 strlcat(dir, uml_dir, sizeof(dir));
0047 len = strlen(dir);
0048 if (len > 0 && dir[len - 1] != '/')
0049 strlcat(dir, "/", sizeof(dir));
0050
0051 err = -ENOMEM;
0052 uml_dir = malloc(strlen(dir) + 1);
0053 if (uml_dir == NULL) {
0054 printk(UM_KERN_ERR "%s : malloc failed, errno = %d\n",
0055 __func__, errno);
0056 goto err;
0057 }
0058 strcpy(uml_dir, dir);
0059
0060 if ((mkdir(uml_dir, 0777) < 0) && (errno != EEXIST)) {
0061 printk(UM_KERN_ERR "Failed to mkdir '%s': %s\n",
0062 uml_dir, strerror(errno));
0063 err = -errno;
0064 goto err_free;
0065 }
0066 return 0;
0067
0068 err_free:
0069 free(uml_dir);
0070 err:
0071 uml_dir = NULL;
0072 return err;
0073 }
0074
0075
0076
0077
0078
0079
0080
0081 static int remove_files_and_dir(char *dir)
0082 {
0083 DIR *directory;
0084 struct dirent *ent;
0085 int len;
0086 char file[256];
0087 int ret;
0088
0089 directory = opendir(dir);
0090 if (directory == NULL) {
0091 if (errno != ENOENT)
0092 return -errno;
0093 else
0094 return 0;
0095 }
0096
0097 while ((ent = readdir(directory)) != NULL) {
0098 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
0099 continue;
0100 len = strlen(dir) + strlen("/") + strlen(ent->d_name) + 1;
0101 if (len > sizeof(file)) {
0102 ret = -E2BIG;
0103 goto out;
0104 }
0105
0106 sprintf(file, "%s/%s", dir, ent->d_name);
0107 if (unlink(file) < 0 && errno != ENOENT) {
0108 ret = -errno;
0109 goto out;
0110 }
0111 }
0112
0113 if (rmdir(dir) < 0 && errno != ENOENT) {
0114 ret = -errno;
0115 goto out;
0116 }
0117
0118 ret = 0;
0119 out:
0120 closedir(directory);
0121 return ret;
0122 }
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136 static inline int is_umdir_used(char *dir)
0137 {
0138 char pid[sizeof("nnnnnnnnn")], *end, *file;
0139 int fd, p, n, err;
0140 size_t filelen = strlen(dir) + sizeof("/pid") + 1;
0141
0142 file = malloc(filelen);
0143 if (!file)
0144 return -ENOMEM;
0145
0146 snprintf(file, filelen, "%s/pid", dir);
0147
0148 fd = open(file, O_RDONLY);
0149 if (fd < 0) {
0150 fd = -errno;
0151 if (fd != -ENOENT) {
0152 printk(UM_KERN_ERR "is_umdir_used : couldn't open pid "
0153 "file '%s', err = %d\n", file, -fd);
0154 }
0155 goto out;
0156 }
0157
0158 err = 0;
0159 n = read(fd, pid, sizeof(pid));
0160 if (n < 0) {
0161 printk(UM_KERN_ERR "is_umdir_used : couldn't read pid file "
0162 "'%s', err = %d\n", file, errno);
0163 goto out_close;
0164 } else if (n == 0) {
0165 printk(UM_KERN_ERR "is_umdir_used : couldn't read pid file "
0166 "'%s', 0-byte read\n", file);
0167 goto out_close;
0168 }
0169
0170 p = strtoul(pid, &end, 0);
0171 if (end == pid) {
0172 printk(UM_KERN_ERR "is_umdir_used : couldn't parse pid file "
0173 "'%s', errno = %d\n", file, errno);
0174 goto out_close;
0175 }
0176
0177 if ((kill(p, 0) == 0) || (errno != ESRCH)) {
0178 printk(UM_KERN_ERR "umid \"%s\" is already in use by pid %d\n",
0179 umid, p);
0180 return 1;
0181 }
0182
0183 out_close:
0184 close(fd);
0185 out:
0186 free(file);
0187 return 0;
0188 }
0189
0190
0191
0192
0193
0194
0195
0196 static int umdir_take_if_dead(char *dir)
0197 {
0198 int ret;
0199 if (is_umdir_used(dir))
0200 return -EEXIST;
0201
0202 ret = remove_files_and_dir(dir);
0203 if (ret) {
0204 printk(UM_KERN_ERR "is_umdir_used - remove_files_and_dir "
0205 "failed with err = %d\n", ret);
0206 }
0207 return ret;
0208 }
0209
0210 static void __init create_pid_file(void)
0211 {
0212 char pid[sizeof("nnnnnnnnn")], *file;
0213 int fd, n;
0214
0215 n = strlen(uml_dir) + UMID_LEN + sizeof("/pid");
0216 file = malloc(n);
0217 if (!file)
0218 return;
0219
0220 if (umid_file_name("pid", file, n))
0221 goto out;
0222
0223 fd = open(file, O_RDWR | O_CREAT | O_EXCL, 0644);
0224 if (fd < 0) {
0225 printk(UM_KERN_ERR "Open of machine pid file \"%s\" failed: "
0226 "%s\n", file, strerror(errno));
0227 goto out;
0228 }
0229
0230 snprintf(pid, sizeof(pid), "%d\n", getpid());
0231 n = write(fd, pid, strlen(pid));
0232 if (n != strlen(pid))
0233 printk(UM_KERN_ERR "Write of pid file failed - err = %d\n",
0234 errno);
0235
0236 close(fd);
0237 out:
0238 free(file);
0239 }
0240
0241 int __init set_umid(char *name)
0242 {
0243 if (strlen(name) > UMID_LEN - 1)
0244 return -E2BIG;
0245
0246 strlcpy(umid, name, sizeof(umid));
0247
0248 return 0;
0249 }
0250
0251
0252 static int umid_setup = 0;
0253
0254 static int __init make_umid(void)
0255 {
0256 int fd, err;
0257 char tmp[256];
0258
0259 if (umid_setup)
0260 return 0;
0261
0262 make_uml_dir();
0263
0264 if (*umid == '\0') {
0265 strlcpy(tmp, uml_dir, sizeof(tmp));
0266 strlcat(tmp, "XXXXXX", sizeof(tmp));
0267 fd = mkstemp(tmp);
0268 if (fd < 0) {
0269 printk(UM_KERN_ERR "make_umid - mkstemp(%s) failed: "
0270 "%s\n", tmp, strerror(errno));
0271 err = -errno;
0272 goto err;
0273 }
0274
0275 close(fd);
0276
0277 set_umid(&tmp[strlen(uml_dir)]);
0278
0279
0280
0281
0282
0283
0284 if (unlink(tmp)) {
0285 err = -errno;
0286 goto err;
0287 }
0288 }
0289
0290 snprintf(tmp, sizeof(tmp), "%s%s", uml_dir, umid);
0291 err = mkdir(tmp, 0777);
0292 if (err < 0) {
0293 err = -errno;
0294 if (err != -EEXIST)
0295 goto err;
0296
0297 if (umdir_take_if_dead(tmp) < 0)
0298 goto err;
0299
0300 err = mkdir(tmp, 0777);
0301 }
0302 if (err) {
0303 err = -errno;
0304 printk(UM_KERN_ERR "Failed to create '%s' - err = %d\n", umid,
0305 errno);
0306 goto err;
0307 }
0308
0309 umid_setup = 1;
0310
0311 create_pid_file();
0312
0313 err = 0;
0314 err:
0315 return err;
0316 }
0317
0318 static int __init make_umid_init(void)
0319 {
0320 if (!make_umid())
0321 return 0;
0322
0323
0324
0325
0326
0327 printk(UM_KERN_ERR "Failed to initialize umid \"%s\", trying with a "
0328 "random umid\n", umid);
0329 *umid = '\0';
0330 make_umid();
0331
0332 return 0;
0333 }
0334
0335 __initcall(make_umid_init);
0336
0337 int __init umid_file_name(char *name, char *buf, int len)
0338 {
0339 int n, err;
0340
0341 err = make_umid();
0342 if (err)
0343 return err;
0344
0345 n = snprintf(buf, len, "%s%s/%s", uml_dir, umid, name);
0346 if (n >= len) {
0347 printk(UM_KERN_ERR "umid_file_name : buffer too short\n");
0348 return -E2BIG;
0349 }
0350
0351 return 0;
0352 }
0353
0354 char *get_umid(void)
0355 {
0356 return umid;
0357 }
0358
0359 static int __init set_uml_dir(char *name, int *add)
0360 {
0361 if (*name == '\0') {
0362 os_warn("uml_dir can't be an empty string\n");
0363 return 0;
0364 }
0365
0366 if (name[strlen(name) - 1] == '/') {
0367 uml_dir = name;
0368 return 0;
0369 }
0370
0371 uml_dir = malloc(strlen(name) + 2);
0372 if (uml_dir == NULL) {
0373 os_warn("Failed to malloc uml_dir - error = %d\n", errno);
0374
0375
0376
0377
0378
0379 return 0;
0380 }
0381 sprintf(uml_dir, "%s/", name);
0382
0383 return 0;
0384 }
0385
0386 __uml_setup("uml_dir=", set_uml_dir,
0387 "uml_dir=<directory>\n"
0388 " The location to place the pid and umid files.\n\n"
0389 );
0390
0391 static void remove_umid_dir(void)
0392 {
0393 char *dir, err;
0394
0395 dir = malloc(strlen(uml_dir) + UMID_LEN + 1);
0396 if (!dir)
0397 return;
0398
0399 sprintf(dir, "%s%s", uml_dir, umid);
0400 err = remove_files_and_dir(dir);
0401 if (err)
0402 os_warn("%s - remove_files_and_dir failed with err = %d\n",
0403 __func__, err);
0404
0405 free(dir);
0406 }
0407
0408 __uml_exitcall(remove_umid_dir);