Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/um/os-Linux/util.c
26424 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
4
*/
5
6
#include <stdarg.h>
7
#include <stdio.h>
8
#include <stdlib.h>
9
#include <unistd.h>
10
#include <errno.h>
11
#include <signal.h>
12
#include <string.h>
13
#include <termios.h>
14
#include <sys/wait.h>
15
#include <sys/mman.h>
16
#include <sys/utsname.h>
17
#include <sys/random.h>
18
#include <init.h>
19
#include <os.h>
20
21
void stack_protections(unsigned long address)
22
{
23
if (mprotect((void *) address, UM_THREAD_SIZE,
24
PROT_READ | PROT_WRITE | PROT_EXEC) < 0)
25
panic("protecting stack failed, errno = %d", errno);
26
}
27
28
int raw(int fd)
29
{
30
struct termios tt;
31
int err;
32
33
CATCH_EINTR(err = tcgetattr(fd, &tt));
34
if (err < 0)
35
return -errno;
36
37
cfmakeraw(&tt);
38
39
CATCH_EINTR(err = tcsetattr(fd, TCSADRAIN, &tt));
40
if (err < 0)
41
return -errno;
42
43
/*
44
* XXX tcsetattr could have applied only some changes
45
* (and cfmakeraw() is a set of changes)
46
*/
47
return 0;
48
}
49
50
void setup_machinename(char *machine_out)
51
{
52
struct utsname host;
53
54
uname(&host);
55
#if IS_ENABLED(CONFIG_UML_X86)
56
# if !IS_ENABLED(CONFIG_64BIT)
57
if (!strcmp(host.machine, "x86_64")) {
58
strcpy(machine_out, "i686");
59
return;
60
}
61
# else
62
if (!strcmp(host.machine, "i686")) {
63
strcpy(machine_out, "x86_64");
64
return;
65
}
66
# endif
67
#endif
68
strcpy(machine_out, host.machine);
69
}
70
71
void setup_hostinfo(char *buf, int len)
72
{
73
struct utsname host;
74
75
uname(&host);
76
snprintf(buf, len, "%s %s %s %s %s", host.sysname, host.nodename,
77
host.release, host.version, host.machine);
78
}
79
80
/*
81
* We cannot use glibc's abort(). It makes use of tgkill() which
82
* has no effect within UML's kernel threads.
83
* After that glibc would execute an invalid instruction to kill
84
* the calling process and UML crashes with SIGSEGV.
85
*/
86
static inline void __attribute__ ((noreturn)) uml_abort(void)
87
{
88
sigset_t sig;
89
90
fflush(NULL);
91
92
if (!sigemptyset(&sig) && !sigaddset(&sig, SIGABRT))
93
sigprocmask(SIG_UNBLOCK, &sig, 0);
94
95
for (;;)
96
if (kill(getpid(), SIGABRT) < 0)
97
exit(127);
98
}
99
100
ssize_t os_getrandom(void *buf, size_t len, unsigned int flags)
101
{
102
return getrandom(buf, len, flags);
103
}
104
105
/*
106
* UML helper threads must not handle SIGWINCH/INT/TERM
107
*/
108
void os_fix_helper_signals(void)
109
{
110
signal(SIGWINCH, SIG_IGN);
111
signal(SIGINT, SIG_DFL);
112
signal(SIGTERM, SIG_DFL);
113
}
114
115
void os_dump_core(void)
116
{
117
int pid;
118
119
signal(SIGSEGV, SIG_DFL);
120
121
/*
122
* We are about to SIGTERM this entire process group to ensure that
123
* nothing is around to run after the kernel exits. The
124
* kernel wants to abort, not die through SIGTERM, so we
125
* ignore it here.
126
*/
127
128
signal(SIGTERM, SIG_IGN);
129
kill(0, SIGTERM);
130
/*
131
* Most of the other processes associated with this UML are
132
* likely sTopped, so give them a SIGCONT so they see the
133
* SIGTERM.
134
*/
135
kill(0, SIGCONT);
136
137
/*
138
* Now, having sent signals to everyone but us, make sure they
139
* die by ptrace. Processes can survive what's been done to
140
* them so far - the mechanism I understand is receiving a
141
* SIGSEGV and segfaulting immediately upon return. There is
142
* always a SIGSEGV pending, and (I'm guessing) signals are
143
* processed in numeric order so the SIGTERM (signal 15 vs
144
* SIGSEGV being signal 11) is never handled.
145
*
146
* Run a waitpid loop until we get some kind of error.
147
* Hopefully, it's ECHILD, but there's not a lot we can do if
148
* it's something else. Tell os_kill_ptraced_process not to
149
* wait for the child to report its death because there's
150
* nothing reasonable to do if that fails.
151
*/
152
153
while ((pid = waitpid(-1, NULL, WNOHANG | __WALL)) > 0)
154
os_kill_ptraced_process(pid, 0);
155
156
uml_abort();
157
}
158
159
void um_early_printk(const char *s, unsigned int n)
160
{
161
printf("%.*s", n, s);
162
}
163
164
static int quiet_info;
165
166
static int __init quiet_cmd_param(char *str, int *add)
167
{
168
quiet_info = 1;
169
return 0;
170
}
171
172
__uml_setup("quiet", quiet_cmd_param,
173
"quiet\n"
174
" Turns off information messages during boot.\n\n");
175
176
/*
177
* The os_info/os_warn functions will be called by helper threads. These
178
* have a very limited stack size and using the libc formatting functions
179
* may overflow the stack.
180
* So pull in the kernel vscnprintf and use that instead with a fixed
181
* on-stack buffer.
182
*/
183
int vscnprintf(char *buf, size_t size, const char *fmt, va_list args);
184
185
void os_info(const char *fmt, ...)
186
{
187
char buf[256];
188
va_list list;
189
int len;
190
191
if (quiet_info)
192
return;
193
194
va_start(list, fmt);
195
len = vscnprintf(buf, sizeof(buf), fmt, list);
196
fwrite(buf, len, 1, stderr);
197
va_end(list);
198
}
199
200
void os_warn(const char *fmt, ...)
201
{
202
char buf[256];
203
va_list list;
204
int len;
205
206
va_start(list, fmt);
207
len = vscnprintf(buf, sizeof(buf), fmt, list);
208
fwrite(buf, len, 1, stderr);
209
va_end(list);
210
}
211
212