Description:
[grader] obsolete new_problem, fixed memory measurement bug in box.cc git-svn-id: http://theory.cpe.ku.ac.th/grader/judge/trunk/scripts@186 6386c4cd-e34a-4fa8-8920-d93eb39b512e
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r49:5746784ead66 - - 2 files changed: 11 inserted, 2 deleted

@@ -1,68 +1,73
1 1 #!/usr/bin/ruby
2 2
3 3 # new_problem:
4 4 # * creates a directory for a problem in the current directory,
5 5 # * create standard testcase config file
6 6
7 7 require 'erb'
8 8
9 9 def process_options(options)
10 10 i = 2
11 11 while i<ARGV.length
12 12 if ARGV[i]=='-t'
13 13 options[:time_limit] = ARGV[i+1].to_i if ARGV.length>i+1
14 14 i += 1
15 15 end
16 16 if ARGV[i]=='-m'
17 17 options[:mem_limit] = ARGV[i+1].to_i if ARGV.length>i+1
18 18 i += 1
19 19 end
20 20 i += 1
21 21 end
22 22 end
23 23
24 +
25 + puts "This script is out of dated, shall be fixed soon"
26 + puts "Right now, you can create raw_ev and import"
27 + exit(0)
28 +
24 29 GRADER_DIR = File.dirname(__FILE__)
25 30
26 31 # print usage
27 32 if ARGV.length < 2
28 33 puts <<USAGE
29 34 using: new_problem problem number_of_testcase [options]
30 35 * creates a directory for a problem in the current directory,
31 36 * create standard testcase config file
32 37 * options: -t time-limit (in seconds)
33 38 -m mem-limit (in MB)
34 39 USAGE
35 40 exit(127)
36 41 end
37 42
38 43 # processing arguments
39 44 problem = ARGV[0]
40 45 num_testcases = ARGV[1].to_i
41 46
42 47 options = {:time_limit => 1, :mem_limit => 16}
43 48 process_options(options)
44 49
45 50 # start working
46 51 puts "creating directories"
47 52
48 53 system("mkdir #{problem}")
49 54 system("mkdir #{problem}/script")
50 55 system("mkdir #{problem}/test_cases")
51 56
52 57 puts "creating testcases directories"
53 58
54 59 1.upto(num_testcases) do |i|
55 60 system("mkdir #{problem}/test_cases/#{i}")
56 61 end
57 62
58 63 # generating all_tests.cfg
59 64 puts "generating testcase config file"
60 65
61 - template = File.open(File.dirname(__FILE__) + "/all_tests.cfg.erb").read
66 + template = File.open(File.dirname(__FILE__) + "/templates/all_tests.cfg.erb").read
62 67 all_test_cfg = ERB.new(template)
63 68
64 69 cfg_file = File.open("#{problem}/test_cases/all_tests.cfg","w")
65 70 cfg_file.puts all_test_cfg.result
66 71 cfg_file.close
67 72
68 73 puts "done"
@@ -1,598 +1,602
1 1 /*
2 2 * A Simple Testing Sandbox
3 3 *
4 4 * (c) 2001--2004 Martin Mares <mj@ucw.cz>
5 5 */
6 6
7 7 #define _LARGEFILE64_SOURCE
8 8 //#define _GNU_SOURCE
9 9
10 10 #include <errno.h>
11 11 #include <stdio.h>
12 12 #include <fcntl.h>
13 13 #include <stdlib.h>
14 14 #include <string.h>
15 15 #include <stdarg.h>
16 16 #include <unistd.h>
17 17 #include <getopt.h>
18 18 #include <time.h>
19 19 #include <sys/wait.h>
20 20 #include <sys/user.h>
21 21 #include <sys/time.h>
22 22 #include <sys/ptrace.h>
23 23 #include <sys/signal.h>
24 24 #include <sys/sysinfo.h>
25 25 #include <sys/syscall.h>
26 26 #include <sys/resource.h>
27 27
28 28 #define NONRET __attribute__((noreturn))
29 29 #define UNUSED __attribute__((unused))
30 30
31 31 static int filter_syscalls; /* 0=off, 1=liberal, 2=totalitarian */
32 32 static int timeout;
33 33 static int pass_environ;
34 34 static int use_wall_clock;
35 35 static int file_access;
36 36 static int verbose;
37 37 static int memory_limit;
38 38 static int allow_times;
39 39 static char *redir_stdin, *redir_stdout;
40 40 static char *set_cwd;
41 41
42 42 static pid_t box_pid;
43 43 static int is_ptraced;
44 44 static volatile int timer_tick;
45 45 static time_t start_time;
46 46 static int ticks_per_sec;
47 + static int page_size;
47 48
48 49 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ > 0
49 50 /* glibc 2.1 or newer -> has lseek64 */
50 51 #define long_seek(f,o,w) lseek64(f,o,w)
51 52 #else
52 53 /* Touching clandestine places in glibc */
53 54 extern loff_t llseek(int fd, loff_t pos, int whence);
54 55 #define long_seek(f,o,w) llseek(f,o,w)
55 56 #endif
56 57
57 58 int max_mem_used = 0;
58 59
59 60 void print_running_stat(double wall_time,
60 61 double user_time,
61 62 double system_time,
62 63 int mem_usage)
63 64 {
64 65 fprintf(stderr,"%.4lfr%.4lfu%.4lfs%dm\n",
65 66 wall_time, user_time, system_time, mem_usage);
66 67 }
67 68
68 69 static void NONRET
69 70 box_exit(void)
70 71 {
71 72 if (box_pid > 0) {
72 73 if (is_ptraced)
73 74 ptrace(PTRACE_KILL, box_pid);
74 75 kill(-box_pid, SIGKILL);
75 76 kill(box_pid, SIGKILL);
76 77 }
77 78
78 79 struct timeval total;
79 80 int wall;
80 81 struct rusage rus;
81 82 int stat;
82 83 pid_t p;
83 84
84 85 // wait so that we can get information
85 86 p = wait4(box_pid, &stat, WUNTRACED, &rus);
86 87 if (p < 0) {
87 88 fprintf(stderr,"wait4: error\n");
88 89 print_running_stat(0,0,0,max_mem_used);
89 90 } else if (p != box_pid) {
90 91 fprintf(stderr,"wait4: unknown pid %d exited!\n", p);
91 92 print_running_stat(0,0,0,max_mem_used);
92 93 } else {
93 94 if (!WIFEXITED(stat))
94 95 fprintf(stderr,"wait4: unknown status\n");
95 96 struct timeval total;
96 97 int wall;
97 98 wall = time(NULL) - start_time;
98 99 timeradd(&rus.ru_utime, &rus.ru_stime, &total);
99 100
100 101 print_running_stat((double)wall,
101 102 (double) rus.ru_utime.tv_sec +
102 103 ((double) rus.ru_utime.tv_usec/1000000.0),
103 104 (double) rus.ru_stime.tv_sec +
104 105 ((double) rus.ru_stime.tv_usec/1000000.0),
105 106 max_mem_used);
106 107 }
107 108 exit(1);
108 109 }
109 110
110 111 static void NONRET __attribute__((format(printf,1,2)))
111 112 die(char *msg, ...)
112 113 {
113 114 va_list args;
114 115 va_start(args, msg);
115 116 vfprintf(stderr, msg, args);
116 117 fputc('\n', stderr);
117 118 box_exit();
118 119 }
119 120
120 121 static void __attribute__((format(printf,1,2)))
121 122 log(char *msg, ...)
122 123 {
123 124 va_list args;
124 125 va_start(args, msg);
125 126 if (verbose)
126 127 {
127 128 vfprintf(stderr, msg, args);
128 129 fflush(stderr);
129 130 }
130 131 va_end(args);
131 132 }
132 133
133 134 static void
134 135 valid_filename(unsigned long addr)
135 136 {
136 137 char namebuf[4096], *p, *end;
137 138 static int mem_fd;
138 139
139 140 if (!file_access)
140 141 die("File access forbidden.");
141 142 if (file_access >= 9)
142 143 return;
143 144
144 145 if (!mem_fd)
145 146 {
146 147 sprintf(namebuf, "/proc/%d/mem", (int) box_pid);
147 148 mem_fd = open(namebuf, O_RDONLY);
148 149 if (mem_fd < 0)
149 150 die("open(%s): %m", namebuf);
150 151 }
151 152 p = end = namebuf;
152 153 do
153 154 {
154 155 if (p >= end)
155 156 {
156 157 int remains = PAGE_SIZE - (addr & (PAGE_SIZE-1));
157 158 int l = namebuf + sizeof(namebuf) - end;
158 159 if (l > remains)
159 160 l = remains;
160 161 if (!l)
161 162 die("Access to file with name too long.");
162 163 if (long_seek(mem_fd, addr, SEEK_SET) < 0)
163 164 die("long_seek(mem): %m");
164 165 remains = read(mem_fd, end, l);
165 166 if (remains < 0)
166 167 die("read(mem): %m");
167 168 if (!remains)
168 169 die("Access to file with name out of memory.");
169 170 end += l;
170 171 addr += l;
171 172 }
172 173 }
173 174 while (*p++);
174 175
175 176 log("[%s] ", namebuf);
176 177 if (file_access >= 3)
177 178 return;
178 179 if (!strchr(namebuf, '/') && strcmp(namebuf, ".."))
179 180 return;
180 181 if (file_access >= 2)
181 182 {
182 183 if ((!strncmp(namebuf, "/etc/", 5) ||
183 184 !strncmp(namebuf, "/lib/", 5) ||
184 185 !strncmp(namebuf, "/usr/lib/", 9))
185 186 && !strstr(namebuf, ".."))
186 187 return;
187 188 if (!strcmp(namebuf, "/dev/null") ||
188 189 !strcmp(namebuf, "/dev/zero") ||
189 190 !strcmp(namebuf, "/proc/meminfo") ||
190 191 !strcmp(namebuf, "/proc/self/stat") ||
191 192 !strncmp(namebuf, "/usr/share/zoneinfo/", 20))
192 193 return;
193 194 }
194 195 die("Forbidden access to file `%s'.", namebuf);
195 196 }
196 197
197 198 static int
198 199 valid_syscall(struct user *u)
199 200 {
200 201 switch (u->regs.orig_eax)
201 202 {
202 203 case __NR_execve:
203 204 {
204 205 static int exec_counter;
205 206 return !exec_counter++;
206 207 }
207 208 case __NR_open:
208 209 case __NR_creat:
209 210 case __NR_unlink:
210 211 case __NR_oldstat:
211 212 case __NR_access:
212 213 case __NR_oldlstat:
213 214 case __NR_truncate:
214 215 case __NR_stat:
215 216 case __NR_lstat:
216 217 case __NR_truncate64:
217 218 case __NR_stat64:
218 219 case __NR_lstat64:
219 220 valid_filename(u->regs.ebx);
220 221 return 1;
221 222 case __NR_exit:
222 223 case __NR_read:
223 224 case __NR_write:
224 225 case __NR_close:
225 226 case __NR_lseek:
226 227 case __NR_getpid:
227 228 case __NR_getuid:
228 229 case __NR_oldfstat:
229 230 case __NR_dup:
230 231 case __NR_brk:
231 232 case __NR_getgid:
232 233 case __NR_geteuid:
233 234 case __NR_getegid:
234 235 case __NR_dup2:
235 236 case __NR_ftruncate:
236 237 case __NR_fstat:
237 238 case __NR_personality:
238 239 case __NR__llseek:
239 240 case __NR_readv:
240 241 case __NR_writev:
241 242 case __NR_getresuid:
242 243 #ifdef __NR_pread64
243 244 case __NR_pread64:
244 245 case __NR_pwrite64:
245 246 #else
246 247 case __NR_pread:
247 248 case __NR_pwrite:
248 249 #endif
249 250 case __NR_ftruncate64:
250 251 case __NR_fstat64:
251 252 case __NR_fcntl:
252 253 case __NR_fcntl64:
253 254 case __NR_mmap:
254 255 case __NR_munmap:
255 256 case __NR_ioctl:
256 257 case __NR_uname:
257 258 case 252:
258 259 case 243:
259 260 return 1;
260 261 // case __NR_time:
261 262 case __NR_alarm:
262 263 // case __NR_pause:
263 264 case __NR_signal:
264 265 case __NR_fchmod:
265 266 case __NR_sigaction:
266 267 case __NR_sgetmask:
267 268 case __NR_ssetmask:
268 269 case __NR_sigsuspend:
269 270 case __NR_sigpending:
270 271 case __NR_getrlimit:
271 272 case __NR_getrusage:
272 273 case __NR_gettimeofday:
273 274 case __NR_select:
274 275 case __NR_readdir:
275 276 case __NR_setitimer:
276 277 case __NR_getitimer:
277 278 case __NR_sigreturn:
278 279 case __NR_mprotect:
279 280 case __NR_sigprocmask:
280 281 case __NR_getdents:
281 282 case __NR_getdents64:
282 283 case __NR__newselect:
283 284 case __NR_fdatasync:
284 285 case __NR_mremap:
285 286 case __NR_poll:
286 287 case __NR_getcwd:
287 288 case __NR_nanosleep:
288 289 case __NR_rt_sigreturn:
289 290 case __NR_rt_sigaction:
290 291 case __NR_rt_sigprocmask:
291 292 case __NR_rt_sigpending:
292 293 case __NR_rt_sigtimedwait:
293 294 case __NR_rt_sigqueueinfo:
294 295 case __NR_rt_sigsuspend:
295 296 case __NR_mmap2:
296 297 case __NR__sysctl:
297 298 return (filter_syscalls == 1);
298 299 case __NR_times:
299 300 return allow_times;
300 301 case __NR_kill:
301 302 if (u->regs.ebx == box_pid)
302 303 die("Commited suicide by signal %d.", (int)u->regs.ecx);
303 304 return 0;
304 305 default:
305 306 return 0;
306 307 }
307 308 }
308 309
309 310 static void
310 311 signal_alarm(int unused UNUSED)
311 312 {
312 313 /* Time limit checks are synchronous, so we only schedule them there. */
313 314 timer_tick = 1;
314 315
315 316 //NOTE: do not use alarm, changed to setitimer for precision
316 317 // alarm(1);
317 318 }
318 319
319 320 static void
320 321 signal_int(int unused UNUSED)
321 322 {
322 323 /* Interrupts are fatal, so no synchronization requirements. */
323 324 die("Interrupted.");
324 325 }
325 326
326 327 static void
327 328 check_timeout(void)
328 329 {
329 330 int sec;
330 331
331 332 if (use_wall_clock)
332 333 sec = time(NULL) - start_time;
333 334 else
334 335 {
335 336 char buf[4096], *x;
336 337 int c, utime, stime;
337 338 static int proc_status_fd;
338 339 if (!proc_status_fd)
339 340 {
340 341 sprintf(buf, "/proc/%d/stat", (int) box_pid);
341 342 proc_status_fd = open(buf, O_RDONLY);
342 343 if (proc_status_fd < 0)
343 344 die("open(%s): %m", buf);
344 345 }
345 346 lseek(proc_status_fd, 0, SEEK_SET);
346 347 if ((c = read(proc_status_fd, buf, sizeof(buf)-1)) < 0)
347 348 die("read on /proc/$pid/stat: %m");
348 349 if (c >= (int) sizeof(buf) - 1)
349 350 die("/proc/$pid/stat too long");
350 351 buf[c] = 0;
351 352 x = buf;
352 353 while (*x && *x != ' ')
353 354 x++;
354 355 while (*x == ' ')
355 356 x++;
356 357 if (*x++ != '(')
357 358 die("proc syntax error 1");
358 359 while (*x && (*x != ')' || x[1] != ' '))
359 360 x++;
360 361 while (*x == ')' || *x == ' ')
361 362 x++;
362 363 if (sscanf(x, "%*c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %d %d", &utime, &stime) != 2)
363 364 die("proc syntax error 2");
364 365 //printf("%s - %d\n",x,ticks_per_sec);
365 366 sec = (utime + stime + ticks_per_sec-1)/ticks_per_sec;
366 367 }
367 368 if (verbose > 1)
368 369 fprintf(stderr, "[timecheck: %d seconds]\n", sec);
369 370 if (sec > timeout) {
370 371 die("Time limit exceeded.");
371 372 }
372 373 }
373 374
374 375 static void
375 376 check_memory_usage()
376 377 {
377 378 char proc_fname[100];
378 379 sprintf(proc_fname,"/proc/%d/statm",box_pid);
379 380 //printf("proc fname: %s\n",proc_fname);
380 381 FILE *fp = fopen(proc_fname,"r");
381 382 if(fp!=NULL) {
382 383 char line[1000];
383 384 fgets(line,999,fp);
384 385 //printf("%s\n",line);
385 386 int m;
386 387
387 - if(sscanf(line,"%d",&m)==1)
388 + if(sscanf(line,"%d",&m)==1) {
389 + m = (m*page_size+1023)/1024;
388 390 if(m>max_mem_used)
389 391 max_mem_used = m;
392 + }
390 393
391 394 fclose(fp);
392 395 }
393 396 }
394 397
395 398 static void
396 399 boxkeeper(void)
397 400 {
398 401 int syscall_count = 0;
399 402 struct sigaction sa;
400 403
401 404 is_ptraced = 1;
402 405 bzero(&sa, sizeof(sa));
403 406 sa.sa_handler = signal_int;
404 407 sigaction(SIGINT, &sa, NULL);
405 408 start_time = time(NULL);
406 409 ticks_per_sec = sysconf(_SC_CLK_TCK);
410 + page_size = getpagesize();
407 411 if (ticks_per_sec <= 0)
408 412 die("Invalid ticks_per_sec!");
409 413
410 414 check_memory_usage();
411 415
412 416 sa.sa_handler = signal_alarm;
413 417 sigaction(SIGALRM, &sa, NULL);
414 418 //alarm(1);
415 419
416 420 struct itimerval val;
417 421 val.it_interval.tv_sec = 0;
418 422 val.it_interval.tv_usec = 50000;
419 423 val.it_value.tv_sec = 0;
420 424 val.it_value.tv_usec = 50000;
421 425 setitimer(ITIMER_REAL,&val,NULL);
422 426
423 427 /*
424 428 --- add alarm handler no matter what..
425 429 if (timeout)
426 430 {
427 431 sa.sa_handler = signal_alarm;
428 432 sigaction(SIGALRM, &sa, NULL);
429 433 alarm(1);
430 434 }
431 435 */
432 436
433 437 for(;;)
434 438 {
435 439 struct rusage rus;
436 440 int stat;
437 441 pid_t p;
438 442
439 443 if (timer_tick)
440 444 {
441 445 check_timeout();
442 446 check_memory_usage();
443 447 timer_tick = 0;
444 448 }
445 449 p = wait4(box_pid, &stat, WUNTRACED, &rus);
446 450
447 451 if (p < 0)
448 452 {
449 453 if (errno == EINTR)
450 454 continue;
451 455 die("wait4: %m");
452 456 }
453 457 if (p != box_pid)
454 458 die("wait4: unknown pid %d exited!", p);
455 459 if (WIFEXITED(stat))
456 460 {
457 461 struct timeval total;
458 462 int wall;
459 463 wall = time(NULL) - start_time;
460 464 timeradd(&rus.ru_utime, &rus.ru_stime, &total);
461 465
462 466 box_pid = 0;
463 467 if (WEXITSTATUS(stat))
464 468 fprintf(stderr,"Exited with error status %d.\n", WEXITSTATUS(stat));
465 469 else if ((use_wall_clock ? wall : total.tv_sec) > timeout)
466 470 fprintf(stderr,"Time limit exceeded.\n");
467 471 else
468 472 // report OK and statistics
469 473 fprintf(stderr,"OK\n");
470 474
471 475 print_running_stat((double) wall,
472 476 (double) rus.ru_utime.tv_sec +
473 477 ((double) rus.ru_utime.tv_usec/1000000.0),
474 478 (double) rus.ru_stime.tv_sec +
475 479 ((double) rus.ru_stime.tv_usec/1000000.0),
476 480 max_mem_used);
477 481 /*
478 482 (%.4lf sec real (%d), %d sec wall, %d syscalls, %d kb)\n",
479 483 (double) total.tv_sec + ((double)total.tv_usec / 1000000.0),
480 484 (int) total.tv_usec,
481 485 wall,
482 486 syscall_count,
483 487 max_mem_used);
484 488 */
485 489 exit(0);
486 490 }
487 491 if (WIFSIGNALED(stat))
488 492 {
489 493 box_pid = 0;
490 494 fprintf(stderr,"Caught fatal signal %d.\n", WTERMSIG(stat));
491 495
492 496 struct timeval total;
493 497 int wall;
494 498 wall = time(NULL) - start_time;
495 499 timeradd(&rus.ru_utime, &rus.ru_stime, &total);
496 500 print_running_stat((double) wall,
497 501 (double) rus.ru_utime.tv_sec +
498 502 ((double) rus.ru_utime.tv_usec/1000000.0),
499 503 (double) rus.ru_stime.tv_sec +
500 504 ((double) rus.ru_stime.tv_usec/1000000.0),
501 505 max_mem_used);
502 506 exit(0);
503 507 }
504 508 if (WIFSTOPPED(stat))
505 509 {
506 510 int sig = WSTOPSIG(stat);
507 511 if (sig == SIGTRAP)
508 512 {
509 513 struct user u;
510 514 static int stop_count = -1;
511 515 if (ptrace(PTRACE_GETREGS, box_pid, NULL, &u) < 0)
512 516 die("ptrace(PTRACE_GETREGS): %m");
513 517 stop_count++;
514 518 if (!stop_count) /* Traceme request */
515 519 log(">> Traceme request caught\n");
516 520 else if (stop_count & 1) /* Syscall entry */
517 521 {
518 522 log(">> Syscall %3ld (%08lx,%08lx,%08lx) ", u.regs.orig_eax, u.regs.ebx, u.regs.ecx, u.regs.edx);
519 523 syscall_count++;
520 524 if (!valid_syscall(&u))
521 525 {
522 526 /*
523 527 * Unfortunately, PTRACE_KILL kills _after_ the syscall completes,
524 528 * so we have to change it to something harmless (e.g., an undefined
525 529 * syscall) and make the program continue.
526 530 */
527 531 unsigned int sys = u.regs.orig_eax;
528 532 u.regs.orig_eax = 0xffffffff;
529 533 if (ptrace(PTRACE_SETREGS, box_pid, NULL, &u) < 0)
530 534 die("ptrace(PTRACE_SETREGS): %m");
531 535 die("Forbidden syscall %d.", sys);
532 536 }
533 537 }
534 538 else /* Syscall return */
535 539 log("= %ld\n", u.regs.eax);
536 540 ptrace(PTRACE_SYSCALL, box_pid, 0, 0);
537 541 }
538 542 else if (sig != SIGSTOP && sig != SIGXCPU && sig != SIGXFSZ)
539 543 {
540 544 log(">> Signal %d\n", sig);
541 545 ptrace(PTRACE_SYSCALL, box_pid, 0, sig);
542 546 }
543 547 else
544 548 die("Received signal %d.", sig);
545 549 }
546 550 else
547 551 die("wait4: unknown status %x, giving up!", stat);
548 552 }
549 553 }
550 554
551 555 static void
552 556 box_inside(int argc, char **argv)
553 557 {
554 558 struct rlimit rl;
555 559 char *args[argc+1];
556 560 char *env[1] = { NULL };
557 561
558 562 memcpy(args, argv, argc * sizeof(char *));
559 563 args[argc] = NULL;
560 564 if (set_cwd && chdir(set_cwd))
561 565 die("chdir: %m");
562 566 if (redir_stdin)
563 567 {
564 568 close(0);
565 569 if (open(redir_stdin, O_RDONLY) != 0)
566 570 die("open(\"%s\"): %m", redir_stdin);
567 571 }
568 572 if (redir_stdout)
569 573 {
570 574 close(1);
571 575 if (open(redir_stdout, O_WRONLY | O_CREAT | O_TRUNC, 0666) != 1)
572 576 die("open(\"%s\"): %m", redir_stdout);
573 577 }
574 578 dup2(1, 2);
575 579 setpgrp();
576 580 if (memory_limit)
577 581 {
578 582 rl.rlim_cur = rl.rlim_max = memory_limit * 1024;
579 583 if (setrlimit(RLIMIT_AS, &rl) < 0)
580 584 die("setrlimit: %m");
581 585 }
582 586 rl.rlim_cur = rl.rlim_max = 64;
583 587 if (setrlimit(RLIMIT_NOFILE, &rl) < 0)
584 588 die("setrlimit: %m");
585 589 if (filter_syscalls && ptrace(PTRACE_TRACEME) < 0)
586 590 die("ptrace(PTRACE_TRACEME): %m");
587 591 execve(args[0], args, (pass_environ ? environ : env));
588 592 die("execve(\"%s\"): %m", args[0]);
589 593 }
590 594
591 595 static void
592 596 usage(void)
593 597 {
594 598 fprintf(stderr, "Invalid arguments!\n");
595 599 printf("\
596 600 Usage: box [<options>] -- <command> <arguments>\n\
597 601 \n\
598 602 Options:\n\
You need to be logged in to leave comments. Login now