|
|
1.1 root 1: /* cusub.c
2: System dependent routines for cu.
3:
4: Copyright (C) 1992 Ian Lance Taylor
5:
6: This file is part of the Taylor UUCP package.
7:
8: This program is free software; you can redistribute it and/or
9: modify it under the terms of the GNU General Public License as
10: published by the Free Software Foundation; either version 2 of the
11: License, or (at your option) any later version.
12:
13: This program is distributed in the hope that it will be useful, but
14: WITHOUT ANY WARRANTY; without even the implied warranty of
15: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16: General Public License for more details.
17:
18: You should have received a copy of the GNU General Public License
19: along with this program; if not, write to the Free Software
20: Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21:
22: The author of the program may be contacted at [email protected] or
23: c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
24: */
25:
26: #include "uucp.h"
27:
28: #if USE_RCS_ID
29: const char cusub_rcsid[] = "$Id: cusub.c,v 1.1 93/07/30 08:02:24 bin Exp Locker: bin $";
30: #endif
31:
32: #include "uudefs.h"
33: #include "uuconf.h"
34: #include "sysdep.h"
35: #include "system.h"
36: #include "cu.h"
37: #include "conn.h"
38: #include "prot.h"
39:
40: #include <errno.h>
41:
42: /* Get definitions for EAGAIN, EWOULDBLOCK and ENODATA. */
43: #ifndef EAGAIN
44: #ifndef EWOULDBLOCK
45: #define EAGAIN (-1)
46: #define EWOULDBLOCK (-1)
47: #else /* defined (EWOULDBLOCK) */
48: #define EAGAIN EWOULDBLOCK
49: #endif /* defined (EWOULDBLOCK) */
50: #else /* defined (EAGAIN) */
51: #ifndef EWOULDBLOCK
52: #define EWOULDBLOCK EAGAIN
53: #endif /* ! defined (EWOULDBLOCK) */
54: #endif /* defined (EAGAIN) */
55:
56: #ifndef ENODATA
57: #define ENODATA EAGAIN
58: #endif
59:
60: /* Local variables. */
61:
62: /* The EOF character, as set by fsysdep_terminal_raw. */
63: static char bSeof;
64:
65: /* The SUSP character, as set by fsysdep_terminal_raw. */
66: static char bStstp;
67:
68: /* Local functions. */
69:
70: static const char *zsport_line P((const struct uuconf_port *qport));
71: static void uscu_child P((struct sconnection *qconn, int opipe));
72: static RETSIGTYPE uscu_alarm P((int isig));
73: static int cscu_escape P((char *pbcmd, const char *zlocalname));
74: static RETSIGTYPE uscu_alarm_kill P((int isig));
75:
76: /* Return the device name for a port, or NULL if none. */
77:
78: static const char *
79: zsport_line (qport)
80: const struct uuconf_port *qport;
81: {
82: const char *zline;
83:
84: if (qport == NULL)
85: return NULL;
86:
87: switch (qport->uuconf_ttype)
88: {
89: default:
90: case UUCONF_PORTTYPE_STDIN:
91: return NULL;
92: case UUCONF_PORTTYPE_MODEM:
93: zline = qport->uuconf_u.uuconf_smodem.uuconf_zdevice;
94: break;
95: case UUCONF_PORTTYPE_DIRECT:
96: zline = qport->uuconf_u.uuconf_sdirect.uuconf_zdevice;
97: break;
98: case UUCONF_PORTTYPE_TCP:
99: case UUCONF_PORTTYPE_TLI:
100: return NULL;
101: }
102:
103: if (zline == NULL)
104: zline = qport->uuconf_zname;
105: return zline;
106: }
107:
108: /* Check whether the user has legitimate access to a port. */
109:
110: boolean
111: fsysdep_port_access (qport)
112: struct uuconf_port *qport;
113: {
114: const char *zline;
115: char *zfree;
116: boolean fret;
117:
118: zline = zsport_line (qport);
119: if (zline == NULL)
120: return TRUE;
121:
122: zfree = NULL;
123: if (*zline != '/')
124: {
125: zfree = zbufalc (sizeof "/dev/" + strlen (zline));
126: sprintf (zfree, "/dev/%s", zline);
127: zline = zfree;
128: }
129:
130: fret = access (zline, R_OK | W_OK) == 0;
131: ubuffree (zfree);
132: return fret;
133: }
134:
135: /* Return whether the given port is named by the given line. */
136:
137: boolean
138: fsysdep_port_is_line (qport, zline)
139: struct uuconf_port *qport;
140: const char *zline;
141: {
142: const char *zpline;
143: char *zfree1, *zfree2;
144: boolean fret;
145:
146: zpline = zsport_line (qport);
147: if (zpline == NULL)
148: return FALSE;
149:
150: if (strcmp (zline, zpline) == 0)
151: return TRUE;
152:
153: zfree1 = NULL;
154: zfree2 = NULL;
155: if (*zline != '/')
156: {
157: zfree1 = zbufalc (sizeof "/dev/" + strlen (zline));
158: sprintf (zfree1, "/dev/%s", zline);
159: zline = zfree1;
160: }
161: if (*zpline != '/')
162: {
163: zfree2 = zbufalc (sizeof "/dev/" + strlen (zpline));
164: sprintf (zfree2, "/dev/%s", zpline);
165: zpline = zfree2;
166: }
167:
168: fret = strcmp (zline, zpline) == 0;
169: ubuffree (zfree1);
170: ubuffree (zfree2);
171: return fret;
172: }
173:
174: /* The cu program wants the system dependent layer to handle the
175: details of copying data from the communications port to the
176: terminal. This copying need only be done while executing
177: fsysdep_cu. On Unix, however, we set up a subprocess to do it all
178: the time. This subprocess must be controllable via the
179: fsysdep_cu_copy function.
180:
181: We keep a pipe open to the subprocess. When we want it to stop we
182: send it a signal, and then wait for it to write a byte to us over
183: the pipe. */
184:
185: /* The subprocess pid. */
186: static volatile pid_t iSchild;
187:
188: /* The pipe from the subprocess. */
189: static int oSpipe;
190:
191: /* When we tell the child to stop, it sends this. */
192: #define CHILD_STOPPED ('S')
193:
194: /* When we tell the child to start, it sends this. */
195: #define CHILD_STARTED ('G')
196:
197: /* Initialize the subprocess, and have it start copying data. */
198:
199: boolean
200: fsysdep_cu_init (qconn)
201: struct sconnection *qconn;
202: {
203: int ai[2];
204:
205: /* Write out anything we may have buffered up during the chat
206: script. We do this before forking the child only to make it easy
207: to move the child into a separate executable. */
208: while (iPrecend != iPrecstart)
209: {
210: char *z;
211: int c;
212:
213: z = abPrecbuf + iPrecstart;
214: if (iPrecend > iPrecstart)
215: c = iPrecend - iPrecstart;
216: else
217: c = CRECBUFLEN - iPrecstart;
218:
219: iPrecstart = (iPrecstart + c) % CRECBUFLEN;
220:
221: while (c > 0)
222: {
223: int cwrote;
224:
225: cwrote = write (1, z, c);
226: if (cwrote <= 0)
227: {
228: if (cwrote < 0)
229: ulog (LOG_ERROR, "write: %s", strerror (errno));
230: else
231: ulog (LOG_ERROR, "Line disconnected");
232: return FALSE;
233: }
234: c -= cwrote;
235: z += cwrote;
236: }
237: }
238:
239: if (pipe (ai) < 0)
240: {
241: ulog (LOG_ERROR, "pipe: %s", strerror (errno));
242: return FALSE;
243: }
244:
245: iSchild = ixsfork ();
246: if (iSchild < 0)
247: {
248: ulog (LOG_ERROR, "fork: %s", strerror (errno));
249: return FALSE;
250: }
251:
252: if (iSchild == 0)
253: {
254: (void) close (ai[0]);
255: uscu_child (qconn, ai[1]);
256: /*NOTREACHED*/
257: }
258:
259: (void) close (ai[1]);
260:
261: oSpipe = ai[0];
262:
263: return TRUE;
264: }
265:
266: /* Copy all data from the terminal to the communications port. If we
267: see an escape character following a newline character, read the
268: next character and return it. */
269:
270: boolean
271: fsysdep_cu (qconn, pbcmd, zlocalname)
272: struct sconnection *qconn;
273: char *pbcmd;
274: const char *zlocalname;
275: {
276: boolean fstart;
277: char b;
278: int c;
279:
280: fstart = TRUE;
281:
282: while (TRUE)
283: {
284: if (fsysdep_catch ())
285: usysdep_start_catch ();
286: else
287: {
288: ulog (LOG_ERROR, (const char *) NULL);
289: return FALSE;
290: }
291:
292: c = read (0, &b, 1);
293:
294: usysdep_end_catch ();
295:
296: if (c <= 0)
297: break;
298:
299: if (fstart && b == *zCuvar_escape)
300: {
301: c = cscu_escape (pbcmd, zlocalname);
302: if (c <= 0)
303: break;
304: if (*pbcmd != b)
305: {
306: write (1, pbcmd, 1);
307:
308: /* For Unix, we let the eof character be the same as
309: '.', and we let the suspend character (if any) be the
310: same as 'z'. */
311: if (*pbcmd == bSeof)
312: *pbcmd = '.';
313: if (*pbcmd == bStstp)
314: *pbcmd = 'z';
315: return TRUE;
316: }
317: }
318: if (! fconn_write (qconn, &b, (size_t) 1))
319: return FALSE;
320: fstart = strchr (zCuvar_eol, b) != NULL;
321: }
322:
323: if (c < 0)
324: {
325: if (errno != EINTR)
326: ulog (LOG_ERROR, "read: %s", strerror (errno));
327: else
328: ulog (LOG_ERROR, (const char *) NULL);
329: return FALSE;
330: }
331:
332: /* I'm not sure what's best in this case. */
333: ulog (LOG_ERROR, "End of file on terminal");
334: return FALSE;
335: }
336:
337: /* A SIGALRM handler that sets fScu_alarm and optionally longjmps. */
338:
339: volatile sig_atomic_t fScu_alarm;
340:
341: static RETSIGTYPE
342: uscu_alarm (isig)
343: int isig;
344: {
345: #if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET
346: (void) signal (isig, uscu_alarm);
347: #endif
348:
349: fScu_alarm = TRUE;
350:
351: #if HAVE_RESTARTABLE_SYSCALLS
352: if (fSjmp)
353: longjmp (sSjmp_buf, 1);
354: #endif
355: }
356:
357: /* We've just seen an escape character. We print the host name,
358: optionally after a 1 second delay. We read the next character from
359: the terminal and return it. The 1 second delay on the host name is
360: mostly to be fancy; it lets ~~ look smoother. */
361:
362: static int
363: cscu_escape (pbcmd, zlocalname)
364: char *pbcmd;
365: const char *zlocalname;
366: {
367: CATCH_PROTECT int c;
368:
369: write (1, zCuvar_escape, 1);
370:
371: fScu_alarm = FALSE;
372: usset_signal (SIGALRM, uscu_alarm, TRUE, (boolean *) NULL);
373:
374: if (fsysdep_catch ())
375: {
376: usysdep_start_catch ();
377: alarm (1);
378: }
379:
380: c = 0;
381:
382: while (TRUE)
383: {
384: if (fScu_alarm)
385: {
386: char b;
387:
388: fScu_alarm = FALSE;
389: b = '[';
390: write (1, &b, 1);
391: write (1, zlocalname, strlen (zlocalname));
392: b = ']';
393: write (1, &b, 1);
394: }
395:
396: if (c <= 0)
397: c = read (0, pbcmd, 1);
398: if (c >= 0 || errno != EINTR)
399: {
400: usysdep_end_catch ();
401: usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
402: alarm (0);
403: return c;
404: }
405: }
406: }
407:
408: /* A SIGALRM handler which does nothing but send a signal to the child
409: process and schedule another alarm. POSIX.1 permits kill and alarm
410: from a signal handler. The reference to static data may or may not
411: be permissible. */
412:
413: static volatile sig_atomic_t iSsend_sig;
414:
415: static RETSIGTYPE
416: uscu_alarm_kill (isig)
417: int isig;
418: {
419: #if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET
420: (void) signal (isig, uscu_alarm_kill);
421: #endif
422:
423: (void) kill (iSchild, iSsend_sig);
424:
425: alarm (1);
426: }
427:
428: /* Start or stop copying data from the communications port to the
429: terminal. We send a signal to the child process to tell it what to
430: do. Unfortunately, there are race conditions in the child, so we
431: keep sending it a signal once a second until it responds. We send
432: SIGUSR1 to make it start copying, and SIGUSR2 to make it stop. */
433:
434: boolean
435: fsysdep_cu_copy (fcopy)
436: boolean fcopy;
437: {
438: int ierr;
439: int c;
440:
441: usset_signal (SIGALRM, uscu_alarm_kill, TRUE, (boolean *) NULL);
442: if (fcopy)
443: iSsend_sig = SIGUSR1;
444: else
445: iSsend_sig = SIGUSR2;
446:
447: uscu_alarm_kill (SIGALRM);
448:
449: alarm (1);
450:
451: while (TRUE)
452: {
453: char b;
454:
455: c = read (oSpipe, &b, 1);
456:
457: #if DEBUG > 1
458: if (c > 0)
459: DEBUG_MESSAGE1 (DEBUG_INCOMING,
460: "fsysdep_cu_copy: Got '%d'", b);
461: #endif
462:
463: if ((c < 0 && errno != EINTR)
464: || c == 0
465: || (c > 0 && b == (fcopy ? CHILD_STARTED : CHILD_STOPPED)))
466: break;
467:
468: /* If none of the above conditions were true, then we either got
469: an EINTR error, in which case we probably timed out and the
470: SIGALRM handler resent the signal, or we read the wrong
471: character, in which case we will just read again from the
472: pipe. */
473: }
474:
475: ierr = errno;
476:
477: usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
478: alarm (0);
479:
480: if (c > 0)
481: return TRUE;
482:
483: if (c == 0)
484: ulog (LOG_ERROR, "EOF on child pipe");
485: else
486: ulog (LOG_ERROR, "read: %s", strerror (ierr));
487:
488: return FALSE;
489: }
490:
491: /* Shut down cu by killing the child process. */
492:
493: boolean
494: fsysdep_cu_finish ()
495: {
496: (void) close (oSpipe);
497:
498: /* We hit the child with SIGTERM, give it two seconds to die, and
499: then send a SIGKILL. */
500: if (kill (iSchild, SIGTERM) < 0)
501: {
502: /* Don't give an error if the child has already died. */
503: if (errno != ESRCH)
504: ulog (LOG_ERROR, "kill: %s", strerror (errno));
505: }
506:
507: usset_signal (SIGALRM, uscu_alarm_kill, TRUE, (boolean *) NULL);
508: iSsend_sig = SIGKILL;
509: alarm (2);
510:
511: (void) ixswait ((unsigned long) iSchild, "child");
512:
513: usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
514: alarm (0);
515:
516: return TRUE;
517: }
518:
519: /* Code for the child process. */
520:
521: /* This signal handler just records the signal. In this case we only
522: care about which signal we received most recently. */
523:
524: static volatile sig_atomic_t iSchild_sig;
525:
526: static RETSIGTYPE
527: uscu_child_handler (isig)
528: int isig;
529: {
530: #if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET
531: (void) signal (isig, uscu_child_handler);
532: #endif
533:
534: iSchild_sig = isig;
535:
536: #if HAVE_RESTARTABLE_SYSCALLS
537: if (fSjmp)
538: longjmp (sSjmp_buf, 1);
539: #endif /* HAVE_RESTARTABLE_SYSCALLS */
540: }
541:
542: /* The child process. This copies the port to the terminal, except
543: when it is stopped by a signal. It would be reasonable to write a
544: separate program for this, probably passing it the port on stdin.
545: This would reduce the memory requirements, since we wouldn't need a
546: second process holding all the configuration stuff, and also let it
547: work reasonably on 680x0 versions of MINIX. */
548:
549: static void
550: uscu_child (qconn, opipe)
551: struct sconnection *qconn;
552: int opipe;
553: {
554: CATCH_PROTECT int oport;
555: CATCH_PROTECT boolean fstopped, fgot;
556: CATCH_PROTECT int cwrite;
557: CATCH_PROTECT char abbuf[1024];
558:
559: /* It would be nice if we could just use fsserial_read, but that
560: will log signals that we don't want logged. There should be a
561: generic way to extract the file descriptor from the port. */
562: if (qconn->qport == NULL)
563: oport = 0;
564: else
565: {
566: switch (qconn->qport->uuconf_ttype)
567: {
568: #if DEBUG > 0
569: default:
570: ulog (LOG_FATAL, "uscu_child: Can't happen");
571: oport = -1;
572: break;
573: #endif
574: case UUCONF_PORTTYPE_STDIN:
575: oport = 0;
576: break;
577: case UUCONF_PORTTYPE_MODEM:
578: case UUCONF_PORTTYPE_DIRECT:
579: case UUCONF_PORTTYPE_TCP:
580: case UUCONF_PORTTYPE_TLI:
581: oport = ((struct ssysdep_conn *) qconn->psysdep)->o;
582: break;
583: }
584: }
585:
586: usset_signal (SIGUSR1, uscu_child_handler, TRUE, (boolean *) NULL);
587: usset_signal (SIGUSR2, uscu_child_handler, TRUE, (boolean *) NULL);
588: usset_signal (SIGINT, SIG_IGN, TRUE, (boolean *) NULL);
589: usset_signal (SIGQUIT, SIG_IGN, TRUE, (boolean *) NULL);
590: usset_signal (SIGPIPE, SIG_DFL, TRUE, (boolean *) NULL);
591: usset_signal (SIGTERM, uscu_child_handler, TRUE, (boolean *) NULL);
592:
593: fstopped = FALSE;
594: fgot = FALSE;
595: iSchild_sig = 0;
596: cwrite = 0;
597:
598: if (fsysdep_catch ())
599: usysdep_start_catch ();
600:
601: while (TRUE)
602: {
603: int isig;
604: int c;
605:
606: /* There is a race condition here between checking the signal
607: and receiving a new and possibly different one. This is
608: solved by having the parent resend the signal until it gets a
609: response. */
610: isig = iSchild_sig;
611: iSchild_sig = 0;
612: if (isig != 0)
613: {
614: char b;
615:
616: if (isig == SIGTERM)
617: exit (EXIT_SUCCESS);
618:
619: if (isig == SIGUSR1)
620: {
621: fstopped = FALSE;
622: b = CHILD_STARTED;
623: }
624: else
625: {
626: fstopped = TRUE;
627: b = CHILD_STOPPED;
628: cwrite = 0;
629: }
630:
631: c = write (opipe, &b, 1);
632:
633: /* Apparently on some systems we can get EAGAIN here. */
634: if (c < 0 &&
635: (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENODATA))
636: c = 0;
637:
638: if (c <= 0)
639: {
640: /* Should we give an error message here? */
641: (void) kill (getppid (), SIGHUP);
642: exit (EXIT_FAILURE);
643: }
644: }
645:
646: if (fstopped)
647: pause ();
648: else if (cwrite > 0)
649: {
650: char *zbuf;
651:
652: zbuf = abbuf;
653: while (cwrite > 0)
654: {
655: c = write (1, zbuf, cwrite);
656:
657: /* Apparently on some systems we can get EAGAIN here. */
658: if (c < 0 &&
659: (errno == EAGAIN
660: || errno == EWOULDBLOCK
661: || errno == ENODATA))
662: c = 0;
663:
664: if (c < 0 && errno == EINTR)
665: break;
666: if (c <= 0)
667: {
668: /* Should we give an error message here? */
669: (void) kill (getppid (), SIGHUP);
670: exit (EXIT_FAILURE);
671: }
672: cwrite -= c;
673: zbuf += c;
674: }
675: }
676: else
677: {
678: /* On some systems apparently read will return 0 until
679: something has been written to the port. We therefore
680: accept a 0 return until after we have managed to read
681: something. Setting errno to 0 apparently avoids a
682: problem on Coherent. */
683: errno = 0;
684: c = read (oport, abbuf, sizeof abbuf);
685:
686: /* Apparently on some systems we can get EAGAIN here. */
687: if (c < 0 &&
688: (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENODATA))
689: c = 0;
690:
691: if ((c == 0 && fgot)
692: || (c < 0 && errno != EINTR))
693: {
694: /* This can be a normal way to exit, depending on just
695: how the connection is dropped. */
696: (void) kill (getppid (), SIGHUP);
697: exit (EXIT_SUCCESS);
698: }
699: if (c > 0)
700: {
701: fgot = TRUE;
702: cwrite = c;
703: }
704: }
705: }
706: }
707:
708: /* Terminal control routines. */
709:
710: /* Whether file descriptor 0 is attached to a terminal or not. */
711: static boolean fSterm;
712:
713: /* Whether we are doing local echoing. */
714: static boolean fSlocalecho;
715:
716: /* The original state of the terminal. */
717: static sterminal sSterm_orig;
718:
719: /* The new state of the terminal. */
720: static sterminal sSterm_new;
721:
722: #if ! HAVE_BSD_TTY
723: #ifdef SIGTSTP
724: /* Whether SIGTSTP is being ignored. */
725: static boolean fStstp_ignored;
726: #endif
727: #endif
728:
729: /* Set the terminal into raw mode. */
730:
731: boolean
732: fsysdep_terminal_raw (flocalecho)
733: boolean flocalecho;
734: {
735: fSlocalecho = flocalecho;
736:
737: /* This defaults may be overriden below. */
738: bSeof = '\004';
739: bStstp = '\032';
740:
741: if (! fgetterminfo (0, &sSterm_orig))
742: {
743: fSterm = FALSE;
744: return TRUE;
745: }
746:
747: fSterm = TRUE;
748:
749: sSterm_new = sSterm_orig;
750:
751: #if HAVE_BSD_TTY
752:
753: /* We use CBREAK mode rather than RAW mode, because RAW mode turns
754: off all output processing, which we don't want to do. This means
755: that we have to disable the interrupt characters, which we do by
756: setting them to -1. */
757: bSeof = sSterm_orig.stchars.t_eofc;
758:
759: sSterm_new.stchars.t_intrc = -1;
760: sSterm_new.stchars.t_quitc = -1;
761: sSterm_new.stchars.t_startc = -1;
762: sSterm_new.stchars.t_stopc = -1;
763: sSterm_new.stchars.t_eofc = -1;
764: sSterm_new.stchars.t_brkc = -1;
765:
766: bStstp = sSterm_orig.sltchars.t_suspc;
767:
768: sSterm_new.sltchars.t_suspc = -1;
769: sSterm_new.sltchars.t_dsuspc = -1;
770: sSterm_new.sltchars.t_rprntc = -1;
771: sSterm_new.sltchars.t_flushc = -1;
772: sSterm_new.sltchars.t_werasc = -1;
773: sSterm_new.sltchars.t_lnextc = -1;
774:
775: if (! flocalecho)
776: {
777: sSterm_new.stty.sg_flags |= (CBREAK | ANYP);
778: sSterm_new.stty.sg_flags &=~ (ECHO | CRMOD | TANDEM);
779: }
780: else
781: {
782: sSterm_new.stty.sg_flags |= (CBREAK | ANYP | ECHO);
783: sSterm_new.stty.sg_flags &=~ (CRMOD | TANDEM);
784: }
785:
786: #endif /* HAVE_BSD_TTY */
787:
788: #if HAVE_SYSV_TERMIO
789:
790: bSeof = sSterm_new.c_cc[VEOF];
791: if (! flocalecho)
792: sSterm_new.c_lflag &=~ (ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHONL);
793: else
794: sSterm_new.c_lflag &=~ (ICANON | ISIG);
795: sSterm_new.c_iflag &=~ (INLCR | IGNCR | ICRNL);
796: sSterm_new.c_oflag &=~ (OPOST);
797: sSterm_new.c_cc[VMIN] = 1;
798: sSterm_new.c_cc[VTIME] = 0;
799:
800: #endif /* HAVE_SYSV_TERMIO */
801:
802: #if HAVE_POSIX_TERMIOS
803:
804: bSeof = sSterm_new.c_cc[VEOF];
805: bStstp = sSterm_new.c_cc[VSUSP];
806: if (! flocalecho)
807: sSterm_new.c_lflag &=~
808: (ICANON | IEXTEN | ISIG | ECHO | ECHOE | ECHOK | ECHONL);
809: else
810: sSterm_new.c_lflag &=~ (ICANON | IEXTEN | ISIG);
811: sSterm_new.c_iflag &=~ (INLCR | IGNCR | ICRNL);
812: sSterm_new.c_oflag &=~ (OPOST);
813: sSterm_new.c_cc[VMIN] = 1;
814: sSterm_new.c_cc[VTIME] = 0;
815:
816: #endif /* HAVE_POSIX_TERMIOS */
817:
818: if (! fsetterminfo (0, &sSterm_new))
819: {
820: ulog (LOG_ERROR, "Can't set terminal settings: %s", strerror (errno));
821: return FALSE;
822: }
823:
824: return TRUE;
825: }
826:
827: /* Restore the terminal to its original setting. */
828:
829: boolean
830: fsysdep_terminal_restore ()
831: {
832: if (! fSterm)
833: return TRUE;
834:
835: if (! fsetterminfo (0, &sSterm_orig))
836: {
837: ulog (LOG_ERROR, "Can't restore terminal: %s", strerror (errno));
838: return FALSE;
839: }
840: return TRUE;
841: }
842:
843: /* Read a line from the terminal. This will be called after
844: fsysdep_terminal_raw has been called. */
845:
846: char *
847: zsysdep_terminal_line (zprompt)
848: const char *zprompt;
849: {
850: CATCH_PROTECT size_t cbuf = 0;
851: CATCH_PROTECT char *zbuf = NULL;
852: CATCH_PROTECT size_t cgot = 0;
853:
854: if (zprompt != NULL && *zprompt != '\0')
855: (void) write (1, zprompt, strlen (zprompt));
856:
857: /* Forgot about any previous SIGINT or SIGQUIT signals we may have
858: received. We don't worry about the race condition here, since we
859: can't get these signals from the terminal at the moment and it's
860: not too likely that somebody else will be sending them to us. */
861: afSignal[INDEXSIG_SIGINT] = 0;
862: afSignal[INDEXSIG_SIGQUIT] = 0;
863:
864: if (! fsysdep_terminal_restore ())
865: return NULL;
866:
867: if (fsysdep_catch ())
868: {
869: usysdep_start_catch ();
870: cbuf = 0;
871: zbuf = NULL;
872: cgot = 0;
873: }
874:
875: while (TRUE)
876: {
877: char b;
878: int c;
879:
880: if (afSignal[INDEXSIG_SIGINT]
881: || afSignal[INDEXSIG_SIGQUIT])
882: {
883: usysdep_end_catch ();
884: /* Make sure the signal is logged. */
885: ulog (LOG_ERROR, (const char *) NULL);
886: /* Return an empty string. */
887: cgot = 0;
888: break;
889: }
890:
891: /* There's a race here between checking the signals and calling
892: read. It just means that the user will have to hit ^C more
893: than once. */
894:
895: c = read (0, &b, 1);
896: if (c < 0)
897: {
898: if (errno == EINTR)
899: continue;
900: usysdep_end_catch ();
901: ulog (LOG_ERROR, "read: %s", strerror (errno));
902: (void) fsysdep_terminal_raw (fSlocalecho);
903: return NULL;
904: }
905: if (c == 0)
906: {
907: /* I'm not quite sure what to do here. */
908: usysdep_end_catch ();
909: ulog (LOG_ERROR, "EOF on terminal");
910: (void) fsysdep_terminal_raw (fSlocalecho);
911: return NULL;
912: }
913:
914: if (cgot >= cbuf)
915: {
916: char *znew;
917:
918: cbuf += 64;
919: znew = zbufalc (cbuf);
920: if (zbuf != NULL)
921: {
922: memcpy (znew, zbuf, cgot);
923: ubuffree (zbuf);
924: }
925: zbuf = znew;
926: }
927:
928: zbuf[cgot] = b;
929:
930: ++cgot;
931:
932: if (b == '\n')
933: {
934: usysdep_end_catch ();
935: break;
936: }
937: }
938:
939: if (cgot >= cbuf)
940: {
941: char *znew;
942:
943: ++cbuf;
944: znew = zbufalc (cbuf);
945: if (zbuf != NULL)
946: {
947: memcpy (znew, zbuf, cgot);
948: ubuffree (zbuf);
949: }
950: zbuf = znew;
951: }
952:
953: zbuf[cgot] = '\0';
954:
955: if (! fsysdep_terminal_raw (fSlocalecho))
956: return NULL;
957:
958: return zbuf;
959: }
960:
961: /* Write a line to the terminal with a trailing newline. */
962:
963: boolean
964: fsysdep_terminal_puts (zline)
965: const char *zline;
966: {
967: char *zalc, *zprint;
968: size_t clen;
969:
970: if (zline == NULL)
971: {
972: zalc = zbufalc (2);
973: clen = 0;
974: }
975: else
976: {
977: clen = strlen (zline);
978: zalc = zbufalc (clen + 2);
979: memcpy (zalc, zline, clen);
980: }
981:
982: if (fSterm)
983: {
984: zalc[clen] = '\r';
985: ++clen;
986: }
987: zalc[clen] = '\n';
988: ++clen;
989:
990: zprint = zalc;
991: while (clen > 0)
992: {
993: int c;
994:
995: c = write (1, zprint, clen);
996: if (c <= 0)
997: {
998: ubuffree (zalc);
999: ulog (LOG_ERROR, "write: %s", strerror (errno));
1000: return FALSE;
1001: }
1002: clen -= c;
1003: zprint += c;
1004: }
1005:
1006: ubuffree (zalc);
1007:
1008: return TRUE;
1009: }
1010:
1011: /* Allow or disallow signals from the terminal. */
1012:
1013: boolean
1014: fsysdep_terminal_signals (faccept)
1015: boolean faccept;
1016: {
1017: #if HAVE_BSD_TTY
1018:
1019: if (faccept)
1020: {
1021: sSterm_new.stchars.t_intrc = sSterm_orig.stchars.t_intrc;
1022: sSterm_new.stchars.t_quitc = sSterm_orig.stchars.t_quitc;
1023: }
1024: else
1025: {
1026: sSterm_new.stchars.t_intrc = -1;
1027: sSterm_new.stchars.t_quitc = -1;
1028: }
1029:
1030: #else /* ! HAVE_BSD_TTY */
1031:
1032: if (faccept)
1033: sSterm_new.c_lflag |= ISIG;
1034: else
1035: sSterm_new.c_lflag &=~ ISIG;
1036:
1037: #ifdef SIGTSTP
1038: /* We only want to get SIGINT and SIGQUIT, not SIGTSTP. This
1039: function will be called with faccept TRUE before it is called
1040: with faccept FALSE, so fStstp_ignored will be correctly
1041: initialized. */
1042: if (faccept)
1043: usset_signal (SIGTSTP, SIG_IGN, FALSE, &fStstp_ignored);
1044: else if (! fStstp_ignored)
1045: usset_signal (SIGTSTP, SIG_DFL, TRUE, (boolean *) NULL);
1046: #endif
1047:
1048: #endif /* ! HAVE_BSD_TTY */
1049:
1050: if (! fsetterminfo (0, &sSterm_new))
1051: {
1052: ulog (LOG_ERROR, "Can't set terminal: %s", strerror (errno));
1053: return FALSE;
1054: }
1055:
1056: return TRUE;
1057: }
1058:
1059: /* Start up a command, or possibly just a shell. Optionally attach
1060: stdin or stdout to the port. We attach directly to the port,
1061: rather than copying the data ourselves. */
1062:
1063: boolean
1064: fsysdep_shell (qconn, zcmd, tcmd)
1065: struct sconnection *qconn;
1066: const char *zcmd;
1067: enum tshell_cmd tcmd;
1068: {
1069: const char *azargs[4];
1070: int oread, owrite;
1071: int aidescs[3];
1072: pid_t ipid;
1073:
1074: azargs[0] = "/bin/sh";
1075: if (zcmd == NULL || *zcmd == '\0')
1076: azargs[1] = NULL;
1077: else
1078: {
1079: azargs[1] = "-c";
1080: azargs[2] = zcmd;
1081: azargs[3] = NULL;
1082: }
1083:
1084: if (qconn->qport == NULL)
1085: {
1086: oread = 0;
1087: owrite = 1;
1088: }
1089: else
1090: {
1091: switch (qconn->qport->uuconf_ttype)
1092: {
1093: default:
1094: oread = owrite = -1;
1095: break;
1096: case UUCONF_PORTTYPE_STDIN:
1097: oread = 0;
1098: owrite = 1;
1099: break;
1100: case UUCONF_PORTTYPE_MODEM:
1101: case UUCONF_PORTTYPE_DIRECT:
1102: case UUCONF_PORTTYPE_TCP:
1103: case UUCONF_PORTTYPE_TLI:
1104: oread = owrite = ((struct ssysdep_conn *) qconn->psysdep)->o;
1105: break;
1106: }
1107: }
1108:
1109: aidescs[0] = 0;
1110: aidescs[1] = 1;
1111: aidescs[2] = 2;
1112:
1113: if (tcmd == SHELL_STDIN_FROM_PORT || tcmd == SHELL_STDIO_ON_PORT)
1114: aidescs[0] = oread;
1115: if (tcmd == SHELL_STDOUT_TO_PORT || tcmd == SHELL_STDIO_ON_PORT)
1116: aidescs[1] = owrite;
1117:
1118: ipid = ixsspawn (azargs, aidescs, FALSE, TRUE, (const char *) NULL,
1119: FALSE, FALSE, (const char *) NULL,
1120: (const char *) NULL, (const char *) NULL);
1121: if (ipid < 0)
1122: {
1123: ulog (LOG_ERROR, "ixsspawn (/bin/sh): %s", strerror (errno));
1124: return FALSE;
1125: }
1126:
1127: return ixswait ((unsigned long) ipid, "shell") == 0;
1128: }
1129:
1130: /* Change directories. */
1131:
1132: boolean
1133: fsysdep_chdir (zdir)
1134: const char *zdir;
1135: {
1136: if (zdir == NULL || *zdir == '\0')
1137: {
1138: zdir = getenv ("HOME");
1139: if (zdir == NULL)
1140: {
1141: ulog (LOG_ERROR, "HOME not defined");
1142: return FALSE;
1143: }
1144: }
1145: if (chdir (zdir) < 0)
1146: {
1147: ulog (LOG_ERROR, "chdir (%s): %s", zdir, strerror (errno));
1148: return FALSE;
1149: }
1150: return TRUE;
1151: }
1152:
1153: /* Suspend the current process. */
1154:
1155: boolean
1156: fsysdep_suspend ()
1157: {
1158: #ifndef SIGTSTP
1159: return fsysdep_terminal_puts ("[process suspension not supported]");
1160: #else
1161: return kill (getpid (), SIGTSTP) == 0;
1162: #endif
1163: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.