Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/um/os-Linux/helper.c
26424 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
4
*/
5
6
#include <stdlib.h>
7
#include <string.h>
8
#include <unistd.h>
9
#include <errno.h>
10
#include <sched.h>
11
#include <pthread.h>
12
#include <linux/limits.h>
13
#include <sys/socket.h>
14
#include <sys/wait.h>
15
#include <kern_util.h>
16
#include <os.h>
17
#include <um_malloc.h>
18
19
struct helper_data {
20
void (*pre_exec)(void*);
21
void *pre_data;
22
char **argv;
23
int fd;
24
char *buf;
25
};
26
27
static int helper_child(void *arg)
28
{
29
struct helper_data *data = arg;
30
char **argv = data->argv;
31
int err, ret;
32
33
if (data->pre_exec != NULL)
34
(*data->pre_exec)(data->pre_data);
35
err = execvp_noalloc(data->buf, argv[0], argv);
36
37
/* If the exec succeeds, we don't get here */
38
CATCH_EINTR(ret = write(data->fd, &err, sizeof(err)));
39
40
return 0;
41
}
42
43
/* Returns either the pid of the child process we run or -E* on failure. */
44
int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv)
45
{
46
struct helper_data data;
47
unsigned long stack, sp;
48
int pid, fds[2], ret, n;
49
50
stack = alloc_stack(0, __uml_cant_sleep());
51
if (stack == 0)
52
return -ENOMEM;
53
54
ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
55
if (ret < 0) {
56
ret = -errno;
57
printk(UM_KERN_ERR "run_helper : pipe failed, errno = %d\n",
58
errno);
59
goto out_free;
60
}
61
62
ret = os_set_exec_close(fds[1]);
63
if (ret < 0) {
64
printk(UM_KERN_ERR "run_helper : setting FD_CLOEXEC failed, "
65
"ret = %d\n", -ret);
66
goto out_close;
67
}
68
69
sp = stack + UM_KERN_PAGE_SIZE;
70
data.pre_exec = pre_exec;
71
data.pre_data = pre_data;
72
data.argv = argv;
73
data.fd = fds[1];
74
data.buf = __uml_cant_sleep() ? uml_kmalloc(PATH_MAX, UM_GFP_ATOMIC) :
75
uml_kmalloc(PATH_MAX, UM_GFP_KERNEL);
76
pid = clone(helper_child, (void *) sp, CLONE_VM, &data);
77
if (pid < 0) {
78
ret = -errno;
79
printk(UM_KERN_ERR "run_helper : clone failed, errno = %d\n",
80
errno);
81
goto out_free2;
82
}
83
84
close(fds[1]);
85
fds[1] = -1;
86
87
/*
88
* Read the errno value from the child, if the exec failed, or get 0 if
89
* the exec succeeded because the pipe fd was set as close-on-exec.
90
*/
91
n = read(fds[0], &ret, sizeof(ret));
92
if (n == 0) {
93
ret = pid;
94
} else {
95
if (n < 0) {
96
n = -errno;
97
printk(UM_KERN_ERR "run_helper : read on pipe failed, "
98
"ret = %d\n", -n);
99
ret = n;
100
}
101
CATCH_EINTR(waitpid(pid, NULL, __WALL));
102
}
103
104
if (ret < 0)
105
printk(UM_KERN_ERR "run_helper : failed to exec %s on host: %s\n",
106
argv[0], strerror(-ret));
107
108
out_free2:
109
kfree(data.buf);
110
out_close:
111
if (fds[1] != -1)
112
close(fds[1]);
113
close(fds[0]);
114
out_free:
115
free_stack(stack, 0);
116
return ret;
117
}
118
119
int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags,
120
unsigned long *stack_out)
121
{
122
unsigned long stack, sp;
123
int pid, status, err;
124
125
/* To share memory space, use os_run_helper_thread() instead. */
126
if (flags & CLONE_VM)
127
return -EINVAL;
128
129
stack = alloc_stack(0, __uml_cant_sleep());
130
if (stack == 0)
131
return -ENOMEM;
132
133
sp = stack + UM_KERN_PAGE_SIZE;
134
pid = clone(proc, (void *) sp, flags, arg);
135
if (pid < 0) {
136
err = -errno;
137
printk(UM_KERN_ERR "run_helper_thread : clone failed, "
138
"errno = %d\n", errno);
139
return err;
140
}
141
if (stack_out == NULL) {
142
CATCH_EINTR(pid = waitpid(pid, &status, __WALL));
143
if (pid < 0) {
144
err = -errno;
145
printk(UM_KERN_ERR "run_helper_thread - wait failed, "
146
"errno = %d\n", errno);
147
pid = err;
148
}
149
if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
150
printk(UM_KERN_ERR "run_helper_thread - thread "
151
"returned status 0x%x\n", status);
152
free_stack(stack, 0);
153
} else
154
*stack_out = stack;
155
return pid;
156
}
157
158
int helper_wait(int pid)
159
{
160
int ret, status;
161
int wflags = __WALL;
162
163
CATCH_EINTR(ret = waitpid(pid, &status, wflags));
164
if (ret < 0) {
165
printk(UM_KERN_ERR "helper_wait : waitpid process %d failed, "
166
"errno = %d\n", pid, errno);
167
return -errno;
168
} else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
169
printk(UM_KERN_ERR "helper_wait : process %d exited with "
170
"status 0x%x\n", pid, status);
171
return -ECHILD;
172
} else
173
return 0;
174
}
175
176
struct os_helper_thread {
177
pthread_t handle;
178
};
179
180
int os_run_helper_thread(struct os_helper_thread **td_out,
181
void *(*routine)(void *), void *arg)
182
{
183
struct os_helper_thread *td;
184
sigset_t sigset, oset;
185
int err, flags;
186
187
flags = __uml_cant_sleep() ? UM_GFP_ATOMIC : UM_GFP_KERNEL;
188
td = uml_kmalloc(sizeof(*td), flags);
189
if (!td)
190
return -ENOMEM;
191
192
sigfillset(&sigset);
193
if (sigprocmask(SIG_SETMASK, &sigset, &oset) < 0) {
194
err = -errno;
195
kfree(td);
196
return err;
197
}
198
199
err = pthread_create(&td->handle, NULL, routine, arg);
200
201
if (sigprocmask(SIG_SETMASK, &oset, NULL) < 0)
202
panic("Failed to restore the signal mask: %d", errno);
203
204
if (err != 0)
205
kfree(td);
206
else
207
*td_out = td;
208
209
return -err;
210
}
211
212
void os_kill_helper_thread(struct os_helper_thread *td)
213
{
214
pthread_cancel(td->handle);
215
pthread_join(td->handle, NULL);
216
kfree(td);
217
}
218
219
void os_fix_helper_thread_signals(void)
220
{
221
sigset_t sigset;
222
223
sigemptyset(&sigset);
224
225
sigaddset(&sigset, SIGWINCH);
226
sigaddset(&sigset, SIGPIPE);
227
sigaddset(&sigset, SIGPROF);
228
sigaddset(&sigset, SIGINT);
229
sigaddset(&sigset, SIGTERM);
230
sigaddset(&sigset, SIGCHLD);
231
sigaddset(&sigset, SIGALRM);
232
sigaddset(&sigset, SIGIO);
233
sigaddset(&sigset, SIGUSR1);
234
235
pthread_sigmask(SIG_SETMASK, &sigset, NULL);
236
}
237
238