197870c34SAlex Dewar // SPDX-License-Identifier: GPL-2.0
2ba180fd4SJeff Dike /*
3ba180fd4SJeff Dike * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
4ba180fd4SJeff Dike */
5ba180fd4SJeff Dike
62264c475SJeff Dike #include <stdio.h>
72264c475SJeff Dike #include <stdlib.h>
82264c475SJeff Dike #include <dirent.h>
9ba180fd4SJeff Dike #include <errno.h>
10ba180fd4SJeff Dike #include <fcntl.h>
11ba180fd4SJeff Dike #include <signal.h>
12ba180fd4SJeff Dike #include <string.h>
13ba180fd4SJeff Dike #include <unistd.h>
142264c475SJeff Dike #include <sys/stat.h>
1537185b33SAl Viro #include <init.h>
1637185b33SAl Viro #include <os.h>
172264c475SJeff Dike
182264c475SJeff Dike #define UML_DIR "~/.uml/"
192264c475SJeff Dike
202264c475SJeff Dike #define UMID_LEN 64
212264c475SJeff Dike
222264c475SJeff Dike /* Changed by set_umid, which is run early in boot */
23de5fe76eSJeff Dike static char umid[UMID_LEN] = { 0 };
242264c475SJeff Dike
252264c475SJeff Dike /* Changed by set_uml_dir and make_uml_dir, which are run early in boot */
262264c475SJeff Dike static char *uml_dir = UML_DIR;
272264c475SJeff Dike
make_uml_dir(void)282264c475SJeff Dike static int __init make_uml_dir(void)
292264c475SJeff Dike {
302264c475SJeff Dike char dir[512] = { '\0' };
317eebe8a9SJeff Dike int len, err;
322264c475SJeff Dike
332264c475SJeff Dike if (*uml_dir == '~') {
342264c475SJeff Dike char *home = getenv("HOME");
352264c475SJeff Dike
367eebe8a9SJeff Dike err = -ENOENT;
372264c475SJeff Dike if (home == NULL) {
38e03c78acSMasami Hiramatsu printk(UM_KERN_ERR
39e03c78acSMasami Hiramatsu "%s: no value in environment for $HOME\n",
40e03c78acSMasami Hiramatsu __func__);
417eebe8a9SJeff Dike goto err;
422264c475SJeff Dike }
43*61ce78f2SAzeem Shaikh strscpy(dir, home, sizeof(dir));
442264c475SJeff Dike uml_dir++;
452264c475SJeff Dike }
462264c475SJeff Dike strlcat(dir, uml_dir, sizeof(dir));
472264c475SJeff Dike len = strlen(dir);
482264c475SJeff Dike if (len > 0 && dir[len - 1] != '/')
492264c475SJeff Dike strlcat(dir, "/", sizeof(dir));
502264c475SJeff Dike
517eebe8a9SJeff Dike err = -ENOMEM;
522264c475SJeff Dike uml_dir = malloc(strlen(dir) + 1);
532264c475SJeff Dike if (uml_dir == NULL) {
54e03c78acSMasami Hiramatsu printk(UM_KERN_ERR "%s : malloc failed, errno = %d\n",
55e03c78acSMasami Hiramatsu __func__, errno);
567eebe8a9SJeff Dike goto err;
572264c475SJeff Dike }
582264c475SJeff Dike strcpy(uml_dir, dir);
592264c475SJeff Dike
602264c475SJeff Dike if ((mkdir(uml_dir, 0777) < 0) && (errno != EEXIST)) {
61e03c78acSMasami Hiramatsu printk(UM_KERN_ERR "Failed to mkdir '%s': %s\n",
62e03c78acSMasami Hiramatsu uml_dir, strerror(errno));
637eebe8a9SJeff Dike err = -errno;
647eebe8a9SJeff Dike goto err_free;
652264c475SJeff Dike }
662264c475SJeff Dike return 0;
677eebe8a9SJeff Dike
687eebe8a9SJeff Dike err_free:
697eebe8a9SJeff Dike free(uml_dir);
707eebe8a9SJeff Dike err:
717eebe8a9SJeff Dike uml_dir = NULL;
727eebe8a9SJeff Dike return err;
732264c475SJeff Dike }
742264c475SJeff Dike
75eb28931eSPaolo 'Blaisorblade' Giarrusso /*
76eb28931eSPaolo 'Blaisorblade' Giarrusso * Unlinks the files contained in @dir and then removes @dir.
77eb28931eSPaolo 'Blaisorblade' Giarrusso * Doesn't handle directory trees, so it's not like rm -rf, but almost such. We
78ba180fd4SJeff Dike * ignore ENOENT errors for anything (they happen, strangely enough - possibly
79ba180fd4SJeff Dike * due to races between multiple dying UML threads).
80eb28931eSPaolo 'Blaisorblade' Giarrusso */
remove_files_and_dir(char * dir)81eb28931eSPaolo 'Blaisorblade' Giarrusso static int remove_files_and_dir(char *dir)
822264c475SJeff Dike {
832264c475SJeff Dike DIR *directory;
842264c475SJeff Dike struct dirent *ent;
852264c475SJeff Dike int len;
862264c475SJeff Dike char file[256];
87eb28931eSPaolo 'Blaisorblade' Giarrusso int ret;
882264c475SJeff Dike
892264c475SJeff Dike directory = opendir(dir);
90eb28931eSPaolo 'Blaisorblade' Giarrusso if (directory == NULL) {
91eb28931eSPaolo 'Blaisorblade' Giarrusso if (errno != ENOENT)
927eebe8a9SJeff Dike return -errno;
93eb28931eSPaolo 'Blaisorblade' Giarrusso else
94eb28931eSPaolo 'Blaisorblade' Giarrusso return 0;
95eb28931eSPaolo 'Blaisorblade' Giarrusso }
967eebe8a9SJeff Dike
972264c475SJeff Dike while ((ent = readdir(directory)) != NULL) {
982264c475SJeff Dike if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
992264c475SJeff Dike continue;
100e8a58591SMaciej Żenczykowski len = strlen(dir) + strlen("/") + strlen(ent->d_name) + 1;
101eb28931eSPaolo 'Blaisorblade' Giarrusso if (len > sizeof(file)) {
102eb28931eSPaolo 'Blaisorblade' Giarrusso ret = -E2BIG;
103eb28931eSPaolo 'Blaisorblade' Giarrusso goto out;
104eb28931eSPaolo 'Blaisorblade' Giarrusso }
1057eebe8a9SJeff Dike
1062264c475SJeff Dike sprintf(file, "%s/%s", dir, ent->d_name);
107eb28931eSPaolo 'Blaisorblade' Giarrusso if (unlink(file) < 0 && errno != ENOENT) {
108eb28931eSPaolo 'Blaisorblade' Giarrusso ret = -errno;
109eb28931eSPaolo 'Blaisorblade' Giarrusso goto out;
1102264c475SJeff Dike }
111eb28931eSPaolo 'Blaisorblade' Giarrusso }
1127eebe8a9SJeff Dike
113eb28931eSPaolo 'Blaisorblade' Giarrusso if (rmdir(dir) < 0 && errno != ENOENT) {
114eb28931eSPaolo 'Blaisorblade' Giarrusso ret = -errno;
115eb28931eSPaolo 'Blaisorblade' Giarrusso goto out;
116eb28931eSPaolo 'Blaisorblade' Giarrusso }
117eb28931eSPaolo 'Blaisorblade' Giarrusso
118eb28931eSPaolo 'Blaisorblade' Giarrusso ret = 0;
119eb28931eSPaolo 'Blaisorblade' Giarrusso out:
120eb28931eSPaolo 'Blaisorblade' Giarrusso closedir(directory);
121eb28931eSPaolo 'Blaisorblade' Giarrusso return ret;
1222264c475SJeff Dike }
1232264c475SJeff Dike
124ba180fd4SJeff Dike /*
125ba180fd4SJeff Dike * This says that there isn't already a user of the specified directory even if
1267eebe8a9SJeff Dike * there are errors during the checking. This is because if these errors
1277eebe8a9SJeff Dike * happen, the directory is unusable by the pre-existing UML, so we might as
1287eebe8a9SJeff Dike * well take it over. This could happen either by
1297eebe8a9SJeff Dike * the existing UML somehow corrupting its umid directory
1307eebe8a9SJeff Dike * something other than UML sticking stuff in the directory
1317eebe8a9SJeff Dike * this boot racing with a shutdown of the other UML
1327eebe8a9SJeff Dike * In any of these cases, the directory isn't useful for anything else.
133912ad922SPaolo 'Blaisorblade' Giarrusso *
134912ad922SPaolo 'Blaisorblade' Giarrusso * Boolean return: 1 if in use, 0 otherwise.
1357eebe8a9SJeff Dike */
is_umdir_used(char * dir)136912ad922SPaolo 'Blaisorblade' Giarrusso static inline int is_umdir_used(char *dir)
1372264c475SJeff Dike {
138e8a58591SMaciej Żenczykowski char pid[sizeof("nnnnnnnnn")], *end, *file;
1396e12adccSHaowen Bai int fd, p, n, err;
14097be7ceaSAnton Ivanov size_t filelen = strlen(dir) + sizeof("/pid") + 1;
1412264c475SJeff Dike
14297be7ceaSAnton Ivanov file = malloc(filelen);
14397be7ceaSAnton Ivanov if (!file)
14497be7ceaSAnton Ivanov return -ENOMEM;
1450d4e5ac7SBartosz Golaszewski
14697be7ceaSAnton Ivanov snprintf(file, filelen, "%s/pid", dir);
1477eebe8a9SJeff Dike
1487eebe8a9SJeff Dike fd = open(file, O_RDONLY);
1492264c475SJeff Dike if (fd < 0) {
150d84a19ceSPaolo 'Blaisorblade' Giarrusso fd = -errno;
1512264c475SJeff Dike if (fd != -ENOENT) {
152ba180fd4SJeff Dike printk(UM_KERN_ERR "is_umdir_used : couldn't open pid "
153ba180fd4SJeff Dike "file '%s', err = %d\n", file, -fd);
1542264c475SJeff Dike }
1557eebe8a9SJeff Dike goto out;
1562264c475SJeff Dike }
1577eebe8a9SJeff Dike
1587eebe8a9SJeff Dike err = 0;
1597eebe8a9SJeff Dike n = read(fd, pid, sizeof(pid));
160d84a19ceSPaolo 'Blaisorblade' Giarrusso if (n < 0) {
161ba180fd4SJeff Dike printk(UM_KERN_ERR "is_umdir_used : couldn't read pid file "
162ba180fd4SJeff Dike "'%s', err = %d\n", file, errno);
163d84a19ceSPaolo 'Blaisorblade' Giarrusso goto out_close;
164d84a19ceSPaolo 'Blaisorblade' Giarrusso } else if (n == 0) {
165ba180fd4SJeff Dike printk(UM_KERN_ERR "is_umdir_used : couldn't read pid file "
166ba180fd4SJeff Dike "'%s', 0-byte read\n", file);
1677eebe8a9SJeff Dike goto out_close;
1682264c475SJeff Dike }
1697eebe8a9SJeff Dike
1702264c475SJeff Dike p = strtoul(pid, &end, 0);
1712264c475SJeff Dike if (end == pid) {
172ba180fd4SJeff Dike printk(UM_KERN_ERR "is_umdir_used : couldn't parse pid file "
173ba180fd4SJeff Dike "'%s', errno = %d\n", file, errno);
1747eebe8a9SJeff Dike goto out_close;
1752264c475SJeff Dike }
1767eebe8a9SJeff Dike
1771fbbd684SJeff Dike if ((kill(p, 0) == 0) || (errno != ESRCH)) {
178ba180fd4SJeff Dike printk(UM_KERN_ERR "umid \"%s\" is already in use by pid %d\n",
179ba180fd4SJeff Dike umid, p);
1807eebe8a9SJeff Dike return 1;
1811fbbd684SJeff Dike }
1827eebe8a9SJeff Dike
1837eebe8a9SJeff Dike out_close:
1847eebe8a9SJeff Dike close(fd);
1857eebe8a9SJeff Dike out:
1860d4e5ac7SBartosz Golaszewski free(file);
1877eebe8a9SJeff Dike return 0;
1882264c475SJeff Dike }
1892264c475SJeff Dike
190912ad922SPaolo 'Blaisorblade' Giarrusso /*
191912ad922SPaolo 'Blaisorblade' Giarrusso * Try to remove the directory @dir unless it's in use.
192912ad922SPaolo 'Blaisorblade' Giarrusso * Precondition: @dir exists.
193912ad922SPaolo 'Blaisorblade' Giarrusso * Returns 0 for success, < 0 for failure in removal or if the directory is in
194912ad922SPaolo 'Blaisorblade' Giarrusso * use.
195912ad922SPaolo 'Blaisorblade' Giarrusso */
umdir_take_if_dead(char * dir)196912ad922SPaolo 'Blaisorblade' Giarrusso static int umdir_take_if_dead(char *dir)
197912ad922SPaolo 'Blaisorblade' Giarrusso {
198912ad922SPaolo 'Blaisorblade' Giarrusso int ret;
199912ad922SPaolo 'Blaisorblade' Giarrusso if (is_umdir_used(dir))
200912ad922SPaolo 'Blaisorblade' Giarrusso return -EEXIST;
201912ad922SPaolo 'Blaisorblade' Giarrusso
202eb28931eSPaolo 'Blaisorblade' Giarrusso ret = remove_files_and_dir(dir);
203912ad922SPaolo 'Blaisorblade' Giarrusso if (ret) {
204ba180fd4SJeff Dike printk(UM_KERN_ERR "is_umdir_used - remove_files_and_dir "
205ba180fd4SJeff Dike "failed with err = %d\n", ret);
206912ad922SPaolo 'Blaisorblade' Giarrusso }
207912ad922SPaolo 'Blaisorblade' Giarrusso return ret;
208912ad922SPaolo 'Blaisorblade' Giarrusso }
209912ad922SPaolo 'Blaisorblade' Giarrusso
create_pid_file(void)2102264c475SJeff Dike static void __init create_pid_file(void)
2112264c475SJeff Dike {
212e8a58591SMaciej Żenczykowski char pid[sizeof("nnnnnnnnn")], *file;
2132264c475SJeff Dike int fd, n;
2142264c475SJeff Dike
215e8a58591SMaciej Żenczykowski n = strlen(uml_dir) + UMID_LEN + sizeof("/pid");
216ba758cfcSWen Yang file = malloc(n);
2170d4e5ac7SBartosz Golaszewski if (!file)
2182264c475SJeff Dike return;
2192264c475SJeff Dike
220ba758cfcSWen Yang if (umid_file_name("pid", file, n))
2210d4e5ac7SBartosz Golaszewski goto out;
2220d4e5ac7SBartosz Golaszewski
2237eebe8a9SJeff Dike fd = open(file, O_RDWR | O_CREAT | O_EXCL, 0644);
2242264c475SJeff Dike if (fd < 0) {
225ba180fd4SJeff Dike printk(UM_KERN_ERR "Open of machine pid file \"%s\" failed: "
226ba180fd4SJeff Dike "%s\n", file, strerror(errno));
2270d4e5ac7SBartosz Golaszewski goto out;
2282264c475SJeff Dike }
2292264c475SJeff Dike
2307eebe8a9SJeff Dike snprintf(pid, sizeof(pid), "%d\n", getpid());
2317eebe8a9SJeff Dike n = write(fd, pid, strlen(pid));
2322264c475SJeff Dike if (n != strlen(pid))
233ba180fd4SJeff Dike printk(UM_KERN_ERR "Write of pid file failed - err = %d\n",
234ba180fd4SJeff Dike errno);
2357eebe8a9SJeff Dike
2367eebe8a9SJeff Dike close(fd);
2370d4e5ac7SBartosz Golaszewski out:
2380d4e5ac7SBartosz Golaszewski free(file);
2392264c475SJeff Dike }
2402264c475SJeff Dike
set_umid(char * name)2417eebe8a9SJeff Dike int __init set_umid(char *name)
2422264c475SJeff Dike {
2432264c475SJeff Dike if (strlen(name) > UMID_LEN - 1)
2447eebe8a9SJeff Dike return -E2BIG;
2457eebe8a9SJeff Dike
246*61ce78f2SAzeem Shaikh strscpy(umid, name, sizeof(umid));
2472264c475SJeff Dike
2482264c475SJeff Dike return 0;
2492264c475SJeff Dike }
2502264c475SJeff Dike
251de5fe76eSJeff Dike /* Changed in make_umid, which is called during early boot */
2522264c475SJeff Dike static int umid_setup = 0;
2532264c475SJeff Dike
make_umid(void)25499764fa4SWANG Cong static int __init make_umid(void)
2552264c475SJeff Dike {
2562264c475SJeff Dike int fd, err;
2572264c475SJeff Dike char tmp[256];
2582264c475SJeff Dike
2597eebe8a9SJeff Dike if (umid_setup)
2607eebe8a9SJeff Dike return 0;
2617eebe8a9SJeff Dike
2622264c475SJeff Dike make_uml_dir();
2632264c475SJeff Dike
2642264c475SJeff Dike if (*umid == '\0') {
265*61ce78f2SAzeem Shaikh strscpy(tmp, uml_dir, sizeof(tmp));
2667eebe8a9SJeff Dike strlcat(tmp, "XXXXXX", sizeof(tmp));
2672264c475SJeff Dike fd = mkstemp(tmp);
2682264c475SJeff Dike if (fd < 0) {
269ba180fd4SJeff Dike printk(UM_KERN_ERR "make_umid - mkstemp(%s) failed: "
270ba180fd4SJeff Dike "%s\n", tmp, strerror(errno));
2717eebe8a9SJeff Dike err = -errno;
2727eebe8a9SJeff Dike goto err;
2732264c475SJeff Dike }
2742264c475SJeff Dike
2757eebe8a9SJeff Dike close(fd);
2767eebe8a9SJeff Dike
2777eebe8a9SJeff Dike set_umid(&tmp[strlen(uml_dir)]);
2787eebe8a9SJeff Dike
279ba180fd4SJeff Dike /*
280ba180fd4SJeff Dike * There's a nice tiny little race between this unlink and
2812264c475SJeff Dike * the mkdir below. It'd be nice if there were a mkstemp
2822264c475SJeff Dike * for directories.
2832264c475SJeff Dike */
2847eebe8a9SJeff Dike if (unlink(tmp)) {
2857eebe8a9SJeff Dike err = -errno;
2867eebe8a9SJeff Dike goto err;
2877eebe8a9SJeff Dike }
2882264c475SJeff Dike }
2892264c475SJeff Dike
2907eebe8a9SJeff Dike snprintf(tmp, sizeof(tmp), "%s%s", uml_dir, umid);
2912264c475SJeff Dike err = mkdir(tmp, 0777);
2922264c475SJeff Dike if (err < 0) {
2937eebe8a9SJeff Dike err = -errno;
2941fbbd684SJeff Dike if (err != -EEXIST)
2957eebe8a9SJeff Dike goto err;
2967eebe8a9SJeff Dike
297912ad922SPaolo 'Blaisorblade' Giarrusso if (umdir_take_if_dead(tmp) < 0)
2987eebe8a9SJeff Dike goto err;
2997eebe8a9SJeff Dike
3002264c475SJeff Dike err = mkdir(tmp, 0777);
3012264c475SJeff Dike }
3021fbbd684SJeff Dike if (err) {
3031fbbd684SJeff Dike err = -errno;
304ba180fd4SJeff Dike printk(UM_KERN_ERR "Failed to create '%s' - err = %d\n", umid,
305ba180fd4SJeff Dike errno);
3061fbbd684SJeff Dike goto err;
3072264c475SJeff Dike }
3082264c475SJeff Dike
3092264c475SJeff Dike umid_setup = 1;
3102264c475SJeff Dike
3112264c475SJeff Dike create_pid_file();
3122264c475SJeff Dike
3131fbbd684SJeff Dike err = 0;
3147eebe8a9SJeff Dike err:
3157eebe8a9SJeff Dike return err;
3162264c475SJeff Dike }
3172264c475SJeff Dike
make_umid_init(void)3182264c475SJeff Dike static int __init make_umid_init(void)
3192264c475SJeff Dike {
3201fbbd684SJeff Dike if (!make_umid())
3211fbbd684SJeff Dike return 0;
3221fbbd684SJeff Dike
323ba180fd4SJeff Dike /*
324ba180fd4SJeff Dike * If initializing with the given umid failed, then try again with
3251fbbd684SJeff Dike * a random one.
3261fbbd684SJeff Dike */
327ba180fd4SJeff Dike printk(UM_KERN_ERR "Failed to initialize umid \"%s\", trying with a "
328ba180fd4SJeff Dike "random umid\n", umid);
3291fbbd684SJeff Dike *umid = '\0';
3307eebe8a9SJeff Dike make_umid();
3312264c475SJeff Dike
3327eebe8a9SJeff Dike return 0;
3332264c475SJeff Dike }
3342264c475SJeff Dike
3352264c475SJeff Dike __initcall(make_umid_init);
3362264c475SJeff Dike
umid_file_name(char * name,char * buf,int len)3372264c475SJeff Dike int __init umid_file_name(char *name, char *buf, int len)
3382264c475SJeff Dike {
3392264c475SJeff Dike int n, err;
3402264c475SJeff Dike
3417eebe8a9SJeff Dike err = make_umid();
3422264c475SJeff Dike if (err)
3432264c475SJeff Dike return err;
3442264c475SJeff Dike
3457eebe8a9SJeff Dike n = snprintf(buf, len, "%s%s/%s", uml_dir, umid, name);
3467eebe8a9SJeff Dike if (n >= len) {
347ba180fd4SJeff Dike printk(UM_KERN_ERR "umid_file_name : buffer too short\n");
3487eebe8a9SJeff Dike return -E2BIG;
3492264c475SJeff Dike }
3502264c475SJeff Dike
3517eebe8a9SJeff Dike return 0;
3522264c475SJeff Dike }
3532264c475SJeff Dike
get_umid(void)3547eebe8a9SJeff Dike char *get_umid(void)
3552264c475SJeff Dike {
3562264c475SJeff Dike return umid;
3572264c475SJeff Dike }
3582264c475SJeff Dike
set_uml_dir(char * name,int * add)3592264c475SJeff Dike static int __init set_uml_dir(char *name, int *add)
3602264c475SJeff Dike {
3617eebe8a9SJeff Dike if (*name == '\0') {
3620936d4f3SMasami Hiramatsu os_warn("uml_dir can't be an empty string\n");
3637eebe8a9SJeff Dike return 0;
3647eebe8a9SJeff Dike }
3657eebe8a9SJeff Dike
3667eebe8a9SJeff Dike if (name[strlen(name) - 1] == '/') {
3677eebe8a9SJeff Dike uml_dir = name;
3687eebe8a9SJeff Dike return 0;
3697eebe8a9SJeff Dike }
3707eebe8a9SJeff Dike
3712264c475SJeff Dike uml_dir = malloc(strlen(name) + 2);
3722264c475SJeff Dike if (uml_dir == NULL) {
3730936d4f3SMasami Hiramatsu os_warn("Failed to malloc uml_dir - error = %d\n", errno);
3747eebe8a9SJeff Dike
375ba180fd4SJeff Dike /*
376ba180fd4SJeff Dike * Return 0 here because do_initcalls doesn't look at
3772264c475SJeff Dike * the return value.
3782264c475SJeff Dike */
3797eebe8a9SJeff Dike return 0;
3802264c475SJeff Dike }
3812264c475SJeff Dike sprintf(uml_dir, "%s/", name);
3827eebe8a9SJeff Dike
3837eebe8a9SJeff Dike return 0;
3842264c475SJeff Dike }
3852264c475SJeff Dike
3862264c475SJeff Dike __uml_setup("uml_dir=", set_uml_dir,
3872264c475SJeff Dike "uml_dir=<directory>\n"
3882264c475SJeff Dike " The location to place the pid and umid files.\n\n"
3892264c475SJeff Dike );
3902264c475SJeff Dike
remove_umid_dir(void)3912264c475SJeff Dike static void remove_umid_dir(void)
3922264c475SJeff Dike {
3930d4e5ac7SBartosz Golaszewski char *dir, err;
3940d4e5ac7SBartosz Golaszewski
3950d4e5ac7SBartosz Golaszewski dir = malloc(strlen(uml_dir) + UMID_LEN + 1);
3960d4e5ac7SBartosz Golaszewski if (!dir)
3970d4e5ac7SBartosz Golaszewski return;
3982264c475SJeff Dike
3992264c475SJeff Dike sprintf(dir, "%s%s", uml_dir, umid);
400eb28931eSPaolo 'Blaisorblade' Giarrusso err = remove_files_and_dir(dir);
4017eebe8a9SJeff Dike if (err)
4020936d4f3SMasami Hiramatsu os_warn("%s - remove_files_and_dir failed with err = %d\n",
4030936d4f3SMasami Hiramatsu __func__, err);
4040d4e5ac7SBartosz Golaszewski
4050d4e5ac7SBartosz Golaszewski free(dir);
4062264c475SJeff Dike }
4072264c475SJeff Dike
4082264c475SJeff Dike __uml_exitcall(remove_umid_dir);
409