1 /* $NetBSD: ssh.c,v 1.2 2002/05/26 00:09:09 wiz Exp $ */
4 * Copyright (c) 1995 Gordon W. Ross
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * Small Shell - Nothing fancy. Just runs programs.
30 * The RAMDISK root uses this to save space.
42 #include <sys/param.h>
45 /* XXX - SunOS hacks... */
47 #define WCOREDUMP(x) ((x) & 0200)
55 extern int optind
, opterr
;
61 char cur_path
[MAXPATH
] = "PATH=/bin:/usr/bin";
63 char rc_name
[] = ".sshrc";
64 char *prompt
= "ssh: ";
66 int eflag
; /* exit on cmd failure */
67 int iflag
; /* interactive mode (catch interrupts) */
68 int sflag
; /* read from stdin (ignore file arg) */
69 int xflag
; /* execution trace */
71 /* Command file: name, line number, arg count, arg vector */
82 void catchsig
__P((int sig
));
83 void child_newfd
__P((int setfd
, char *file
, int otype
));
84 int find_in_path
__P((char *cmd
, char *filebuf
));
85 void print_termsig
__P((FILE *fp
, int cstat
));
86 int runfile
__P((FILE *fp
));
94 FILE *cfp
; /* command file ptr */
98 while ((c
= getopt(argc
, argv
, "eisx")) != -1) {
118 fprintf(stderr
, "usage: ssh [-eisx] [cmd_file [...]]\n");
121 cf_argc
= argc
- optind
;
122 cf_argv
= &argv
[optind
];
124 /* If this is a login shell, run the rc file. */
125 if (argv
[0] && argv
[0][0] == '-') {
128 if ((cfp
= fopen(cf_name
, "r")) != NULL
) {
129 error
= runfile(cfp
);
134 /* If no file names, read commands from stdin. */
137 /* If stdin is a tty, be interactive. */
138 if (sflag
&& isatty(fileno(stdin
)))
141 /* Maybe run a command file... */
142 if (!sflag
&& cf_argc
) {
144 cf_name
= cf_argv
[0];
145 cfp
= fopen(cf_name
, "r");
150 error
= runfile(cfp
);
155 /* Read commands from stdin. */
159 eflag
= 0; /* don't kill shell on error. */
160 sig
= setjmp(next_cmd
);
162 /* Initialization... */
163 sa
.sa_handler
= catchsig
;
165 sigemptyset(&sa
.sa_mask
);
166 sigaction(SIGINT
, &sa
, NULL
);
167 sigaction(SIGQUIT
, &sa
, NULL
);
168 sigaction(SIGTERM
, &sa
, NULL
);
170 /* Got here via longjmp. */
171 fprintf(stderr
, " signal %d\n", sig
);
172 sigemptyset(&sa
.sa_mask
);
173 sigprocmask(SIG_SETMASK
, &sa
.sa_mask
, NULL
);
176 error
= runfile(stdin
);
184 longjmp(next_cmd
, sig
);
188 * Run command from the passed stdio file pointer.
189 * Returns exit status.
198 int i
, argc
, exitcode
, cpid
, cstat
;
200 /* The command loop. */
204 fprintf(stderr
, prompt
);
208 if ((fgets(ibuf
, sizeof(ibuf
), cfp
)) == NULL
)
215 while (argc
< MAXARGS
-1) {
216 /* skip blanks or tabs */
217 while ((*p
== ' ') || (*p
== '\t')) {
222 if ((*p
== '\n') || (*p
== '#')) {
228 /* save start of token */
230 /* find end of token */
232 if ((*p
== '\n') || (*p
== '#')) {
236 if ((*p
== ' ') || (*p
== '\t'))
245 fprintf(stderr
, "x");
246 for (i
= 0; i
< argc
; i
++) {
247 fprintf(stderr
, " %s", argv
[i
]);
249 fprintf(stderr
, "\n");
252 exitcode
= cmd_eval(argc
, argv
);
255 /* Collect children. */
256 while ((cpid
= waitpid(0, &cstat
, WNOHANG
)) > 0) {
258 fprintf(stderr
, "[%d] ", cpid
);
259 if (WTERMSIG(cstat
)) {
260 print_termsig(stderr
, cstat
);
262 fprintf(stderr
, "Exited, status %d\n",
268 if (exitcode
&& eflag
)
271 /* return status of last command */
276 /****************************************************************
277 * Table of buildin commands
278 * for cmd_eval() to search...
279 ****************************************************************/
286 struct cmd cmd_table
[];
289 * Evaluate a command named as argv[0]
290 * with arguments argv[1],argv[2]...
291 * Returns exit status.
301 * Do linear search for a builtin command.
302 * Performance does not matter here.
304 for (cp
= cmd_table
; cp
->name
; cp
++) {
305 if (!strcmp(cp
->name
, argv
[0])) {
306 /* Pass only args to builtin. */
308 return (cp
->func(argc
, argv
));
313 * If no matching builtin, let "run ..."
314 * have a chance to try an external.
316 return (cmd_run(argc
, argv
));
319 /*****************************************************************
320 * Here are the actual commands. For these,
321 * the command name has been skipped, so
322 * argv[0] is the first arg (if any args).
323 * All return an exit status.
324 ****************************************************************/
326 char help_cd
[] = "cd [dir]";
339 dir
= getenv("HOME");
350 char help_exit
[] = "exit [n]";
364 char help_help
[] = "help [command]";
374 for (cp
= cmd_table
; cp
->name
; cp
++) {
375 if (!strcmp(cp
->name
, argv
[0])) {
376 printf("usage: %s\n", cp
->help
);
380 printf("%s: no such command\n", argv
[0]);
383 printf("Builtin commands: ");
384 for (cp
= cmd_table
; cp
->name
; cp
++) {
385 printf(" %s", cp
->name
);
387 printf("\nFor specific usage: help [command]\n");
391 char help_path
[] = "path [dir1:dir2:...]";
401 printf("%s\n", cur_path
);
405 strncpy(cur_path
+5, argv
[0], MAXPATH
-6);
411 /*****************************************************************
412 * The "run" command is the big one.
413 * Does fork/exec/wait, redirection...
414 * Returns exit status of child
415 * (or zero for a background job)
416 ****************************************************************/
419 run [-bg] [-i ifile] [-o ofile] [-e efile] program [args...]\n\
420 or simply: program [args...]";
428 int pid
, err
, cstat
, fd
;
429 char file
[MAXPATHLEN
];
431 char *opt
, *ifile
, *ofile
, *efile
;
432 extern char **environ
;
442 ifile
= ofile
= efile
= NULL
;
443 while ((argc
> 0) && (argv
[0][0] == '-')) {
460 fprintf(stderr
, "run %s: bad option\n", opt
);
468 fprintf(stderr
, "%s:%d run: missing command\n",
473 /* Commands containing '/' get no path search. */
474 if (strchr(argv
[0], '/')) {
475 strncpy(file
, argv
[0], sizeof(file
)-1);
476 if (access(file
, X_OK
)) {
481 if (find_in_path(argv
[0], file
)) {
482 fprintf(stderr
, "%s: command not found\n", argv
[0]);
489 /* child runs this */
490 /* handle redirection options... */
492 child_newfd(0, ifile
, O_RDONLY
);
494 child_newfd(1, ofile
, O_WRONLY
|O_CREAT
);
496 child_newfd(2, efile
, O_WRONLY
|O_CREAT
);
498 /* Ignore SIGINT, SIGQUIT */
499 sa
.sa_handler
= SIG_IGN
;
501 sigemptyset(&sa
.sa_mask
);
502 sigaction(SIGINT
, &sa
, NULL
);
503 sigaction(SIGQUIT
, &sa
, NULL
);
505 err
= execve(file
, argv
, environ
);
510 /* Handle background option... */
512 fprintf(stderr
, "[%d]\n", pid
);
516 if (waitpid(pid
, &cstat
, 0) < 0) {
520 if (WTERMSIG(cstat
)) {
521 print_termsig(stderr
, cstat
);
523 return (WEXITSTATUS(cstat
));
526 /*****************************************************************
527 * table of builtin commands
528 ****************************************************************/
529 struct cmd cmd_table
[] = {
530 { "cd", cmd_cd
, help_cd
},
531 { "exit", cmd_exit
, help_exit
},
532 { "help", cmd_help
, help_help
},
533 { "path", cmd_path
, help_path
},
534 { "run", cmd_run
, help_run
},
538 /*****************************************************************
539 * helper functions for the "run" command
540 ****************************************************************/
543 find_in_path(cmd
, filebuf
)
547 char *dirp
, *endp
, *bufp
; /* dir, end */
553 while (*endp
&& (*endp
!= ':'))
557 if (access(filebuf
, X_OK
) == 0)
561 dirp
= endp
; /* next dir */
567 * Set the file descriptor SETFD to FILE,
568 * which was opened with OTYPE and MODE.
571 child_newfd(setfd
, file
, otype
)
572 int setfd
; /* what to set (i.e. 0,1,2) */
574 int otype
; /* O_RDONLY, etc. */
579 if ((newfd
= open(file
, otype
, def_omode
)) < 0) {
583 if (newfd
!= setfd
) {
590 print_termsig(fp
, cstat
)
594 fprintf(fp
, "Terminated, signal %d",
596 if (WCOREDUMP(cstat
))
597 fprintf(fp
, " (core dumped)");