]>
Commit | Line | Data |
---|---|---|
4fef0c10 | 1 | /* |
5134d8fe | 2 | * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) |
1da177e4 LT |
3 | * Licensed under the GPL |
4 | */ | |
5 | ||
6 | #include <stdio.h> | |
7 | #include <stdlib.h> | |
b2db2199 | 8 | #include <unistd.h> |
1da177e4 | 9 | #include <errno.h> |
5134d8fe | 10 | #include <signal.h> |
1da177e4 | 11 | #include <string.h> |
5134d8fe JD |
12 | #include <termios.h> |
13 | #include <wait.h> | |
14 | #include <sys/mman.h> | |
15 | #include <sys/utsname.h> | |
f7887ee1 | 16 | #include <init.h> |
37185b33 | 17 | #include <os.h> |
1da177e4 LT |
18 | |
19 | void stack_protections(unsigned long address) | |
20 | { | |
5134d8fe | 21 | if (mprotect((void *) address, UM_THREAD_SIZE, |
57598fd7 | 22 | PROT_READ | PROT_WRITE | PROT_EXEC) < 0) |
1da177e4 LT |
23 | panic("protecting stack failed, errno = %d", errno); |
24 | } | |
25 | ||
1da177e4 LT |
26 | int raw(int fd) |
27 | { | |
28 | struct termios tt; | |
29 | int err; | |
30 | ||
31 | CATCH_EINTR(err = tcgetattr(fd, &tt)); | |
5134d8fe | 32 | if (err < 0) |
b4fd310e | 33 | return -errno; |
1da177e4 LT |
34 | |
35 | cfmakeraw(&tt); | |
36 | ||
4fef0c10 | 37 | CATCH_EINTR(err = tcsetattr(fd, TCSADRAIN, &tt)); |
5134d8fe | 38 | if (err < 0) |
b4fd310e | 39 | return -errno; |
1da177e4 | 40 | |
5134d8fe JD |
41 | /* |
42 | * XXX tcsetattr could have applied only some changes | |
43 | * (and cfmakeraw() is a set of changes) | |
44 | */ | |
57598fd7 | 45 | return 0; |
1da177e4 LT |
46 | } |
47 | ||
48 | void setup_machinename(char *machine_out) | |
49 | { | |
50 | struct utsname host; | |
51 | ||
52 | uname(&host); | |
69fada32 PBG |
53 | #ifdef UML_CONFIG_UML_X86 |
54 | # ifndef UML_CONFIG_64BIT | |
8e5cb35a PBG |
55 | if (!strcmp(host.machine, "x86_64")) { |
56 | strcpy(machine_out, "i686"); | |
57 | return; | |
58 | } | |
69fada32 PBG |
59 | # else |
60 | if (!strcmp(host.machine, "i686")) { | |
61 | strcpy(machine_out, "x86_64"); | |
62 | return; | |
63 | } | |
64 | # endif | |
8e5cb35a | 65 | #endif |
1da177e4 LT |
66 | strcpy(machine_out, host.machine); |
67 | } | |
68 | ||
b4ffb6ad | 69 | void setup_hostinfo(char *buf, int len) |
1da177e4 LT |
70 | { |
71 | struct utsname host; | |
72 | ||
73 | uname(&host); | |
b4ffb6ad JD |
74 | snprintf(buf, len, "%s %s %s %s %s", host.sysname, host.nodename, |
75 | host.release, host.version, host.machine); | |
1da177e4 LT |
76 | } |
77 | ||
b2db2199 RW |
78 | /* |
79 | * We cannot use glibc's abort(). It makes use of tgkill() which | |
80 | * has no effect within UML's kernel threads. | |
81 | * After that glibc would execute an invalid instruction to kill | |
82 | * the calling process and UML crashes with SIGSEGV. | |
83 | */ | |
84 | static inline void __attribute__ ((noreturn)) uml_abort(void) | |
85 | { | |
86 | sigset_t sig; | |
87 | ||
88 | fflush(NULL); | |
89 | ||
90 | if (!sigemptyset(&sig) && !sigaddset(&sig, SIGABRT)) | |
91 | sigprocmask(SIG_UNBLOCK, &sig, 0); | |
92 | ||
93 | for (;;) | |
94 | if (kill(getpid(), SIGABRT) < 0) | |
95 | exit(127); | |
96 | } | |
97 | ||
91d44ff8 RW |
98 | /* |
99 | * UML helper threads must not handle SIGWINCH/INT/TERM | |
100 | */ | |
101 | void os_fix_helper_signals(void) | |
102 | { | |
103 | signal(SIGWINCH, SIG_IGN); | |
104 | signal(SIGINT, SIG_DFL); | |
105 | signal(SIGTERM, SIG_DFL); | |
106 | } | |
107 | ||
63843c26 JD |
108 | void os_dump_core(void) |
109 | { | |
a24864a1 LW |
110 | int pid; |
111 | ||
63843c26 | 112 | signal(SIGSEGV, SIG_DFL); |
a24864a1 LW |
113 | |
114 | /* | |
115 | * We are about to SIGTERM this entire process group to ensure that | |
116 | * nothing is around to run after the kernel exits. The | |
117 | * kernel wants to abort, not die through SIGTERM, so we | |
118 | * ignore it here. | |
119 | */ | |
120 | ||
121 | signal(SIGTERM, SIG_IGN); | |
122 | kill(0, SIGTERM); | |
123 | /* | |
124 | * Most of the other processes associated with this UML are | |
125 | * likely sTopped, so give them a SIGCONT so they see the | |
126 | * SIGTERM. | |
127 | */ | |
128 | kill(0, SIGCONT); | |
129 | ||
130 | /* | |
131 | * Now, having sent signals to everyone but us, make sure they | |
132 | * die by ptrace. Processes can survive what's been done to | |
133 | * them so far - the mechanism I understand is receiving a | |
134 | * SIGSEGV and segfaulting immediately upon return. There is | |
135 | * always a SIGSEGV pending, and (I'm guessing) signals are | |
136 | * processed in numeric order so the SIGTERM (signal 15 vs | |
137 | * SIGSEGV being signal 11) is never handled. | |
138 | * | |
139 | * Run a waitpid loop until we get some kind of error. | |
140 | * Hopefully, it's ECHILD, but there's not a lot we can do if | |
141 | * it's something else. Tell os_kill_ptraced_process not to | |
142 | * wait for the child to report its death because there's | |
143 | * nothing reasonable to do if that fails. | |
144 | */ | |
145 | ||
4dbed85a | 146 | while ((pid = waitpid(-1, NULL, WNOHANG | __WALL)) > 0) |
a24864a1 LW |
147 | os_kill_ptraced_process(pid, 0); |
148 | ||
b2db2199 | 149 | uml_abort(); |
63843c26 | 150 | } |
d634f194 RW |
151 | |
152 | void um_early_printk(const char *s, unsigned int n) | |
153 | { | |
154 | printf("%.*s", n, s); | |
155 | } | |
f7887ee1 MH |
156 | |
157 | static int quiet_info; | |
158 | ||
159 | static int __init quiet_cmd_param(char *str, int *add) | |
160 | { | |
161 | quiet_info = 1; | |
162 | return 0; | |
163 | } | |
164 | ||
165 | __uml_setup("quiet", quiet_cmd_param, | |
166 | "quiet\n" | |
167 | " Turns off information messages during boot.\n\n"); | |
168 | ||
169 | void os_info(const char *fmt, ...) | |
170 | { | |
171 | va_list list; | |
172 | ||
173 | if (quiet_info) | |
174 | return; | |
175 | ||
176 | va_start(list, fmt); | |
177 | vfprintf(stderr, fmt, list); | |
178 | va_end(list); | |
179 | } |