00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #ifndef lint
00035 char copyright[] =
00036 "@(#) Copyright (c) 1983, 1990 The Regents of the University of California.\n\
00037 All rights reserved.\n";
00038 #endif
00039
00040 #ifndef lint
00041 #ifdef ID
00042 static char sccsid[] = "@(#)rlogin.c 5.33 (Berkeley) 3/1/91";
00043 #endif
00044 #endif
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055 #include <sys/ioctl.h>
00056 #include <sys/types.h>
00057 #include <sys/wait.h>
00058
00059 #include <net/netlib.h>
00060 #include <net/hton.h>
00061 #include <net/gen/in.h>
00062 #include <net/gen/netdb.h>
00063 #include <net/gen/tcp.h>
00064 #include <net/gen/tcp_io.h>
00065
00066 #include <termios.h>
00067 #include <setjmp.h>
00068 #include <errno.h>
00069 #include <pwd.h>
00070 #include <stdio.h>
00071 #include <unistd.h>
00072 #include <string.h>
00073 #include <assert.h>
00074 #include <ctype.h>
00075 #include <fcntl.h>
00076 #include <signal.h>
00077 #include <stdlib.h>
00078
00079 #ifdef KERBEROS
00080 #include <kerberosIV/des.h>
00081 #include <kerberosIV/krb.h>
00082
00083 CREDENTIALS cred;
00084 Key_schedule schedule;
00085 int use_kerberos = 1, doencrypt;
00086 char dst_realm_buf[REALM_SZ], *dest_realm = NULL;
00087 extern char *krb_realmofhost();
00088 #endif
00089
00090 #ifndef TIOCPKT_WINDOW
00091 #define TIOCPKT_WINDOW 0x80
00092 #endif
00093
00094
00095 #ifndef SIGUSR1
00096 #define SIGUSR1 30
00097 #endif
00098
00099 extern int errno;
00100 int eight, litout, rem;
00101
00102 int noescape;
00103 u_char escapechar = '~';
00104
00105 struct speed
00106 {
00107 speed_t speed;
00108 char *name;
00109 } speeds[] = {
00110 { B0, "0" }, { B50, "50" }, { B75, "75" }, { B110, "110" },
00111 { B134, "134" }, { B150, "150" }, { B200, "200" }, { B300, "300" },
00112 { B600, "600" }, { B1200, "1200" }, { B1800, "1800" },
00113 { B2400, "2400" }, { B4800, "4800" }, { B9600, "9600" },
00114 { B19200, "19200" }, { B38400, "38400" }, { B57600, "57600" },
00115 { B115200, "115200" },
00116 { -1, NULL },
00117 };
00118
00119 #if __minix_vmd
00120
00121 int more2read_0;
00122 int inprogress_0;
00123 int more2write_1;
00124 int inprogress_1;
00125 int more2read_rem;
00126 int inprogress_rd_rem;
00127 int more2write_rem;
00128 int inprogress_wr_rem;
00129
00130
00131 size_t wr_rem_size;
00132 size_t wr_rem_offset;
00133 size_t extra_wr_rem_size;
00134 size_t extra_wr_rem_offset;
00135 char *extra_wr_rem;
00136 size_t extra_wr_rem_new_size;
00137 char *extra_wr_rem_new;
00138
00139 #endif
00140
00141 struct winsize winsize;
00142
00143 #define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp)
00144
00145 extern int main _ARGS(( int argc, char **argv ));
00146 static void usage _ARGS(( void ));
00147 static u_char getescape _ARGS(( char *p ));
00148 static char *speeds2str _ARGS(( speed_t speed ));
00149 static void lostpeer _ARGS(( int sig ));
00150 static void doit _ARGS(( void ));
00151 static void setsignal _ARGS(( int sig, void (*act)(int sig) ));
00152 static void msg _ARGS(( char *str ));
00153 static void done _ARGS(( int status ));
00154 #if !__minix_vmd
00155 static int reader _ARGS(( void ));
00156 #endif
00157 static void mode _ARGS(( int f ));
00158 #if __minix_vmd
00159 static void mark_async _ARGS(( int fd ));
00160 static void init_0 _ARGS(( void ));
00161 static void init_1 _ARGS(( void ));
00162 static void init_rd_rem _ARGS(( void ));
00163 static void init_wr_rem _ARGS(( void ));
00164 static void restart_0 _ARGS(( void ));
00165 static void restart_1 _ARGS(( void ));
00166 static void restart_rd_rem _ARGS(( void ));
00167 static void restart_wr_rem _ARGS(( void ));
00168 static void completed_0 _ARGS(( int result, int error ));
00169 static void completed_1 _ARGS(( int result, int error ));
00170 static void completed_rd_rem _ARGS(( int result, int error ));
00171 static void completed_wr_rem _ARGS(( int result, int error ));
00172 static void do_urg _ARGS(( int urg_byte ));
00173 #endif
00174 #if !__minix_vmd
00175 static void catch_child _ARGS(( int sig ));
00176 static void writer _ARGS(( void ));
00177 #endif
00178 static void echo _ARGS(( int c ));
00179 #if __minix_vmd
00180 static void finish _ARGS(( void ));
00181 static void sendwindow _ARGS(( void ));
00182 static void sigwinch _ARGS(( int sig ));
00183 static void subshell _ARGS(( void ));
00184 #endif
00185
00186 int main(argc, argv)
00187 int argc;
00188 char **argv;
00189 {
00190 extern char *optarg;
00191 extern int optind;
00192 struct passwd *pw;
00193 struct servent *sp;
00194 struct termios ttyb;
00195 nwio_tcpopt_t tcpopt;
00196 int error;
00197 int argoff, ch, dflag, one, uid;
00198 char *host, *p, *user, term[1024];
00199
00200 argoff = dflag = 0;
00201 one = 1;
00202 host = user = NULL;
00203
00204 if (p = rindex(argv[0], '/'))
00205 ++p;
00206 else
00207 p = argv[0];
00208
00209 if (strcmp(p, "rlogin"))
00210 host = p;
00211
00212
00213 if (!host && argc > 2 && argv[1][0] != '-') {
00214 host = argv[1];
00215 argoff = 1;
00216 }
00217
00218 #ifdef KERBEROS
00219 #define OPTIONS "8EKLde:k:l:x"
00220 #else
00221 #define OPTIONS "8EKLde:l:"
00222 #endif
00223 while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF)
00224 switch(ch) {
00225 case '8':
00226 eight = 1;
00227 break;
00228 case 'E':
00229 noescape = 1;
00230 break;
00231 case 'K':
00232 #ifdef KERBEROS
00233 use_kerberos = 0;
00234 #endif
00235 break;
00236 case 'L':
00237 litout = 1;
00238 break;
00239 case 'd':
00240 dflag = 1;
00241 break;
00242 case 'e':
00243 escapechar = getescape(optarg);
00244 break;
00245 #ifdef KERBEROS
00246 case 'k':
00247 dest_realm = dst_realm_buf;
00248 (void)strncpy(dest_realm, optarg, REALM_SZ);
00249 break;
00250 #endif
00251 case 'l':
00252 user = optarg;
00253 break;
00254 #ifdef CRYPT
00255 #ifdef KERBEROS
00256 case 'x':
00257 doencrypt = 1;
00258 des_set_key(cred.session, schedule);
00259 break;
00260 #endif
00261 #endif
00262 case '?':
00263 default:
00264 usage();
00265 }
00266 optind += argoff;
00267 argc -= optind;
00268 argv += optind;
00269
00270
00271 if (!host && !(host = *argv++))
00272 usage();
00273
00274 if (*argv)
00275 usage();
00276
00277 if (!(pw = getpwuid(uid = getuid()))) {
00278 (void)fprintf(stderr, "rlogin: unknown user id.\n");
00279 exit(1);
00280 }
00281 if (!user)
00282 user = pw->pw_name;
00283
00284 sp = NULL;
00285 #ifdef KERBEROS
00286 if (use_kerberos) {
00287 sp = getservbyname((doencrypt ? "eklogin" : "klogin"), "tcp");
00288 if (sp == NULL) {
00289 use_kerberos = 0;
00290 warning("can't get entry for %s/tcp service",
00291 doencrypt ? "eklogin" : "klogin");
00292 }
00293 }
00294 #endif
00295 if (sp == NULL)
00296 sp = getservbyname("login", "tcp");
00297 if (sp == NULL) {
00298 (void)fprintf(stderr, "rlogin: login/tcp: unknown service.\n");
00299 exit(1);
00300 }
00301
00302 (void)strncpy(term, (p = getenv("TERM")) ? p : "network", sizeof(term));
00303 term[sizeof(term)-1]= 0;
00304
00305 if (tcgetattr(0, &ttyb) == 0) {
00306 (void)strcat(term, "/");
00307 (void)strcat(term, speeds2str(cfgetospeed(&ttyb)));
00308 }
00309
00310 (void)get_window_size(0, &winsize);
00311
00312 (void)signal(SIGPIPE, lostpeer);
00313
00314 #ifdef KERBEROS
00315 try_connect:
00316 if (use_kerberos) {
00317 rem = KSUCCESS;
00318 errno = 0;
00319 if (dest_realm == NULL)
00320 dest_realm = krb_realmofhost(host);
00321
00322 #ifdef CRYPT
00323 if (doencrypt)
00324 rem = krcmd_mutual(&host, sp->s_port, user, term, 0,
00325 dest_realm, &cred, schedule);
00326 else
00327 #endif
00328 rem = krcmd(&host, sp->s_port, user, term, 0,
00329 dest_realm);
00330 if (rem < 0) {
00331 use_kerberos = 0;
00332 sp = getservbyname("login", "tcp");
00333 if (sp == NULL) {
00334 (void)fprintf(stderr,
00335 "rlogin: unknown service login/tcp.\n");
00336 exit(1);
00337 }
00338 if (errno == ECONNREFUSED)
00339 warning("remote host doesn't support Kerberos");
00340 if (errno == ENOENT)
00341 warning("can't provide Kerberos auth data");
00342 goto try_connect;
00343 }
00344 } else {
00345 #ifdef CRYPT
00346 if (doencrypt) {
00347 (void)fprintf(stderr,
00348 "rlogin: the -x flag requires Kerberos authentication.\n");
00349 exit(1);
00350 }
00351 #endif
00352 rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0);
00353 }
00354 #else
00355 rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0);
00356 #endif
00357
00358 if (rem < 0)
00359 exit(1);
00360
00361
00362 tcpopt.nwto_flags= NWTO_BSD_URG;
00363 error= ioctl(rem, NWIOSTCPOPT, &tcpopt);
00364 if (error == -1)
00365 {
00366 fprintf(stderr, "rlogin: NWIOSTCPOPT failed: %s\n",
00367 strerror(errno));
00368 }
00369
00370 (void)setuid(uid);
00371 doit();
00372
00373 }
00374
00375 struct termios defattr, rawattr;
00376 #if __minix_vmd
00377 int mustsendwindow;
00378 #else
00379 int child;
00380 #endif
00381
00382 static void
00383 doit()
00384 {
00385 struct termios sb;
00386 #if !__minix_vmd
00387 int r;
00388 #else
00389 asio_fd_set_t fd_set;
00390 struct fwait fw;
00391 int result;
00392 #endif
00393
00394 (void)tcgetattr(0, &sb);
00395 defattr = sb;
00396 rawattr = sb;
00397
00398 rawattr.c_iflag &= ~(ICRNL | IGNCR | INLCR | ISTRIP | IXOFF | IXON |
00399 PARMRK | IXANY);
00400 rawattr.c_oflag &= ~(OPOST);
00401 rawattr.c_lflag &= ~(ECHONL | ECHO | ICANON | IEXTEN | ISIG);
00402
00403 (void)signal(SIGINT, SIG_IGN);
00404 setsignal(SIGHUP, exit);
00405 setsignal(SIGQUIT, exit);
00406
00407 #if !__minix_vmd
00408 child = fork();
00409 if (child == -1) {
00410 (void)fprintf(stderr, "rlogin: fork: %s.\n", strerror(errno));
00411 done(1);
00412 }
00413 if (child == 0) {
00414 mode(1);
00415 r = reader();
00416 if (r == 0) {
00417 msg("connection closed.");
00418 exit(0);
00419 }
00420 sleep(1);
00421 msg("\007connection closed.");
00422 exit(1);
00423 }
00424
00425 (void)signal(SIGCHLD, catch_child);
00426 writer();
00427
00428 #else
00429
00430 mode(1);
00431
00432 mark_async(0);
00433 mark_async(1);
00434 mark_async(rem);
00435 init_0();
00436 init_1();
00437 init_rd_rem();
00438 init_wr_rem();
00439
00440 for (;;)
00441 {
00442 ASIO_FD_ZERO(&fd_set);
00443 fw.fw_flags= 0;
00444 fw.fw_bits= fd_set.afds_bits;
00445 fw.fw_maxfd= ASIO_FD_SETSIZE;
00446
00447 if (more2read_0 && !inprogress_0)
00448 {
00449 restart_0();
00450 fw.fw_flags |= FWF_NONBLOCK;
00451 }
00452
00453 if (more2write_1 && !inprogress_1)
00454 {
00455 restart_1();
00456 fw.fw_flags |= FWF_NONBLOCK;
00457 }
00458
00459 if (more2read_rem && !inprogress_rd_rem)
00460 {
00461 restart_rd_rem();
00462 fw.fw_flags |= FWF_NONBLOCK;
00463 }
00464
00465 if (more2write_rem && !inprogress_wr_rem)
00466 {
00467 restart_wr_rem();
00468 fw.fw_flags |= FWF_NONBLOCK;
00469 }
00470
00471 if (more2read_0 && inprogress_0)
00472 ASIO_FD_SET(0, ASIO_READ, &fd_set);
00473 if (more2write_1 && inprogress_1)
00474 ASIO_FD_SET(1, ASIO_WRITE, &fd_set);
00475 if (more2read_rem && inprogress_rd_rem)
00476 ASIO_FD_SET(rem, ASIO_READ, &fd_set);
00477 if (more2write_rem && inprogress_wr_rem)
00478 ASIO_FD_SET(rem, ASIO_WRITE, &fd_set);
00479
00480 for (;;)
00481 {
00482 result= fwait(&fw);
00483 if (result == -1 && (errno == EAGAIN ||
00484 errno == EINTR))
00485 {
00486 break;
00487 }
00488 if (result == -1)
00489 {
00490 fprintf(stderr, "fwait failed (%s)\n",
00491 strerror(errno));
00492 exit(1);
00493 }
00494 assert(result == 0);
00495 #if 0
00496 printf("fwait: fw_fw= %d, fw_operation= %d, fw_result= %d, fw.fw_errno= %d\n",
00497 fw.fw_fd, fw.fw_operation, fw.fw_result, fw.fw_errno);
00498 #endif
00499 if (fw.fw_fd == 0 && fw.fw_operation == ASIO_READ)
00500 {
00501 completed_0(fw.fw_result, fw.fw_errno);
00502 }
00503 else if (fw.fw_fd == 1 &&
00504 fw.fw_operation == ASIO_WRITE)
00505 {
00506 completed_1(fw.fw_result, fw.fw_errno);
00507 }
00508 else if (fw.fw_fd == rem &&
00509 fw.fw_operation == ASIO_READ)
00510 {
00511 completed_rd_rem(fw.fw_result, fw.fw_errno);
00512 }
00513 else if (fw.fw_fd == rem &&
00514 fw.fw_operation == ASIO_WRITE)
00515 {
00516 completed_wr_rem(fw.fw_result, fw.fw_errno);
00517 }
00518 else
00519 {
00520 fprintf(stderr,
00521 "strange result from fwait: fd= %d, operation= %d\n",
00522 fw.fw_fd, fw.fw_operation);
00523 exit(1);
00524 }
00525 if (!(fw.fw_flags & FWF_MORE))
00526 break;
00527 }
00528 if (mustsendwindow)
00529 {
00530 mustsendwindow= 0;
00531 sendwindow();
00532 }
00533 }
00534 #endif
00535 msg("connection closed.");
00536 done(0);
00537 }
00538
00539
00540 static void
00541 setsignal(sig, act)
00542 int sig;
00543 void (*act) _ARGS(( int sig ));
00544 {
00545 if (signal(sig, act) == SIG_IGN)
00546 (void)signal(sig, SIG_IGN);
00547 }
00548
00549 static void
00550 done(status)
00551 int status;
00552 {
00553 int w, wstatus;
00554
00555 mode(0);
00556 #if !__minix_vmd
00557 if (child > 0) {
00558
00559 (void)signal(SIGCHLD, SIG_DFL);
00560 if (kill(child, SIGKILL) >= 0)
00561 while ((w = wait(&wstatus)) > 0 && w != child);
00562 }
00563 #endif
00564 exit(status);
00565 }
00566
00567 int dosigwinch;
00568 #if !__minix
00569 void sigwinch();
00570 #endif
00571
00572 #if !__minix_vmd
00573 static void
00574 catch_child(sig)
00575 int sig;
00576 {
00577 int status;
00578 int pid;
00579
00580 for (;;) {
00581 pid = waitpid(-1, &status, WNOHANG|WUNTRACED);
00582 if (pid == 0)
00583 return;
00584
00585 if (pid < 0 || pid == child && !WIFSTOPPED(status))
00586 done(WTERMSIG(status) | WEXITSTATUS(status));
00587 }
00588
00589 }
00590 #endif
00591
00592 #if !__minix_vmd
00593
00594
00595
00596
00597
00598
00599 static void
00600 writer()
00601 {
00602 register int bol, local, n;
00603 u_char ch;
00604 int c;
00605
00606 bol = 1;
00607 local = 0;
00608 for (;;) {
00609 n = read(STDIN_FILENO, &ch, 1);
00610 if (n <= 0) {
00611 if (n < 0 && errno == EINTR)
00612 continue;
00613 break;
00614 }
00615 c = ch;
00616
00617
00618
00619
00620
00621
00622
00623 if (bol) {
00624 bol = 0;
00625 if (!noescape && c == escapechar) {
00626 local = 1;
00627 continue;
00628 }
00629 } else if (local) {
00630 local = 0;
00631 if (c == '.' || c == defattr.c_cc[VEOF]) {
00632 echo(c);
00633 break;
00634 }
00635 #if !__minix
00636 if (c == defattr.c_cc[VSUSP]) {
00637 bol = 1;
00638 echo(c);
00639 stop(c);
00640 continue;
00641 }
00642 #endif
00643 if (c != escapechar)
00644 #ifdef CRYPT
00645 #ifdef KERBEROS
00646 if (doencrypt)
00647 (void)des_write(rem, &escapechar, 1);
00648 else
00649 #endif
00650 #endif
00651 (void)write(rem, &escapechar, 1);
00652 }
00653
00654 ch = c;
00655 #ifdef CRYPT
00656 #ifdef KERBEROS
00657 if (doencrypt) {
00658 if (des_write(rem, &ch, 1) == 0) {
00659 msg("line gone");
00660 break;
00661 }
00662 } else
00663 #endif
00664 #endif
00665 if (write(rem, &ch, 1) == 0) {
00666 msg("line gone");
00667 break;
00668 }
00669 bol = c == defattr.c_cc[VKILL] ||
00670 c == defattr.c_cc[VEOF] ||
00671 c == defattr.c_cc[VINTR] ||
00672 c == defattr.c_cc[VSUSP] ||
00673 c == '\r' || c == '\n';
00674 }
00675 }
00676 #endif
00677
00678 #if !__minix_vmd
00679 static void
00680 echo(c)
00681 int c;
00682 {
00683 register char *p;
00684 char buf[8];
00685
00686 p = buf;
00687 c &= 0177;
00688 *p++ = escapechar;
00689 if (c < ' ') {
00690 *p++ = '^';
00691 *p++ = c + '@';
00692 } else if (c == 0177) {
00693 *p++ = '^';
00694 *p++ = '?';
00695 } else
00696 *p++ = c;
00697 *p++ = '\r';
00698 *p++ = '\n';
00699 (void)write(STDOUT_FILENO, buf, p - buf);
00700 }
00701 #endif
00702
00703 #if !__minix
00704 stop(cmdc)
00705 char cmdc;
00706 {
00707 mode(0);
00708 (void)signal(SIGCHLD, SIG_IGN);
00709 (void)kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP);
00710 (void)signal(SIGCHLD, catch_child);
00711 mode(1);
00712 sigwinch();
00713 }
00714 #endif
00715
00716 #if __minix_vmd
00717 #ifdef SIGWINCH
00718 static void
00719 sigwinch(sig)
00720 int sig;
00721 {
00722 struct winsize ws;
00723
00724 #if __minix
00725 signal(SIGWINCH, sigwinch);
00726 #endif
00727
00728 if (dosigwinch && get_window_size(0, &ws) == 0 &&
00729 memcmp(&ws, &winsize, sizeof(ws))) {
00730 winsize = ws;
00731 mustsendwindow= 1;
00732 }
00733 }
00734
00735
00736
00737
00738 static void
00739 sendwindow()
00740 {
00741 struct winsize *wp;
00742 char *obuf, *new_buf;
00743
00744 new_buf= realloc(extra_wr_rem_new,
00745 extra_wr_rem_new_size+4+sizeof(*wp));
00746 if (new_buf == 0)
00747 return;
00748 extra_wr_rem_new= new_buf;
00749 obuf= new_buf+extra_wr_rem_new_size;
00750 extra_wr_rem_new_size += 4+sizeof(*wp);
00751
00752 more2read_0= 0;
00753 more2write_rem= 1;
00754
00755 wp = (struct winsize *)(obuf+4);
00756 obuf[0] = 0377;
00757 obuf[1] = 0377;
00758 obuf[2] = 's';
00759 obuf[3] = 's';
00760 wp->ws_row = htons(winsize.ws_row);
00761 wp->ws_col = htons(winsize.ws_col);
00762 wp->ws_xpixel = htons(winsize.ws_xpixel);
00763 wp->ws_ypixel = htons(winsize.ws_ypixel);
00764 }
00765 #endif
00766 #endif
00767
00768 #if !__minix_vmd
00769
00770
00771
00772 #define READING 1
00773 #define WRITING 2
00774
00775 int rcvcnt, rcvstate;
00776 char rcvbuf[8 * 1024];
00777
00778 static int
00779 reader()
00780 {
00781 int pid = -getpid();
00782 int n, remaining;
00783 char *bufp = rcvbuf;
00784
00785 for (;;) {
00786 while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) {
00787 rcvstate = WRITING;
00788 n = write(STDOUT_FILENO, bufp, remaining);
00789 if (n < 0) {
00790 if (errno != EINTR)
00791 return(-1);
00792 continue;
00793 }
00794 bufp += n;
00795 }
00796 bufp = rcvbuf;
00797 rcvcnt = 0;
00798 rcvstate = READING;
00799
00800 #ifdef CRYPT
00801 #ifdef KERBEROS
00802 if (doencrypt)
00803 rcvcnt = des_read(rem, rcvbuf, sizeof(rcvbuf));
00804 else
00805 #endif
00806 #endif
00807 rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf));
00808 if (rcvcnt == 0)
00809 return (0);
00810 if (rcvcnt < 0) {
00811 if (errno == EINTR)
00812 continue;
00813 if (errno == EURG) {
00814 nwio_tcpopt_t tcpopt;
00815 #if DEBUG
00816 fprintf(stderr, "\n\rEURG\n\r");
00817 #endif
00818 tcpopt.nwto_flags= NWTO_RCV_URG;
00819 if (ioctl(rem, NWIOSTCPOPT, &tcpopt) == -1) {
00820 fprintf(stderr,
00821 "rlogin: trouble with urgent data: %s\n",
00822 strerror(errno));
00823 return(-1);
00824 }
00825 continue;
00826 }
00827 if (errno == ENOURG) {
00828 nwio_tcpopt_t tcpopt;
00829 #if DEBUG
00830 fprintf(stderr, "\n\rENOURG\n\r");
00831 #endif
00832 tcpopt.nwto_flags= NWTO_RCV_NOTURG;
00833 if (ioctl(rem, NWIOSTCPOPT, &tcpopt) == -1) {
00834 fprintf(stderr,
00835 "rlogin: trouble with not-urgent data: %s\n",
00836 strerror(errno));
00837 return(-1);
00838 }
00839 continue;
00840 }
00841 (void)fprintf(stderr, "rlogin: read: %s\n",
00842 strerror(errno));
00843 return(-1);
00844 }
00845 }
00846 }
00847 #endif
00848
00849 static void
00850 mode(f)
00851 int f;
00852 {
00853 struct termios *sb;
00854
00855 switch(f) {
00856 case 0:
00857 sb= &defattr;
00858 break;
00859 case 1:
00860 sb= &rawattr;
00861 break;
00862 default:
00863 return;
00864 }
00865 (void)tcsetattr(0, TCSAFLUSH, sb);
00866 }
00867
00868 static void
00869 lostpeer(sig)
00870 int sig;
00871 {
00872 (void)signal(SIGPIPE, SIG_IGN);
00873 msg("\007connection closed.");
00874 done(1);
00875 }
00876
00877 static void
00878 msg(str)
00879 char *str;
00880 {
00881 (void)fprintf(stderr, "rlogin: %s\r\n", str);
00882 }
00883
00884 #ifdef KERBEROS
00885
00886 warning(va_alist)
00887 va_dcl
00888 {
00889 va_list ap;
00890 char *fmt;
00891
00892 (void)fprintf(stderr, "rlogin: warning, using standard rlogin: ");
00893 va_start(ap);
00894 fmt = va_arg(ap, char *);
00895 vfprintf(stderr, fmt, ap);
00896 va_end(ap);
00897 (void)fprintf(stderr, ".\n");
00898 }
00899 #endif
00900
00901 static void
00902 usage()
00903 {
00904 (void)fprintf(stderr,
00905 "Usage: rlogin [-%s]%s[-e char] [-l username] host\n",
00906 #ifdef KERBEROS
00907 #ifdef CRYPT
00908 "8ELx", " [-k realm] ");
00909 #else
00910 "8EL", " [-k realm] ");
00911 #endif
00912 #else
00913 "8EL", " ");
00914 #endif
00915 exit(1);
00916 }
00917
00918
00919
00920
00921
00922 #ifdef sun
00923 get_window_size(fd, wp)
00924 int fd;
00925 struct winsize *wp;
00926 {
00927 struct ttysize ts;
00928 int error;
00929
00930 if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0)
00931 return(error);
00932 wp->ws_row = ts.ts_lines;
00933 wp->ws_col = ts.ts_cols;
00934 wp->ws_xpixel = 0;
00935 wp->ws_ypixel = 0;
00936 return(0);
00937 }
00938 #endif
00939
00940 static u_char
00941 getescape(p)
00942 register char *p;
00943 {
00944 long val;
00945 int len;
00946
00947 if ((len = strlen(p)) == 1)
00948 return((u_char)*p);
00949
00950 if (*p == '\\' && len >= 2 && len <= 4) {
00951 val = strtol(++p, (char **)NULL, 8);
00952 for (;;) {
00953 if (!*++p)
00954 return((u_char)val);
00955 if (*p < '0' || *p > '8')
00956 break;
00957 }
00958 }
00959 msg("illegal option value -- e");
00960 usage();
00961
00962 }
00963
00964 static char *
00965 speeds2str(speed)
00966 speed_t speed;
00967 {
00968 int i;
00969 for (i= 0; speeds[i].name != NULL && speeds[i].speed != speed; i++) {
00970 if (speeds[i].speed == speed) return speeds[i].name;
00971 }
00972 return "unknown";
00973 }
00974
00975 #if __minix_vmd
00976 static void
00977 mark_async(fd)
00978 int fd;
00979 {
00980 int result;
00981 int v;
00982
00983 result= fcntl(fd, F_GETFD);
00984 if (result == -1)
00985 {
00986 fprintf(stderr,
00987 "rlogin: mark_async: fcntl(%d, GETFD) failed (%s)\n",
00988 fd, strerror(errno));
00989 exit(1);
00990 }
00991 v= result | FD_ASYNCHIO;
00992 result= fcntl(fd, F_SETFD, v);
00993 if (result == -1)
00994 {
00995 fprintf(stderr,
00996 "rlogin: mark_async: fcntl(%d, SETFD, %d) failed (%s)\n",
00997 fd, v, strerror(errno));
00998 exit(1);
00999 }
01000 }
01001
01002 #define RD_0_BUFSIZE 256
01003 char rd_0_buf[RD_0_BUFSIZE];
01004 size_t rd_0_offset;
01005
01006 static void
01007 init_0()
01008 {
01009 more2read_0= 1;
01010 inprogress_0= 0;
01011 rd_0_offset= 0;
01012 }
01013
01014 size_t wr_1_size;
01015 size_t wr_1_offset;
01016 char *urg_1;
01017 size_t urg_1_size;
01018 char *extra_1;
01019 size_t extra_1_size;
01020 size_t extra_1_offset;
01021 char *extra_1_new;
01022 size_t extra_1_new_size;
01023 #define MAX_EXTRA_1_NEW_SIZE (16*1024)
01024
01025 static void
01026 init_1()
01027 {
01028 more2write_1= 0;
01029 inprogress_1= 0;
01030 wr_1_size= 0;
01031 wr_1_offset= 0;
01032 urg_1= NULL;
01033 urg_1_size= 0;
01034 extra_1= NULL;
01035 extra_1_size= 0;
01036 extra_1_offset= 0;
01037 extra_1_new= NULL;
01038 extra_1_new_size= 0;
01039 }
01040
01041 #define RD_REM_BUFSIZE (8*1024)
01042 char rd_rem_buf[RD_REM_BUFSIZE];
01043 size_t rd_rem_offset;
01044 int rd_rem_urg;
01045
01046 static void
01047 init_rd_rem()
01048 {
01049 more2read_rem= 1;
01050 inprogress_rd_rem= 0;
01051 rd_rem_offset= 0;
01052 rd_rem_urg= 0;
01053 }
01054
01055 static void
01056 init_wr_rem()
01057 {
01058 more2write_rem= 0;
01059 inprogress_wr_rem= 0;
01060 wr_rem_size= 0;
01061 wr_rem_offset= 0;
01062 extra_wr_rem_size= 0;
01063 extra_wr_rem_offset= 0;
01064 extra_wr_rem= NULL;
01065 extra_wr_rem_new_size= 0;
01066 extra_wr_rem_new= NULL;
01067 }
01068
01069 static void
01070 restart_0()
01071 {
01072 size_t offset;
01073 int result, error;
01074
01075 assert(!inprogress_0);
01076 rd_0_offset= 1;
01077 offset= 0;
01078 while (offset < RD_0_BUFSIZE)
01079 {
01080 result= read(0, rd_0_buf+rd_0_offset+offset,
01081 RD_0_BUFSIZE-rd_0_offset-offset);
01082 if (result > 0)
01083 {
01084 offset += result;
01085 assert(rd_0_offset+offset <= RD_0_BUFSIZE);
01086 continue;
01087 }
01088 error= errno;
01089
01090 if (offset != 0)
01091 completed_0(offset, 0);
01092 rd_0_offset += offset;
01093 if (result == -1 && error == EINPROGRESS)
01094 {
01095 inprogress_0= 1;
01096 return;
01097 }
01098 completed_0(result, error);
01099 return;
01100 }
01101 completed_0(offset, 0);
01102 }
01103
01104 static void
01105 restart_1()
01106 {
01107 size_t offset;
01108 int result, error;
01109
01110 assert(!inprogress_1);
01111
01112 while (extra_1 != NULL || extra_1_new != NULL)
01113 {
01114 if (extra_1 == NULL)
01115 {
01116 extra_1= extra_1_new;
01117 extra_1_new= NULL;
01118 extra_1_size= extra_1_new_size;
01119 extra_1_new_size= 0;
01120 extra_1_offset= 0;
01121 }
01122 offset= 0;
01123 #if DEBUG
01124 if (extra_1_size == 0)
01125 fprintf(stderr, "restart_1: extra_1_size= 0\n");
01126 #endif
01127 while (offset < extra_1_size)
01128 {
01129 result= write(1, extra_1+extra_1_offset+offset,
01130 extra_1_size-offset);
01131 if (result > 0)
01132 {
01133 assert (result <= extra_1_size-offset);
01134 offset += result;
01135 continue;
01136 }
01137 error= errno;
01138 if (offset != 0)
01139 completed_1(offset, 0);
01140
01141 if (result == -1 && errno == EINPROGRESS)
01142 {
01143 inprogress_1= 1;
01144 return;
01145 }
01146 completed_1(result, errno);
01147 return;
01148 }
01149 completed_1(offset, 0);
01150 }
01151
01152 offset= 0;
01153
01154 if (wr_1_size == 0)
01155 {
01156 more2write_1= 0;
01157 more2read_rem= 1;
01158 return;
01159 }
01160
01161 while (offset < wr_1_size)
01162 {
01163 result= write(1, rd_rem_buf+wr_1_offset+offset,
01164 wr_1_size-offset);
01165 if (result > 0)
01166 {
01167 assert (result <= wr_1_size-offset);
01168 offset += result;
01169 continue;
01170 }
01171 error= errno;
01172 if (offset != 0)
01173 completed_1(offset, 0);
01174
01175 if (result == -1 && errno == EINPROGRESS)
01176 {
01177 inprogress_1= 1;
01178 return;
01179 }
01180 completed_1(result, errno);
01181 return;
01182 }
01183 completed_1(offset, 0);
01184 }
01185
01186 static void
01187 restart_rd_rem()
01188 {
01189 size_t offset;
01190 int result, error;
01191
01192 assert(!inprogress_rd_rem);
01193 rd_rem_offset= 0;
01194 offset= 0;
01195 while (offset < RD_REM_BUFSIZE)
01196 {
01197 result= read(rem, rd_rem_buf+offset, RD_REM_BUFSIZE-offset);
01198 if (result > 0)
01199 {
01200 offset += result;
01201 assert(offset <= RD_REM_BUFSIZE);
01202 continue;
01203 }
01204 error= errno;
01205
01206 if (offset != 0)
01207 completed_rd_rem(offset, 0);
01208 rd_rem_offset= offset;
01209 if (result == -1 && error == EINPROGRESS)
01210 {
01211 inprogress_rd_rem= 1;
01212 return;
01213 }
01214 completed_rd_rem(result, error);
01215 return;
01216 }
01217 completed_rd_rem(offset, 0);
01218 }
01219
01220 static void
01221 restart_wr_rem()
01222 {
01223 size_t offset;
01224 int result, error;
01225
01226 assert(!inprogress_wr_rem);
01227
01228 if (extra_wr_rem_new != NULL && extra_wr_rem == NULL)
01229 {
01230 extra_wr_rem= extra_wr_rem_new;
01231 extra_wr_rem_size= extra_wr_rem_new_size;
01232 extra_wr_rem_offset= 0;
01233 extra_wr_rem_new= NULL;
01234 extra_wr_rem_new_size= 0;
01235 }
01236 if (extra_wr_rem != NULL)
01237 {
01238 offset= 0;
01239 while (offset < extra_wr_rem_size)
01240 {
01241 result= write(rem,
01242 extra_wr_rem+extra_wr_rem_offset+offset,
01243 extra_wr_rem_size-offset);
01244 if (result > 0)
01245 {
01246 assert (result <= extra_wr_rem_size-offset);
01247 offset += result;
01248 continue;
01249 }
01250 error= errno;
01251 if (offset != 0)
01252 completed_wr_rem(offset, 0);
01253
01254 if (result == -1 && errno == EINPROGRESS)
01255 {
01256 inprogress_wr_rem= 1;
01257 return;
01258 }
01259 completed_wr_rem(result, errno);
01260 return;
01261 }
01262 completed_wr_rem(offset, 0);
01263 }
01264 if (wr_rem_size == 0)
01265 return;
01266
01267 offset= 0;
01268 while (offset < wr_rem_size)
01269 {
01270 result= write(rem, rd_0_buf+wr_rem_offset+offset,
01271 wr_rem_size-offset);
01272 if (result > 0)
01273 {
01274 assert (result <= wr_rem_size-offset);
01275 offset += result;
01276 continue;
01277 }
01278 error= errno;
01279 if (offset != 0)
01280 completed_wr_rem(offset, 0);
01281
01282 if (result == -1 && errno == EINPROGRESS)
01283 {
01284 inprogress_wr_rem= 1;
01285 return;
01286 }
01287 completed_wr_rem(result, errno);
01288 return;
01289 }
01290 completed_wr_rem(offset, 0);
01291 }
01292
01293 static void
01294 completed_0(result, error)
01295 int result;
01296 int error;
01297 {
01298 static int bol= 0, local= 0;
01299
01300 char *iptr, *optr;
01301 int i;
01302 u_char c;
01303
01304 inprogress_0= 0;
01305
01306 if (result > 0)
01307 {
01308 assert(rd_0_offset > 0);
01309 wr_rem_offset= 1;
01310
01311 iptr= rd_0_buf+rd_0_offset;
01312 optr= rd_0_buf+wr_rem_offset;
01313 for (i= 0; i<result; iptr++, i++)
01314 {
01315 c= *iptr;
01316 if (bol)
01317 {
01318 bol= 0;
01319 if (!noescape && c == escapechar)
01320 {
01321 local= 1;
01322 continue;
01323 }
01324 }
01325 else if (local)
01326 {
01327 local= 0;
01328 if (c == '.' || (c != _POSIX_VDISABLE &&
01329 c == defattr.c_cc[VEOF]))
01330 {
01331 echo(c);
01332 finish();
01333
01334 }
01335 if (c == '!')
01336 {
01337 subshell();
01338 continue;
01339 }
01340 if (c != escapechar)
01341 {
01342 if (optr < iptr)
01343 {
01344 *(optr++)= escapechar;
01345 }
01346 else
01347 {
01348 assert(optr == iptr);
01349 assert(iptr == rd_0_buf+
01350 rd_0_offset);
01351 assert(rd_0_offset > 0);
01352 wr_rem_offset--;
01353 optr[-1]= escapechar;
01354 }
01355 }
01356 }
01357 *(optr++)= c;
01358 bol= (c != _POSIX_VDISABLE) &&
01359 (c == defattr.c_cc[VKILL] ||
01360 c == defattr.c_cc[VEOF] ||
01361 c == defattr.c_cc[VINTR] ||
01362 c == defattr.c_cc[VSUSP] ||
01363 c == '\r' || c == '\n');
01364 }
01365 wr_rem_size += optr-rd_0_buf-wr_rem_offset;
01366 if (wr_rem_size != 0)
01367 {
01368 more2read_0= 0;
01369 more2write_rem= 1;
01370 }
01371 return;
01372 } else
01373 if (result < 0) {
01374 fprintf(stderr, "rlogin: %s\n", strerror(error));
01375 }
01376 done(1);
01377 }
01378
01379 static void
01380 completed_1(result, error)
01381 int result;
01382 int error;
01383 {
01384 inprogress_1= 0;
01385
01386 if (result > 0)
01387 {
01388 if (extra_1 != NULL)
01389 {
01390 assert (result <= extra_1_size);
01391 extra_1_size -= result;
01392 extra_1_offset += result;
01393 if (extra_1_size == 0)
01394 {
01395 more2write_1= 0;
01396 more2read_rem= 1;
01397 free(extra_1);
01398 extra_1= NULL;
01399 }
01400 return;
01401 }
01402 assert (result <= wr_1_size);
01403 wr_1_size -= result;
01404 wr_1_offset += result;
01405 if (wr_1_size == 0)
01406 {
01407 more2write_1= 0;
01408 more2read_rem= 1;
01409 }
01410 return;
01411 } else
01412 if (result < 0) {
01413 fprintf(stderr, "rlogin: %s\n", strerror(error));
01414 }
01415 done(1);
01416 }
01417
01418 static void
01419 completed_rd_rem(result, error)
01420 int result;
01421 int error;
01422 {
01423 nwio_tcpopt_t tcpopt;
01424 char *new_buf;
01425 size_t keep_size;
01426 u_char urg_byte;
01427 int i;
01428
01429 inprogress_rd_rem= 0;
01430
01431 if (result > 0)
01432 {
01433 if (rd_rem_urg)
01434 {
01435 #if DEBUG
01436 fprintf(stderr, "\n\r%d urg bytes\n\r", result);
01437 #endif
01438 if (urg_1_size > MAX_EXTRA_1_NEW_SIZE)
01439 {
01440 keep_size= MAX_EXTRA_1_NEW_SIZE/2;
01441 memmove(urg_1, urg_1+urg_1_size-keep_size,
01442 keep_size);
01443 urg_1_size= keep_size;
01444 }
01445 new_buf= realloc(urg_1, urg_1_size+result);
01446 if (new_buf == NULL)
01447 {
01448 fprintf(stderr,
01449 "rlogin: warning realloc %d failed\n",
01450 urg_1_size+result);
01451 return;
01452 }
01453 memcpy(new_buf+urg_1_size,
01454 rd_rem_buf+rd_rem_offset, result);
01455 urg_1= new_buf;
01456 urg_1_size += result;
01457 return;
01458 }
01459 more2read_rem= 0;
01460 more2write_1= 1;
01461 wr_1_size= result;
01462 wr_1_offset= rd_rem_offset;
01463 return;
01464 }
01465 if (result == -1 && error == EURG)
01466 {
01467 #if DEBUG
01468 fprintf(stderr, "\n\rEURG\n\r");
01469 #endif
01470 rd_rem_urg= 1;
01471 tcpopt.nwto_flags= NWTO_RCV_URG;
01472 result= ioctl(rem, NWIOSTCPOPT, &tcpopt);
01473 if (result == -1)
01474 {
01475 fprintf(stderr,
01476 "rlogin: NWIOSTCPOPT on %d failed (%s)\n",
01477 rem, strerror(errno));
01478 exit(1);
01479 }
01480 return;
01481 }
01482 if (result == -1 && error == ENOURG)
01483 {
01484 #if DEBUG
01485 fprintf(stderr, "\n\rENOURG\n\r");
01486 #endif
01487 rd_rem_urg= 0;
01488 tcpopt.nwto_flags= NWTO_RCV_NOTURG;
01489 result= ioctl(rem, NWIOSTCPOPT, &tcpopt);
01490 if (result == -1)
01491 {
01492 fprintf(stderr,
01493 "rlogin: NWIOSTCPOPT on %d failed (%s)\n",
01494 rem, strerror(errno));
01495 exit(1);
01496 }
01497 if (urg_1_size != 0)
01498 {
01499 urg_byte= urg_1[urg_1_size-1];
01500 urg_1_size--;
01501 do_urg(urg_byte);
01502 if (urg_1_size == 0)
01503 return;
01504 if (extra_1_new_size + urg_1_size > MAX_EXTRA_1_NEW_SIZE)
01505 {
01506 extra_1_new_size= 0;
01507 free(extra_1_new);
01508 extra_1_new= NULL;
01509 }
01510 if (extra_1_new_size != 0)
01511 {
01512 new_buf= realloc(extra_1_new,
01513 extra_1_new_size+urg_1_size);
01514 if (new_buf == 0)
01515 {
01516 extra_1_new_size= 0;
01517 free(extra_1_new);
01518 extra_1_new= NULL;
01519 }
01520 else
01521 {
01522 extra_1_new= new_buf;
01523 memcpy(extra_1_new+extra_1_new_size,
01524 urg_1, urg_1_size);
01525 extra_1_new_size += urg_1_size;
01526 urg_1_size= 0;
01527 free(urg_1);
01528 urg_1= NULL;
01529 }
01530 }
01531 if (extra_1_new_size == 0)
01532 {
01533 extra_1_new_size= urg_1_size;
01534 extra_1_new= urg_1;
01535 urg_1_size= 0;
01536 urg_1= NULL;
01537 }
01538 more2read_rem= 0;
01539 more2write_1= 1;
01540 }
01541 return;
01542 }
01543 if (result == -1 && error == EINTR)
01544 {
01545
01546 return;
01547 }
01548 if (result == 0)
01549 {
01550 msg("connection closed.");
01551 done(0);
01552 }
01553 if (result < 0) {
01554 fprintf(stderr, "rlogin: %s\n", strerror(error));
01555 }
01556 done(1);
01557 }
01558
01559 static void
01560 completed_wr_rem(result, error)
01561 int result;
01562 int error;
01563 {
01564 inprogress_wr_rem= 0;
01565
01566 if (result > 0)
01567 {
01568 if (extra_wr_rem != NULL)
01569 {
01570 assert (result <= extra_wr_rem_size);
01571 extra_wr_rem_size -= result;
01572 extra_wr_rem_offset += result;
01573 if (extra_wr_rem_size == 0)
01574 {
01575 free(extra_wr_rem);
01576 extra_wr_rem= NULL;
01577 if (wr_rem_size == 0)
01578 {
01579 more2write_rem= 0;
01580 more2read_0= 1;
01581 }
01582 }
01583 return;
01584 }
01585
01586 assert (result <= wr_rem_size);
01587 wr_rem_size -= result;
01588 wr_rem_offset += result;
01589 if (wr_rem_size == 0)
01590 {
01591 more2write_rem= 0;
01592 more2read_0= 1;
01593 }
01594 return;
01595 }
01596 if (result < 0) {
01597 fprintf(stderr, "rlogin: %s\n", strerror(error));
01598 }
01599 done(1);
01600 }
01601
01602 static void
01603 do_urg(urg_byte)
01604 int urg_byte;
01605 {
01606 #if DEBUG
01607 fprintf(stderr, "rlogin: warning got urg_byte 0x%x\r\n", urg_byte);
01608 #endif
01609 if (urg_byte & TIOCPKT_WINDOW)
01610 {
01611 if (dosigwinch == 0)
01612 {
01613 sendwindow();
01614 signal(SIGWINCH, sigwinch);
01615 }
01616 dosigwinch= 1;
01617 }
01618 }
01619
01620 static void
01621 echo(c)
01622 int c;
01623 {
01624 u_char c1;
01625 char *new_buf;
01626
01627 new_buf= realloc(extra_1_new, extra_1_new_size+6);
01628 if (new_buf == NULL)
01629 return;
01630 extra_1_new= new_buf;
01631 new_buf= extra_1_new+extra_1_new_size;
01632
01633 c1= escapechar;
01634 if (c1 < ' ')
01635 {
01636 *new_buf++= '^';
01637 *new_buf++= c1 + '@';
01638 }
01639 else if (c1 == 0x7f)
01640 {
01641 *new_buf++= '^';
01642 *new_buf++= '?';
01643 }
01644 else
01645 *new_buf++= c1;
01646
01647 if (c < ' ')
01648 {
01649 *new_buf++= '^';
01650 *new_buf++= c + '@';
01651 }
01652 else if (c == 0x7f)
01653 {
01654 *new_buf++= '^';
01655 *new_buf++= '?';
01656 }
01657 else
01658 *new_buf++= c;
01659
01660 *new_buf++= '\r';
01661 *new_buf++= '\n';
01662 extra_1_new_size= new_buf-extra_1_new;
01663 more2write_1= 1;
01664 }
01665
01666 static void
01667 finish()
01668 {
01669 done(0);
01670 }
01671
01672 static char cmdbuf[256];
01673
01674 static void
01675 subshell()
01676 {
01677
01678
01679
01680
01681 int r, pid, stat, len;
01682 char *shell, *cmd;
01683
01684
01685 if (inprogress_0)
01686 {
01687 r= fcancel(0, ASIO_READ);
01688 if (r != 0) abort();
01689 }
01690 if (inprogress_1)
01691 {
01692 r= fcancel(1, ASIO_WRITE);
01693 if (r != 0) abort();
01694 }
01695 if (inprogress_rd_rem)
01696 {
01697 r= fcancel(rem, ASIO_READ);
01698 if (r != 0) abort();
01699 }
01700 if (inprogress_wr_rem)
01701 {
01702 r= fcancel(rem, ASIO_WRITE);
01703 if (r != 0) abort();
01704 }
01705
01706 mode(0);
01707
01708 pid= fork();
01709 if (pid == -1) abort();
01710 if (pid != 0)
01711 {
01712 r= waitpid(pid, &stat, 0);
01713 if (r != pid) abort();
01714
01715 #if DEBUG
01716 fprintf(stderr, "stat: 0x%x\n", stat);
01717 #endif
01718 mode(1);
01719 return;
01720 }
01721
01722 (void)signal(SIGINT, SIG_DFL);
01723
01724 shell= getenv("SHELL");
01725 if (shell == NULL)
01726 shell= "/bin/sh";
01727 printf("~!\ncommand [%s]: ", shell);
01728 cmd= fgets(cmdbuf, sizeof(cmdbuf), stdin);
01729 if (cmd == NULL)
01730 exit(0);
01731 #if DEBUG
01732 printf("got command '%s'\n", cmd);
01733 #endif
01734
01735
01736 len= strlen(cmd);
01737 if (len > 0 && cmd[len-1] == '\n')
01738 cmd[len-1]= '\0';
01739 else
01740 printf("\n");
01741
01742
01743 while (*cmd != '\0' && isspace(*cmd))
01744 cmd++;
01745
01746 if (*cmd == '+')
01747 {
01748 if (rem != 3)
01749 {
01750 dup2(rem, 3);
01751 close(rem);
01752 }
01753 cmd++;
01754 }
01755 else if (*cmd == '=')
01756 {
01757 dup2(rem, 0);
01758 dup2(rem, 1);
01759 close(rem);
01760 cmd++;
01761 }
01762 else
01763 close(rem);
01764 if (*cmd == '\0')
01765 {
01766 r= execl(shell, shell, NULL);
01767 }
01768 else
01769 {
01770 r= execl("/bin/sh", "sh", "-c", cmd, NULL);
01771 }
01772 printf("exec failed: %d, %d\n", r, errno);
01773 exit(0);
01774 }
01775 #endif