forked from holzschu/ios_system
-
Notifications
You must be signed in to change notification settings - Fork 0
/
libc_replacement.c
292 lines (264 loc) · 9.15 KB
/
libc_replacement.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
//
// libc_replacement.c
// ios_system
//
// Created by Nicolas Holzschuch on 30/04/2018.
// Copyright © 2018 Nicolas Holzschuch. All rights reserved.
//
#include <stdio.h>
#include <wchar.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/wait.h>
#include "ios_error.h"
#undef write
#undef fwrite
#undef puts
#undef fputs
#undef fputc
#undef putw
#undef fflush
int printf (const char *format, ...) {
va_list arg;
int done;
va_start (arg, format);
done = vfprintf (thread_stdout, format, arg);
va_end (arg);
return done;
}
int fprintf(FILE * restrict stream, const char * restrict format, ...) {
va_list arg;
int done;
if (thread_stderr == NULL) thread_stderr = stderr;
if (thread_stdout == NULL) thread_stdout = stdout;
va_start (arg, format);
if (fileno(stream) == STDOUT_FILENO) done = vfprintf (thread_stdout, format, arg);
else if (fileno(stream) == STDERR_FILENO) done = vfprintf (stderr, format, arg);
else done = vfprintf (stream, format, arg);
va_end (arg);
return done;
}
int scanf (const char *format, ...) {
int count;
va_list ap;
if (thread_stderr == NULL) thread_stderr = stderr;
if (thread_stdout == NULL) thread_stdout = stdout;
if (thread_stdin == NULL) thread_stdin = stdin;
fflush(thread_stdout);
fflush(thread_stderr);
va_start (ap, format);
count = vfscanf (thread_stdin, format, ap);
va_end (ap);
return (count);
}
int ios_fflush(FILE *stream) {
if (thread_stdout == NULL) thread_stdout = stdout;
if (thread_stderr == NULL) thread_stderr = stderr;
if (fileno(stream) == STDOUT_FILENO) return fflush(thread_stdout);
if (fileno(stream) == STDERR_FILENO) return fflush(thread_stderr);
return fflush(stream);
}
ssize_t ios_write(int fildes, const void *buf, size_t nbyte) {
if (thread_stdout == NULL) thread_stdout = stdout;
if (thread_stderr == NULL) thread_stderr = stderr;
if (fildes == STDOUT_FILENO) return write(fileno(thread_stdout), buf, nbyte);
if (fildes == STDERR_FILENO) return write(fileno(thread_stderr), buf, nbyte);
return write(fildes, buf, nbyte);
}
size_t ios_fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream) {
if (thread_stdout == NULL) thread_stdout = stdout;
if (thread_stderr == NULL) thread_stderr = stderr;
if (fileno(stream) == STDOUT_FILENO) return fwrite(ptr, size, nitems, thread_stdout);
if (fileno(stream) == STDERR_FILENO) return fwrite(ptr, size, nitems, thread_stderr);
return fwrite(ptr, size, nitems, stream);
}
int ios_puts(const char *s) {
if (thread_stdout == NULL) thread_stdout = stdout;
// puts adds a newline at the end.
int returnValue = fputs(s, thread_stdout);
fputc('\n', thread_stdout);
return returnValue;
}
int ios_fputs(const char* s, FILE *stream) {
if (thread_stdout == NULL) thread_stdout = stdout;
if (thread_stderr == NULL) thread_stderr = stderr;
if (fileno(stream) == STDOUT_FILENO) return fputs(s, thread_stdout);
if (fileno(stream) == STDERR_FILENO) return fputs(s, thread_stderr);
return fputs(s, stream);
}
int ios_fputc(int c, FILE *stream) {
if (thread_stdout == NULL) thread_stdout = stdout;
if (thread_stderr == NULL) thread_stderr = stderr;
if (fileno(stream) == STDOUT_FILENO) return fputc(c, thread_stdout);
if (fileno(stream) == STDERR_FILENO) return fputc(c, thread_stderr);
return fputc(c, stream);
}
#include <assert.h>
int ios_putw(int w, FILE *stream) {
if (thread_stdout == NULL) thread_stdout = stdout;
if (thread_stderr == NULL) thread_stderr = stderr;
if (fileno(stream) == STDOUT_FILENO) return putw(w, thread_stdout);
if (fileno(stream) == STDERR_FILENO) return putw(w, thread_stderr);
return putw(w, stream);
}
// Fake process IDs to go with fake forking:
// You will still need to edit your code to make sure you go through both branches.
#define IOS_MAX_THREADS 128
static pthread_t thread_ids[IOS_MAX_THREADS];
static int pid_overflow = 0;
static pid_t current_pid = 0;
inline pthread_t ios_getThreadId(pid_t pid) {
// return ios_getLastThreadId(); // previous behaviour
return thread_ids[pid];
}
// We do not recycle process ids too quickly to avoid collisions.
static inline const pid_t ios_nextAvailablePid() {
if (!pid_overflow && (current_pid < IOS_MAX_THREADS - 1)) {
current_pid += 1;
thread_ids[current_pid] = 0;
return current_pid;
}
// We've already started more than IOS_MAX_THREADS threads.
if (!pid_overflow) current_pid = 0; // first time over the limit
pid_overflow = 1;
while (1) {
current_pid += 1;
if (current_pid >= IOS_MAX_THREADS) current_pid = 1;
pthread_t thread_pid = ios_getThreadId(current_pid);
if (thread_pid == 0) {
return current_pid; // already released
}
// Dangerous: if the process is already killed, this wil crash
/*
if (pthread_kill(thread_pid, 0) != 0) {
thread_ids[current_pid] = 0;
return current_pid; // not running anymore
}
*/
}
}
inline void ios_storeThreadId(pthread_t thread) {
// To avoid issues when a command starts a command without forking,
// we only store thread IDs for the first thread of the "process".
if (thread_ids[current_pid] == 0) {
thread_ids[current_pid] = thread;
return;
}
if (pthread_kill(ios_getThreadId(current_pid), 0) != 0) thread_ids[current_pid] = thread;
}
void ios_releaseThread(pthread_t thread) {
// TODO: this is inefficient. Replace with NSMutableArray?
for (int p = 0; p < IOS_MAX_THREADS; p++) {
if (thread_ids[p] == thread) {
thread_ids[p] = 0;
return;
}
}
}
void ios_releaseThreadId(pid_t pid) {
thread_ids[pid] = 0;
}
pid_t ios_currentPid() {
return current_pid;
}
pid_t fork(void) { return ios_nextAvailablePid(); } // increases current_pid by 1.
pid_t ios_fork(void) { return ios_nextAvailablePid(); } // increases current_pid by 1.
pid_t vfork(void) { return ios_nextAvailablePid(); }
// simple replacement of waitpid for swift programs
// We use "optnone" to prevent optimization, otherwise the while loops never end.
__attribute__ ((optnone)) void ios_waitpid(pid_t pid) {
pthread_t threadToWaitFor;
// Old system: no explicit pid, just store last thread Id.
if ((pid == -1) || (pid == 0)) {
threadToWaitFor = ios_getLastThreadId();
while (threadToWaitFor != 0) {
threadToWaitFor = ios_getLastThreadId();
}
return;
}
// New system: thread Id is store with pid:
threadToWaitFor = ios_getThreadId(pid);
while (threadToWaitFor != 0) {
threadToWaitFor = ios_getThreadId(pid);
}
return;
}
__attribute__ ((optnone)) pid_t waitpid(pid_t pid, int *stat_loc, int options) {
// pthread_join won't work, because the thread might have been detached.
// (and you can't re-join a detached thread).
// -1 = the call waits for any child process
// 0 = the call waits for any child process in the process group of the caller
if (options && WNOHANG) {
// WNOHANG: just check that the process is still running:
pthread_t threadToWaitFor;
if ((pid == -1) || (pid == 0)) threadToWaitFor = ios_getLastThreadId();
else threadToWaitFor = ios_getThreadId(pid);
if (threadToWaitFor != 0) // the process is still running
return 0;
else {
if (stat_loc) *stat_loc = W_EXITCODE(ios_getCommandStatus(), 0);
fflush(thread_stdout);
fflush(thread_stderr);
return -1;
}
} else {
// Wait until the process is terminated:
ios_waitpid(pid);
if (stat_loc) *stat_loc = W_EXITCODE(ios_getCommandStatus(), 0);
return pid;
}
}
//
void vwarn(const char *fmt, va_list args)
{
if (thread_stderr == NULL) thread_stderr = stderr;
fputs(ios_progname(), thread_stderr);
if (fmt != NULL)
{
fputs(": ", thread_stderr);
vfprintf(thread_stderr, fmt, args);
}
fputs(": ", thread_stderr);
fputs(strerror(errno), thread_stderr);
putc('\n', thread_stderr);
}
void vwarnx(const char *fmt, va_list args)
{
if (thread_stderr == NULL) thread_stderr = stderr;
fputs(ios_progname(), thread_stderr);
fputs(": ", thread_stderr);
if (fmt != NULL)
vfprintf(thread_stderr, fmt, args);
putc('\n', thread_stderr);
}
// void err(int eval, const char *fmt, ...);
void err(int eval, const char *fmt, ...) {
va_list argptr;
va_start(argptr, fmt);
vwarn(fmt, argptr);
va_end(argptr);
ios_exit(eval);
}
// void errx(int eval, const char *fmt, ...);
void errx(int eval, const char *fmt, ...) {
va_list argptr;
va_start(argptr, fmt);
vwarnx(fmt, argptr);
va_end(argptr);
ios_exit(eval);
}
// void warn(const char *fmt, ...);
void warn(const char *fmt, ...) {
va_list argptr;
va_start(argptr, fmt);
vwarn(fmt, argptr);
va_end(argptr);
}
// void warnx(const char *fmt, ...);
void warnx(const char *fmt, ...) {
va_list argptr;
va_start(argptr, fmt);
vwarnx(fmt, argptr);
va_end(argptr);
}