1 1.6 christos /* $NetBSD: ssh.c,v 1.6 2013/11/07 17:18:22 christos Exp $ */ 2 1.1 gwr 3 1.1 gwr /* 4 1.1 gwr * Copyright (c) 1995 Gordon W. Ross 5 1.1 gwr * All rights reserved. 6 1.1 gwr * 7 1.1 gwr * Redistribution and use in source and binary forms, with or without 8 1.1 gwr * modification, are permitted provided that the following conditions 9 1.1 gwr * are met: 10 1.1 gwr * 1. Redistributions of source code must retain the above copyright 11 1.1 gwr * notice, this list of conditions and the following disclaimer. 12 1.1 gwr * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 gwr * notice, this list of conditions and the following disclaimer in the 14 1.1 gwr * documentation and/or other materials provided with the distribution. 15 1.1 gwr * 16 1.1 gwr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 1.1 gwr * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 1.1 gwr * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 1.1 gwr * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 1.1 gwr * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 1.1 gwr * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 1.1 gwr * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 1.1 gwr * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 1.1 gwr * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 1.1 gwr * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 1.1 gwr */ 27 1.1 gwr 28 1.1 gwr /* 29 1.1 gwr * Small Shell - Nothing fancy. Just runs programs. 30 1.1 gwr * The RAMDISK root uses this to save space. 31 1.1 gwr */ 32 1.1 gwr 33 1.1 gwr #include <errno.h> 34 1.1 gwr #include <fcntl.h> 35 1.1 gwr #include <setjmp.h> 36 1.1 gwr #include <signal.h> 37 1.1 gwr #include <stdio.h> 38 1.1 gwr #include <stdlib.h> 39 1.1 gwr #include <string.h> 40 1.1 gwr #include <unistd.h> 41 1.1 gwr 42 1.1 gwr #include <sys/param.h> 43 1.1 gwr #include <sys/wait.h> 44 1.1 gwr 45 1.1 gwr /* XXX - SunOS hacks... */ 46 1.1 gwr #ifndef WCOREDUMP 47 1.1 gwr #define WCOREDUMP(x) ((x) & 0200) 48 1.1 gwr #endif 49 1.1 gwr 50 1.1 gwr #ifndef __P 51 1.1 gwr #define __P(x) x 52 1.1 gwr #endif /* __P */ 53 1.1 gwr 54 1.1 gwr extern char *optarg; 55 1.1 gwr extern int optind, opterr; 56 1.1 gwr 57 1.1 gwr #define MAXLINE 256 58 1.1 gwr #define MAXARGS 32 59 1.1 gwr 60 1.1 gwr #define MAXPATH 256 61 1.1 gwr char cur_path[MAXPATH] = "PATH=/bin:/usr/bin"; 62 1.1 gwr 63 1.1 gwr char rc_name[] = ".sshrc"; 64 1.4 tsutsui const char *prompt = "ssh: "; 65 1.1 gwr 66 1.1 gwr int eflag; /* exit on cmd failure */ 67 1.1 gwr int iflag; /* interactive mode (catch interrupts) */ 68 1.1 gwr int sflag; /* read from stdin (ignore file arg) */ 69 1.1 gwr int xflag; /* execution trace */ 70 1.1 gwr 71 1.1 gwr /* Command file: name, line number, arg count, arg vector */ 72 1.4 tsutsui const char *cf_name; 73 1.1 gwr int cf_line; 74 1.1 gwr int cf_argc; 75 1.1 gwr char **cf_argv; 76 1.1 gwr 77 1.1 gwr int def_omode = 0666; 78 1.1 gwr int run_bg_pid; 79 1.1 gwr 80 1.1 gwr jmp_buf next_cmd; 81 1.1 gwr 82 1.4 tsutsui int main(int, char *[]); 83 1.4 tsutsui void catchsig(int sig); 84 1.4 tsutsui void child_newfd(int setfd, char *file, int otype); 85 1.4 tsutsui int find_in_path(char *cmd, char *filebuf); 86 1.4 tsutsui void print_termsig(FILE *fp, int cstat); 87 1.4 tsutsui int runfile(FILE *fp); 88 1.4 tsutsui 89 1.4 tsutsui int cmd_eval(int, char *[]); 90 1.4 tsutsui int cmd_cd(int, char *[]); 91 1.4 tsutsui int cmd_exit(int, char *[]); 92 1.4 tsutsui int cmd_help(int, char *[]); 93 1.4 tsutsui int cmd_path(int, char *[]); 94 1.4 tsutsui int cmd_run(int, char *[]); 95 1.1 gwr 96 1.1 gwr 97 1.4 tsutsui int 98 1.4 tsutsui main(int argc, char *argv[]) 99 1.1 gwr { 100 1.1 gwr struct sigaction sa; 101 1.1 gwr FILE *cfp; /* command file ptr */ 102 1.1 gwr int c, sig; 103 1.1 gwr int error = 0; 104 1.1 gwr 105 1.1 gwr while ((c = getopt(argc, argv, "eisx")) != -1) { 106 1.1 gwr switch (c) { 107 1.1 gwr case 'e': 108 1.1 gwr eflag++; 109 1.1 gwr break; 110 1.1 gwr case 'i': 111 1.1 gwr eflag++; 112 1.1 gwr break; 113 1.1 gwr case 's': 114 1.1 gwr sflag++; 115 1.1 gwr break; 116 1.1 gwr case 'x': 117 1.1 gwr xflag++; 118 1.1 gwr break; 119 1.1 gwr case '?': 120 1.1 gwr error++; 121 1.1 gwr break; 122 1.1 gwr } 123 1.1 gwr } 124 1.1 gwr if (error) { 125 1.1 gwr fprintf(stderr, "usage: ssh [-eisx] [cmd_file [...]]\n"); 126 1.4 tsutsui exit(EXIT_FAILURE); 127 1.1 gwr } 128 1.1 gwr cf_argc = argc - optind; 129 1.1 gwr cf_argv = &argv[optind]; 130 1.1 gwr 131 1.1 gwr /* If this is a login shell, run the rc file. */ 132 1.1 gwr if (argv[0] && argv[0][0] == '-') { 133 1.1 gwr cf_line = 0; 134 1.1 gwr cf_name = rc_name; 135 1.1 gwr if ((cfp = fopen(cf_name, "r")) != NULL) { 136 1.1 gwr error = runfile(cfp); 137 1.1 gwr fclose(cfp); 138 1.1 gwr } 139 1.1 gwr } 140 1.1 gwr 141 1.1 gwr /* If no file names, read commands from stdin. */ 142 1.1 gwr if (cf_argc == 0) 143 1.1 gwr sflag++; 144 1.1 gwr /* If stdin is a tty, be interactive. */ 145 1.1 gwr if (sflag && isatty(fileno(stdin))) 146 1.1 gwr iflag++; 147 1.1 gwr 148 1.1 gwr /* Maybe run a command file... */ 149 1.1 gwr if (!sflag && cf_argc) { 150 1.1 gwr cf_line = 0; 151 1.1 gwr cf_name = cf_argv[0]; 152 1.1 gwr cfp = fopen(cf_name, "r"); 153 1.1 gwr if (cfp == NULL) { 154 1.1 gwr perror(cf_name); 155 1.4 tsutsui exit(EXIT_FAILURE); 156 1.1 gwr } 157 1.1 gwr error = runfile(cfp); 158 1.1 gwr fclose(cfp); 159 1.1 gwr exit(error); 160 1.1 gwr } 161 1.1 gwr 162 1.1 gwr /* Read commands from stdin. */ 163 1.1 gwr cf_line = 0; 164 1.1 gwr cf_name = "(stdin)"; 165 1.1 gwr if (iflag) { 166 1.1 gwr eflag = 0; /* don't kill shell on error. */ 167 1.1 gwr sig = setjmp(next_cmd); 168 1.1 gwr if (sig == 0) { 169 1.1 gwr /* Initialization... */ 170 1.1 gwr sa.sa_handler = catchsig; 171 1.1 gwr sa.sa_flags = 0; 172 1.1 gwr sigemptyset(&sa.sa_mask); 173 1.1 gwr sigaction(SIGINT, &sa, NULL); 174 1.1 gwr sigaction(SIGQUIT, &sa, NULL); 175 1.1 gwr sigaction(SIGTERM, &sa, NULL); 176 1.1 gwr } else { 177 1.1 gwr /* Got here via longjmp. */ 178 1.1 gwr fprintf(stderr, " signal %d\n", sig); 179 1.1 gwr sigemptyset(&sa.sa_mask); 180 1.1 gwr sigprocmask(SIG_SETMASK, &sa.sa_mask, NULL); 181 1.1 gwr } 182 1.1 gwr } 183 1.1 gwr error = runfile(stdin); 184 1.4 tsutsui exit(error); 185 1.1 gwr } 186 1.1 gwr 187 1.1 gwr void 188 1.4 tsutsui catchsig(int sig) 189 1.1 gwr { 190 1.4 tsutsui 191 1.1 gwr longjmp(next_cmd, sig); 192 1.1 gwr } 193 1.1 gwr 194 1.1 gwr /* 195 1.1 gwr * Run command from the passed stdio file pointer. 196 1.1 gwr * Returns exit status. 197 1.1 gwr */ 198 1.1 gwr int 199 1.4 tsutsui runfile(FILE *cfp) 200 1.1 gwr { 201 1.1 gwr char ibuf[MAXLINE]; 202 1.1 gwr char *argv[MAXARGS]; 203 1.1 gwr char *p; 204 1.1 gwr int i, argc, exitcode, cpid, cstat; 205 1.1 gwr 206 1.1 gwr /* The command loop. */ 207 1.1 gwr exitcode = 0; 208 1.1 gwr for (;;) { 209 1.1 gwr if (iflag) { 210 1.5 christos fprintf(stderr, "%s", prompt); 211 1.1 gwr fflush(stderr); 212 1.1 gwr } 213 1.1 gwr 214 1.1 gwr if ((fgets(ibuf, sizeof(ibuf), cfp)) == NULL) 215 1.1 gwr break; 216 1.1 gwr cf_line++; 217 1.1 gwr 218 1.1 gwr argc = 0; 219 1.1 gwr p = ibuf; 220 1.1 gwr 221 1.1 gwr while (argc < MAXARGS-1) { 222 1.1 gwr /* skip blanks or tabs */ 223 1.1 gwr while ((*p == ' ') || (*p == '\t')) { 224 1.1 gwr next_token: 225 1.1 gwr *p++ = '\0'; 226 1.1 gwr } 227 1.1 gwr /* end of line? */ 228 1.1 gwr if ((*p == '\n') || (*p == '#')) { 229 1.1 gwr *p = '\0'; 230 1.1 gwr break; /* to eol */ 231 1.1 gwr } 232 1.1 gwr if (*p == '\0') 233 1.1 gwr break; 234 1.1 gwr /* save start of token */ 235 1.1 gwr argv[argc++] = p; 236 1.1 gwr /* find end of token */ 237 1.1 gwr while (*p) { 238 1.1 gwr if ((*p == '\n') || (*p == '#')) { 239 1.1 gwr *p = '\0'; 240 1.1 gwr goto eol; 241 1.1 gwr } 242 1.1 gwr if ((*p == ' ') || (*p == '\t')) 243 1.1 gwr goto next_token; 244 1.1 gwr p++; 245 1.1 gwr } 246 1.1 gwr } 247 1.1 gwr eol: 248 1.1 gwr 249 1.1 gwr if (argc > 0) { 250 1.1 gwr if (xflag) { 251 1.1 gwr fprintf(stderr, "x"); 252 1.1 gwr for (i = 0; i < argc; i++) { 253 1.1 gwr fprintf(stderr, " %s", argv[i]); 254 1.1 gwr } 255 1.1 gwr fprintf(stderr, "\n"); 256 1.1 gwr } 257 1.1 gwr argv[argc] = NULL; 258 1.1 gwr exitcode = cmd_eval(argc, argv); 259 1.1 gwr } 260 1.1 gwr 261 1.1 gwr /* Collect children. */ 262 1.1 gwr while ((cpid = waitpid(0, &cstat, WNOHANG)) > 0) { 263 1.1 gwr if (iflag) { 264 1.1 gwr fprintf(stderr, "[%d] ", cpid); 265 1.1 gwr if (WTERMSIG(cstat)) { 266 1.1 gwr print_termsig(stderr, cstat); 267 1.1 gwr } else { 268 1.1 gwr fprintf(stderr, "Exited, status %d\n", 269 1.1 gwr WEXITSTATUS(cstat)); 270 1.1 gwr } 271 1.1 gwr } 272 1.1 gwr } 273 1.1 gwr 274 1.1 gwr if (exitcode && eflag) 275 1.1 gwr break; 276 1.1 gwr } 277 1.1 gwr /* return status of last command */ 278 1.4 tsutsui return exitcode; 279 1.1 gwr } 280 1.1 gwr 281 1.1 gwr 282 1.1 gwr /**************************************************************** 283 1.1 gwr * Table of buildin commands 284 1.1 gwr * for cmd_eval() to search... 285 1.1 gwr ****************************************************************/ 286 1.1 gwr 287 1.1 gwr struct cmd { 288 1.4 tsutsui const char *name; 289 1.4 tsutsui int (*func)(int, char *[]); 290 1.4 tsutsui const char *help; 291 1.1 gwr }; 292 1.1 gwr struct cmd cmd_table[]; 293 1.1 gwr 294 1.1 gwr /* 295 1.1 gwr * Evaluate a command named as argv[0] 296 1.1 gwr * with arguments argv[1],argv[2]... 297 1.1 gwr * Returns exit status. 298 1.1 gwr */ 299 1.1 gwr int 300 1.4 tsutsui cmd_eval(int argc, char *argv[]) 301 1.1 gwr { 302 1.1 gwr struct cmd *cp; 303 1.1 gwr 304 1.1 gwr /* 305 1.1 gwr * Do linear search for a builtin command. 306 1.1 gwr * Performance does not matter here. 307 1.1 gwr */ 308 1.1 gwr for (cp = cmd_table; cp->name; cp++) { 309 1.1 gwr if (!strcmp(cp->name, argv[0])) { 310 1.1 gwr /* Pass only args to builtin. */ 311 1.1 gwr --argc; argv++; 312 1.4 tsutsui return cp->func(argc, argv); 313 1.1 gwr } 314 1.1 gwr } 315 1.1 gwr 316 1.1 gwr /* 317 1.1 gwr * If no matching builtin, let "run ..." 318 1.1 gwr * have a chance to try an external. 319 1.1 gwr */ 320 1.4 tsutsui return cmd_run(argc, argv); 321 1.1 gwr } 322 1.1 gwr 323 1.1 gwr /***************************************************************** 324 1.1 gwr * Here are the actual commands. For these, 325 1.1 gwr * the command name has been skipped, so 326 1.1 gwr * argv[0] is the first arg (if any args). 327 1.1 gwr * All return an exit status. 328 1.1 gwr ****************************************************************/ 329 1.1 gwr 330 1.4 tsutsui const char help_cd[] = "cd [dir]"; 331 1.1 gwr 332 1.1 gwr int 333 1.4 tsutsui cmd_cd(int argc, char *argv[]) 334 1.1 gwr { 335 1.4 tsutsui const char *dir; 336 1.1 gwr 337 1.1 gwr if (argc > 0) 338 1.1 gwr dir = argv[0]; 339 1.1 gwr else { 340 1.1 gwr dir = getenv("HOME"); 341 1.1 gwr if (dir == NULL) 342 1.1 gwr dir = "/"; 343 1.1 gwr } 344 1.1 gwr if (chdir(dir)) { 345 1.1 gwr perror(dir); 346 1.4 tsutsui return 1; 347 1.1 gwr } 348 1.4 tsutsui return 0; 349 1.1 gwr } 350 1.1 gwr 351 1.4 tsutsui const char help_exit[] = "exit [n]"; 352 1.1 gwr 353 1.1 gwr int 354 1.4 tsutsui cmd_exit(int argc, char **argv) 355 1.1 gwr { 356 1.1 gwr int val = 0; 357 1.1 gwr 358 1.1 gwr if (argc > 0) 359 1.1 gwr val = atoi(argv[0]); 360 1.1 gwr exit(val); 361 1.1 gwr } 362 1.1 gwr 363 1.4 tsutsui const char help_help[] = "help [command]"; 364 1.1 gwr 365 1.1 gwr int 366 1.4 tsutsui cmd_help(int argc, char *argv[]) 367 1.1 gwr { 368 1.1 gwr struct cmd *cp; 369 1.1 gwr 370 1.1 gwr if (argc > 0) { 371 1.1 gwr for (cp = cmd_table; cp->name; cp++) { 372 1.1 gwr if (!strcmp(cp->name, argv[0])) { 373 1.1 gwr printf("usage: %s\n", cp->help); 374 1.4 tsutsui return 0; 375 1.1 gwr } 376 1.1 gwr } 377 1.1 gwr printf("%s: no such command\n", argv[0]); 378 1.1 gwr } 379 1.1 gwr 380 1.1 gwr printf("Builtin commands: "); 381 1.1 gwr for (cp = cmd_table; cp->name; cp++) { 382 1.1 gwr printf(" %s", cp->name); 383 1.1 gwr } 384 1.1 gwr printf("\nFor specific usage: help [command]\n"); 385 1.4 tsutsui return 0; 386 1.1 gwr } 387 1.1 gwr 388 1.4 tsutsui const char help_path[] = "path [dir1:dir2:...]"; 389 1.1 gwr 390 1.1 gwr int 391 1.4 tsutsui cmd_path(int argc, char *argv[]) 392 1.1 gwr { 393 1.1 gwr 394 1.1 gwr if (argc <= 0) { 395 1.1 gwr printf("%s\n", cur_path); 396 1.4 tsutsui return 0; 397 1.1 gwr } 398 1.1 gwr 399 1.1 gwr strncpy(cur_path+5, argv[0], MAXPATH-6); 400 1.1 gwr putenv(cur_path); 401 1.1 gwr 402 1.4 tsutsui return 0; 403 1.1 gwr } 404 1.1 gwr 405 1.1 gwr /***************************************************************** 406 1.1 gwr * The "run" command is the big one. 407 1.1 gwr * Does fork/exec/wait, redirection... 408 1.1 gwr * Returns exit status of child 409 1.1 gwr * (or zero for a background job) 410 1.1 gwr ****************************************************************/ 411 1.1 gwr 412 1.4 tsutsui const char help_run[] = "\ 413 1.1 gwr run [-bg] [-i ifile] [-o ofile] [-e efile] program [args...]\n\ 414 1.1 gwr or simply: program [args...]"; 415 1.1 gwr 416 1.1 gwr int 417 1.4 tsutsui cmd_run(int argc, char *argv[]) 418 1.1 gwr { 419 1.1 gwr struct sigaction sa; 420 1.6 christos int pid, cstat; 421 1.1 gwr char file[MAXPATHLEN]; 422 1.1 gwr int background; 423 1.1 gwr char *opt, *ifile, *ofile, *efile; 424 1.1 gwr extern char **environ; 425 1.1 gwr 426 1.1 gwr /* 427 1.1 gwr * Parse options: 428 1.1 gwr * -b : background 429 1.1 gwr * -i : input file 430 1.1 gwr * -o : output file 431 1.1 gwr * -e : error file 432 1.1 gwr */ 433 1.1 gwr background = 0; 434 1.1 gwr ifile = ofile = efile = NULL; 435 1.1 gwr while ((argc > 0) && (argv[0][0] == '-')) { 436 1.1 gwr opt = argv[0]; 437 1.1 gwr --argc; argv++; 438 1.1 gwr switch (opt[1]) { 439 1.1 gwr case 'b': 440 1.1 gwr background++; 441 1.1 gwr break; 442 1.1 gwr case 'i': 443 1.1 gwr ifile = argv[0]; 444 1.1 gwr goto shift; 445 1.1 gwr case 'o': 446 1.1 gwr ofile = argv[0]; 447 1.1 gwr goto shift; 448 1.1 gwr case 'e': 449 1.1 gwr efile = argv[0]; 450 1.1 gwr goto shift; 451 1.1 gwr default: 452 1.1 gwr fprintf(stderr, "run %s: bad option\n", opt); 453 1.4 tsutsui return 1; 454 1.1 gwr shift: 455 1.1 gwr --argc; argv++; 456 1.1 gwr } 457 1.1 gwr } 458 1.1 gwr 459 1.1 gwr if (argc <= 0) { 460 1.1 gwr fprintf(stderr, "%s:%d run: missing command\n", 461 1.1 gwr cf_name, cf_line); 462 1.4 tsutsui return 1; 463 1.1 gwr } 464 1.1 gwr 465 1.1 gwr /* Commands containing '/' get no path search. */ 466 1.1 gwr if (strchr(argv[0], '/')) { 467 1.1 gwr strncpy(file, argv[0], sizeof(file)-1); 468 1.1 gwr if (access(file, X_OK)) { 469 1.1 gwr perror(file); 470 1.4 tsutsui return 1; 471 1.1 gwr } 472 1.1 gwr } else { 473 1.1 gwr if (find_in_path(argv[0], file)) { 474 1.1 gwr fprintf(stderr, "%s: command not found\n", argv[0]); 475 1.4 tsutsui return 1; 476 1.1 gwr } 477 1.1 gwr } 478 1.1 gwr 479 1.1 gwr pid = fork(); 480 1.1 gwr if (pid == 0) { 481 1.1 gwr /* child runs this */ 482 1.1 gwr /* handle redirection options... */ 483 1.1 gwr if (ifile) 484 1.1 gwr child_newfd(0, ifile, O_RDONLY); 485 1.1 gwr if (ofile) 486 1.1 gwr child_newfd(1, ofile, O_WRONLY|O_CREAT); 487 1.1 gwr if (efile) 488 1.1 gwr child_newfd(2, efile, O_WRONLY|O_CREAT); 489 1.1 gwr if (background) { 490 1.1 gwr /* Ignore SIGINT, SIGQUIT */ 491 1.1 gwr sa.sa_handler = SIG_IGN; 492 1.1 gwr sa.sa_flags = 0; 493 1.1 gwr sigemptyset(&sa.sa_mask); 494 1.1 gwr sigaction(SIGINT, &sa, NULL); 495 1.1 gwr sigaction(SIGQUIT, &sa, NULL); 496 1.1 gwr } 497 1.6 christos execve(file, argv, environ); 498 1.1 gwr perror(argv[0]); 499 1.4 tsutsui return 1; 500 1.1 gwr } 501 1.1 gwr /* parent */ 502 1.1 gwr /* Handle background option... */ 503 1.1 gwr if (background) { 504 1.1 gwr fprintf(stderr, "[%d]\n", pid); 505 1.1 gwr run_bg_pid = pid; 506 1.4 tsutsui return 0; 507 1.1 gwr } 508 1.1 gwr if (waitpid(pid, &cstat, 0) < 0) { 509 1.1 gwr perror("waitpid"); 510 1.4 tsutsui return 1; 511 1.1 gwr } 512 1.1 gwr if (WTERMSIG(cstat)) { 513 1.1 gwr print_termsig(stderr, cstat); 514 1.1 gwr } 515 1.4 tsutsui return WEXITSTATUS(cstat); 516 1.1 gwr } 517 1.1 gwr 518 1.1 gwr /***************************************************************** 519 1.1 gwr * table of builtin commands 520 1.1 gwr ****************************************************************/ 521 1.1 gwr struct cmd cmd_table[] = { 522 1.1 gwr { "cd", cmd_cd, help_cd }, 523 1.1 gwr { "exit", cmd_exit, help_exit }, 524 1.1 gwr { "help", cmd_help, help_help }, 525 1.1 gwr { "path", cmd_path, help_path }, 526 1.1 gwr { "run", cmd_run, help_run }, 527 1.4 tsutsui { NULL, NULL, NULL }, 528 1.1 gwr }; 529 1.1 gwr 530 1.1 gwr /***************************************************************** 531 1.1 gwr * helper functions for the "run" command 532 1.1 gwr ****************************************************************/ 533 1.1 gwr 534 1.1 gwr int 535 1.4 tsutsui find_in_path(char *cmd, char *filebuf) 536 1.1 gwr { 537 1.1 gwr char *dirp, *endp, *bufp; /* dir, end */ 538 1.1 gwr 539 1.1 gwr dirp = cur_path + 5; 540 1.1 gwr while (*dirp) { 541 1.1 gwr endp = dirp; 542 1.1 gwr bufp = filebuf; 543 1.1 gwr while (*endp && (*endp != ':')) 544 1.1 gwr *bufp++ = *endp++; 545 1.1 gwr *bufp++ = '/'; 546 1.1 gwr strcpy(bufp, cmd); 547 1.1 gwr if (access(filebuf, X_OK) == 0) 548 1.4 tsutsui return 0; 549 1.1 gwr if (*endp == ':') 550 1.1 gwr endp++; 551 1.1 gwr dirp = endp; /* next dir */ 552 1.1 gwr } 553 1.4 tsutsui return -1; 554 1.1 gwr } 555 1.1 gwr 556 1.1 gwr /* 557 1.1 gwr * Set the file descriptor SETFD to FILE, 558 1.1 gwr * which was opened with OTYPE and MODE. 559 1.1 gwr */ 560 1.1 gwr void 561 1.4 tsutsui child_newfd(int setfd, char *file, int otype) 562 1.4 tsutsui /* int setfd; what to set (i.e. 0,1,2) */ 563 1.4 tsutsui /* char *file; */ 564 1.4 tsutsui /* int otype; O_RDONLY, etc. */ 565 1.1 gwr { 566 1.1 gwr int newfd; 567 1.1 gwr 568 1.1 gwr close(setfd); 569 1.1 gwr if ((newfd = open(file, otype, def_omode)) < 0) { 570 1.1 gwr perror(file); 571 1.4 tsutsui exit(EXIT_FAILURE); 572 1.1 gwr } 573 1.1 gwr if (newfd != setfd) { 574 1.1 gwr dup2(newfd, setfd); 575 1.1 gwr close(newfd); 576 1.1 gwr } 577 1.1 gwr } 578 1.1 gwr 579 1.1 gwr void 580 1.4 tsutsui print_termsig(FILE *fp, int cstat) 581 1.1 gwr { 582 1.1 gwr fprintf(fp, "Terminated, signal %d", 583 1.1 gwr WTERMSIG(cstat)); 584 1.1 gwr if (WCOREDUMP(cstat)) 585 1.1 gwr fprintf(fp, " (core dumped)"); 586 1.1 gwr fprintf(fp, "\n"); 587 1.1 gwr } 588