if_iwm - Sync rs (rate-selection) API definitions from Linux iwlwifi.
[dragonfly.git] / usr.bin / rsh / rsh.c
blob9287924fdbf01dedff8e6ea9c682cf4f5e59d475
1 /*-
2 * Copyright (c) 1983, 1990, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 * Copyright (c) 2002 Networks Associates Technology, Inc.
5 * All rights reserved.
7 * Portions of this software were developed for the FreeBSD Project by
8 * ThinkSec AS and NAI Labs, the Security Research Division of Network
9 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
10 * ("CBOSS"), as part of the DARPA CHATS research program.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
36 * @(#)rsh.c 8.3 (Berkeley) 4/6/94
37 * $FreeBSD: src/usr.bin/rsh/rsh.c,v 1.35 2005/05/21 09:55:07 ru Exp $
38 * $DragonFly: src/usr.bin/rsh/rsh.c,v 1.7 2007/05/18 17:05:12 dillon Exp $
41 #include <sys/param.h>
42 #include <sys/signal.h>
43 #include <sys/socket.h>
44 #include <sys/ioctl.h>
45 #include <sys/file.h>
46 #include <sys/time.h>
48 #include <netinet/in.h>
49 #include <netdb.h>
51 #include <err.h>
52 #include <errno.h>
53 #include <libutil.h>
54 #include <paths.h>
55 #include <pwd.h>
56 #include <signal.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #include <unistd.h>
63 * rsh - remote shell
65 int rfd2;
67 int family = PF_UNSPEC;
68 char rlogin[] = "rlogin";
70 void connect_timeout(int);
71 char *copyargs(char * const *);
72 void sendsig(int);
73 void talk(int, long, pid_t, int, int);
74 void usage(void);
76 int
77 main(int argc, char **argv)
79 struct passwd const *pw;
80 struct servent const *sp;
81 long omask;
82 int argoff, asrsh, ch, dflag, nflag, one, rem;
83 pid_t pid = 0;
84 uid_t uid;
85 char *args, *host, *p, *user;
86 int timeout = 0;
88 argoff = asrsh = dflag = nflag = 0;
89 one = 1;
90 host = user = NULL;
92 /* if called as something other than "rsh", use it as the host name */
93 if ((p = strrchr(argv[0], '/')))
94 ++p;
95 else
96 p = argv[0];
97 if (strcmp(p, "rsh"))
98 host = p;
99 else
100 asrsh = 1;
102 /* handle "rsh host flags" */
103 if (!host && argc > 2 && argv[1][0] != '-') {
104 host = argv[1];
105 argoff = 1;
108 #define OPTIONS "468Lde:l:nt:w"
109 while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != -1)
110 switch(ch) {
111 case '4':
112 family = PF_INET;
113 break;
115 case '6':
116 family = PF_INET6;
117 break;
119 case 'L': /* -8Lew are ignored to allow rlogin aliases */
120 case 'e':
121 case 'w':
122 case '8':
123 break;
124 case 'd':
125 dflag = 1;
126 break;
127 case 'l':
128 user = optarg;
129 break;
130 case 'n':
131 nflag = 1;
132 break;
133 case 't':
134 timeout = atoi(optarg);
135 break;
136 case '?':
137 default:
138 usage();
140 optind += argoff;
142 /* if haven't gotten a host yet, do so */
143 if (!host && !(host = argv[optind++]))
144 usage();
146 /* if no further arguments, must have been called as rlogin. */
147 if (!argv[optind]) {
148 if (asrsh)
149 *argv = rlogin;
150 execv(_PATH_RLOGIN, argv);
151 err(1, "can't exec %s", _PATH_RLOGIN);
154 argc -= optind;
155 argv += optind;
157 if (!(pw = getpwuid(uid = getuid())))
158 errx(1, "unknown user id");
159 if (!user)
160 user = pw->pw_name;
162 args = copyargs(argv);
164 sp = NULL;
165 if (sp == NULL)
166 sp = getservbyname("shell", "tcp");
167 if (sp == NULL)
168 errx(1, "shell/tcp: unknown service");
170 if (timeout) {
171 signal(SIGALRM, connect_timeout);
172 alarm(timeout);
174 rem = rcmd_af(&host, sp->s_port, pw->pw_name, user, args, &rfd2,
175 family);
176 if (timeout) {
177 signal(SIGALRM, SIG_DFL);
178 alarm(0);
181 if (rem < 0)
182 exit(1);
184 if (rfd2 < 0)
185 errx(1, "can't establish stderr");
186 if (dflag) {
187 if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one,
188 sizeof(one)) < 0)
189 warn("setsockopt");
190 if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one,
191 sizeof(one)) < 0)
192 warn("setsockopt");
195 setuid(uid);
196 omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGTERM));
197 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
198 signal(SIGINT, sendsig);
199 if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
200 signal(SIGQUIT, sendsig);
201 if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
202 signal(SIGTERM, sendsig);
204 if (!nflag) {
205 pid = fork();
206 if (pid < 0)
207 err(1, "fork");
209 else
210 shutdown(rem, SHUT_WR);
212 ioctl(rfd2, FIONBIO, &one);
213 ioctl(rem, FIONBIO, &one);
215 talk(nflag, omask, pid, rem, timeout);
217 if (!nflag)
218 kill(pid, SIGKILL);
219 exit(0);
222 void
223 talk(int nflag, long omask, pid_t pid, int rem, int timeout)
225 int cc, wc;
226 fd_set readfrom, ready, rembits;
227 char buf[BUFSIZ];
228 const char *bp;
229 struct timeval tvtimeout;
230 int nfds, srval;
232 if (!nflag && pid == 0) {
233 close(rfd2);
235 reread: errno = 0;
236 if ((cc = read(STDIN_FILENO, buf, sizeof(buf))) <= 0)
237 goto done;
238 bp = buf;
240 rewrite:
241 if (rem >= FD_SETSIZE)
242 errx(1, "descriptor too big");
243 FD_ZERO(&rembits);
244 FD_SET(rem, &rembits);
245 nfds = rem + 1;
246 if (select(nfds, 0, &rembits, 0, 0) < 0) {
247 if (errno != EINTR)
248 err(1, "select");
249 goto rewrite;
251 if (!FD_ISSET(rem, &rembits))
252 goto rewrite;
253 wc = write(rem, bp, cc);
254 if (wc < 0) {
255 if (errno == EWOULDBLOCK)
256 goto rewrite;
257 goto done;
259 bp += wc;
260 cc -= wc;
261 if (cc == 0)
262 goto reread;
263 goto rewrite;
264 done:
265 shutdown(rem, SHUT_WR);
266 exit(0);
269 tvtimeout.tv_sec = timeout;
270 tvtimeout.tv_usec = 0;
272 sigsetmask(omask);
273 if (rfd2 >= FD_SETSIZE || rem >= FD_SETSIZE)
274 errx(1, "descriptor too big");
275 FD_ZERO(&readfrom);
276 FD_SET(rfd2, &readfrom);
277 FD_SET(rem, &readfrom);
278 nfds = MAX(rfd2+1, rem+1);
279 do {
280 ready = readfrom;
281 if (timeout) {
282 srval = select(nfds, &ready, 0, 0, &tvtimeout);
283 } else {
284 srval = select(nfds, &ready, 0, 0, 0);
287 if (srval < 0) {
288 if (errno != EINTR)
289 err(1, "select");
290 continue;
292 if (srval == 0)
293 errx(1, "timeout reached (%d seconds)", timeout);
294 if (FD_ISSET(rfd2, &ready)) {
295 errno = 0;
296 cc = read(rfd2, buf, sizeof(buf));
297 if (cc <= 0) {
298 if (errno != EWOULDBLOCK)
299 FD_CLR(rfd2, &readfrom);
300 } else
301 write(STDERR_FILENO, buf, cc);
303 if (FD_ISSET(rem, &ready)) {
304 errno = 0;
305 cc = read(rem, buf, sizeof(buf));
306 if (cc <= 0) {
307 if (errno != EWOULDBLOCK)
308 FD_CLR(rem, &readfrom);
309 } else
310 write(STDOUT_FILENO, buf, cc);
312 } while (FD_ISSET(rfd2, &readfrom) || FD_ISSET(rem, &readfrom));
315 void
316 connect_timeout(int sig __unused)
318 char message[] = "timeout reached before connection completed.\n";
320 write(STDERR_FILENO, message, sizeof(message) - 1);
321 _exit(1);
324 void
325 sendsig(int sig)
327 char signo;
329 signo = sig;
330 write(rfd2, &signo, 1);
333 char *
334 copyargs(char * const *argv)
336 int cc;
337 char *args, *p;
338 char * const *ap;
340 cc = 0;
341 for (ap = argv; *ap; ++ap)
342 cc += strlen(*ap) + 1;
343 if (!(args = malloc((u_int)cc)))
344 err(1, NULL);
345 for (p = args, ap = argv; *ap; ++ap) {
346 strcpy(p, *ap);
347 for (p = strcpy(p, *ap); *p; ++p);
348 if (ap[1])
349 *p++ = ' ';
351 return (args);
354 void
355 usage(void)
358 fprintf(stderr,
359 "usage: rsh [-46dn] [-l username] [-t timeout] host [command]\n");
360 exit(1);