xref: /plan9/sys/src/ape/cmd/pax/ttyio.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1*9a747e4fSDavid du Colombier /* $Source: /u/mark/src/pax/RCS/ttyio.c,v $
2*9a747e4fSDavid du Colombier  *
3*9a747e4fSDavid du Colombier  * $Revision: 1.2 $
4*9a747e4fSDavid du Colombier  *
5*9a747e4fSDavid du Colombier  * ttyio.c - Terminal/Console I/O functions for all archive interfaces
6*9a747e4fSDavid du Colombier  *
7*9a747e4fSDavid du Colombier  * DESCRIPTION
8*9a747e4fSDavid du Colombier  *
9*9a747e4fSDavid du Colombier  *	These routines provide a consistent, general purpose interface to
10*9a747e4fSDavid du Colombier  *	the user via the users terminal, if it is available to the
11*9a747e4fSDavid du Colombier  *	process.
12*9a747e4fSDavid du Colombier  *
13*9a747e4fSDavid du Colombier  * AUTHOR
14*9a747e4fSDavid du Colombier  *
15*9a747e4fSDavid du Colombier  *     Mark H. Colburn, NAPS International (mark@jhereg.mn.org)
16*9a747e4fSDavid du Colombier  *
17*9a747e4fSDavid du Colombier  * Sponsored by The USENIX Association for public distribution.
18*9a747e4fSDavid du Colombier  *
19*9a747e4fSDavid du Colombier  * Copyright (c) 1989 Mark H. Colburn.
20*9a747e4fSDavid du Colombier  * All rights reserved.
21*9a747e4fSDavid du Colombier  *
22*9a747e4fSDavid du Colombier  * Redistribution and use in source and binary forms are permitted
23*9a747e4fSDavid du Colombier  * provided that the above copyright notice is duplicated in all such
24*9a747e4fSDavid du Colombier  * forms and that any documentation, advertising materials, and other
25*9a747e4fSDavid du Colombier  * materials related to such distribution and use acknowledge that the
26*9a747e4fSDavid du Colombier  * software was developed * by Mark H. Colburn and sponsored by The
27*9a747e4fSDavid du Colombier  * USENIX Association.
28*9a747e4fSDavid du Colombier  *
29*9a747e4fSDavid du Colombier  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
30*9a747e4fSDavid du Colombier  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
31*9a747e4fSDavid du Colombier  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
32*9a747e4fSDavid du Colombier  *
33*9a747e4fSDavid du Colombier  * $Log:	ttyio.c,v $
34*9a747e4fSDavid du Colombier  * Revision 1.2  89/02/12  10:06:11  mark
35*9a747e4fSDavid du Colombier  * 1.2 release fixes
36*9a747e4fSDavid du Colombier  *
37*9a747e4fSDavid du Colombier  * Revision 1.1  88/12/23  18:02:39  mark
38*9a747e4fSDavid du Colombier  * Initial revision
39*9a747e4fSDavid du Colombier  *
40*9a747e4fSDavid du Colombier  */
41*9a747e4fSDavid du Colombier 
42*9a747e4fSDavid du Colombier #ifndef lint
43*9a747e4fSDavid du Colombier static char *ident = "$Id: ttyio.c,v 1.2 89/02/12 10:06:11 mark Exp $";
44*9a747e4fSDavid du Colombier static char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n";
45*9a747e4fSDavid du Colombier #endif /* ! lint */
46*9a747e4fSDavid du Colombier 
47*9a747e4fSDavid du Colombier 
48*9a747e4fSDavid du Colombier /* Headers */
49*9a747e4fSDavid du Colombier 
50*9a747e4fSDavid du Colombier #include "pax.h"
51*9a747e4fSDavid du Colombier 
52*9a747e4fSDavid du Colombier 
53*9a747e4fSDavid du Colombier /* open_tty - open the terminal for interactive queries
54*9a747e4fSDavid du Colombier  *
55*9a747e4fSDavid du Colombier  * DESCRIPTION
56*9a747e4fSDavid du Colombier  *
57*9a747e4fSDavid du Colombier  * 	Assumes that background processes ignore interrupts and that the
58*9a747e4fSDavid du Colombier  *	open() or the isatty() will fail for processes which are not
59*9a747e4fSDavid du Colombier  *	attached to terminals. Returns a file descriptor or -1 if
60*9a747e4fSDavid du Colombier  *	unsuccessful.
61*9a747e4fSDavid du Colombier  *
62*9a747e4fSDavid du Colombier  * RETURNS
63*9a747e4fSDavid du Colombier  *
64*9a747e4fSDavid du Colombier  *	Returns a file descriptor which can be used to read and write
65*9a747e4fSDavid du Colombier  *	directly to the user's terminal, or -1 on failure.
66*9a747e4fSDavid du Colombier  *
67*9a747e4fSDavid du Colombier  * ERRORS
68*9a747e4fSDavid du Colombier  *
69*9a747e4fSDavid du Colombier  *	If SIGINT cannot be ignored, or the open fails, or the newly opened
70*9a747e4fSDavid du Colombier  *	terminal device is not a tty, then open_tty will return a -1 to the
71*9a747e4fSDavid du Colombier  *	caller.
72*9a747e4fSDavid du Colombier  */
73*9a747e4fSDavid du Colombier 
74*9a747e4fSDavid du Colombier #ifdef __STDC__
75*9a747e4fSDavid du Colombier 
open_tty(void)76*9a747e4fSDavid du Colombier int open_tty(void)
77*9a747e4fSDavid du Colombier 
78*9a747e4fSDavid du Colombier #else
79*9a747e4fSDavid du Colombier 
80*9a747e4fSDavid du Colombier int open_tty()
81*9a747e4fSDavid du Colombier 
82*9a747e4fSDavid du Colombier #endif
83*9a747e4fSDavid du Colombier {
84*9a747e4fSDavid du Colombier     int             fd;		/* file descriptor for terminal */
85*9a747e4fSDavid du Colombier     SIG_T         (*intr)();	/* used to restore interupts if signal fails */
86*9a747e4fSDavid du Colombier 
87*9a747e4fSDavid du Colombier     if ((intr = signal(SIGINT, SIG_IGN)) == SIG_IGN) {
88*9a747e4fSDavid du Colombier 	return (-1);
89*9a747e4fSDavid du Colombier     }
90*9a747e4fSDavid du Colombier     signal(SIGINT, intr);
91*9a747e4fSDavid du Colombier     if ((fd = open(TTY, O_RDWR)) < 0) {
92*9a747e4fSDavid du Colombier 	return (-1);
93*9a747e4fSDavid du Colombier     }
94*9a747e4fSDavid du Colombier     if (isatty(fd)) {
95*9a747e4fSDavid du Colombier 	return (fd);
96*9a747e4fSDavid du Colombier     }
97*9a747e4fSDavid du Colombier     close(fd);
98*9a747e4fSDavid du Colombier     return (-1);
99*9a747e4fSDavid du Colombier }
100*9a747e4fSDavid du Colombier 
101*9a747e4fSDavid du Colombier 
102*9a747e4fSDavid du Colombier /* nextask - ask a question and get a response
103*9a747e4fSDavid du Colombier  *
104*9a747e4fSDavid du Colombier  * DESCRIPTION
105*9a747e4fSDavid du Colombier  *
106*9a747e4fSDavid du Colombier  *	Give the user a prompt and wait for their response.  The prompt,
107*9a747e4fSDavid du Colombier  *	located in "msg" is printed, then the user is allowed to type
108*9a747e4fSDavid du Colombier  *	a response to the message.  The first "limit" characters of the
109*9a747e4fSDavid du Colombier  *	user response is stored in "answer".
110*9a747e4fSDavid du Colombier  *
111*9a747e4fSDavid du Colombier  *	Nextask ignores spaces and tabs.
112*9a747e4fSDavid du Colombier  *
113*9a747e4fSDavid du Colombier  * PARAMETERS
114*9a747e4fSDavid du Colombier  *
115*9a747e4fSDavid du Colombier  *	char *msg	- Message to display for user
116*9a747e4fSDavid du Colombier  *	char *answer	- Pointer to user's response to question
117*9a747e4fSDavid du Colombier  *	int limit	- Limit of length for user's response
118*9a747e4fSDavid du Colombier  *
119*9a747e4fSDavid du Colombier  * RETURNS
120*9a747e4fSDavid du Colombier  *
121*9a747e4fSDavid du Colombier  *	Returns the number of characters in the user response to the
122*9a747e4fSDavid du Colombier  *	calling function.  If an EOF was encountered, a -1 is returned to
123*9a747e4fSDavid du Colombier  *	the calling function.  If an error occured which causes the read
124*9a747e4fSDavid du Colombier  *	to return with a value of -1, then the function will return a
125*9a747e4fSDavid du Colombier  *	non-zero return status to the calling process, and abort
126*9a747e4fSDavid du Colombier  *	execution.
127*9a747e4fSDavid du Colombier  */
128*9a747e4fSDavid du Colombier 
129*9a747e4fSDavid du Colombier #ifdef __STDC__
130*9a747e4fSDavid du Colombier 
nextask(char * msg,char * answer,int limit)131*9a747e4fSDavid du Colombier int nextask(char *msg, char *answer, int limit)
132*9a747e4fSDavid du Colombier 
133*9a747e4fSDavid du Colombier #else
134*9a747e4fSDavid du Colombier 
135*9a747e4fSDavid du Colombier int nextask(msg, answer, limit)
136*9a747e4fSDavid du Colombier char           *msg;		/* message to display for user */
137*9a747e4fSDavid du Colombier char           *answer;		/* pointer to user's response to question */
138*9a747e4fSDavid du Colombier int             limit;		/* limit of length for user's response */
139*9a747e4fSDavid du Colombier 
140*9a747e4fSDavid du Colombier #endif
141*9a747e4fSDavid du Colombier {
142*9a747e4fSDavid du Colombier     int             idx;	/* index into answer for character input */
143*9a747e4fSDavid du Colombier     int             got;	/* number of characters read */
144*9a747e4fSDavid du Colombier     char            c;		/* character read */
145*9a747e4fSDavid du Colombier 
146*9a747e4fSDavid du Colombier     if (ttyf < 0) {
147*9a747e4fSDavid du Colombier 	fatal("/dev/tty Unavailable");
148*9a747e4fSDavid du Colombier     }
149*9a747e4fSDavid du Colombier     write(ttyf, msg, (uint) strlen(msg));
150*9a747e4fSDavid du Colombier     idx = 0;
151*9a747e4fSDavid du Colombier     while ((got = read(ttyf, &c, 1)) == 1) {
152*9a747e4fSDavid du Colombier 	if (c == '\n') {
153*9a747e4fSDavid du Colombier 	    break;
154*9a747e4fSDavid du Colombier 	} else if (c == ' ' || c == '\t') {
155*9a747e4fSDavid du Colombier 	    continue;
156*9a747e4fSDavid du Colombier 	} else if (idx < limit - 1) {
157*9a747e4fSDavid du Colombier 	    answer[idx++] = c;
158*9a747e4fSDavid du Colombier 	}
159*9a747e4fSDavid du Colombier     }
160*9a747e4fSDavid du Colombier     if (got == 0) {		/* got an EOF */
161*9a747e4fSDavid du Colombier         return(-1);
162*9a747e4fSDavid du Colombier     }
163*9a747e4fSDavid du Colombier     if (got < 0) {
164*9a747e4fSDavid du Colombier 	fatal(strerror());
165*9a747e4fSDavid du Colombier     }
166*9a747e4fSDavid du Colombier     answer[idx] = '\0';
167*9a747e4fSDavid du Colombier     return(0);
168*9a747e4fSDavid du Colombier }
169*9a747e4fSDavid du Colombier 
170*9a747e4fSDavid du Colombier 
171*9a747e4fSDavid du Colombier /* lineget - get a line from a given stream
172*9a747e4fSDavid du Colombier  *
173*9a747e4fSDavid du Colombier  * DESCRIPTION
174*9a747e4fSDavid du Colombier  *
175*9a747e4fSDavid du Colombier  *	Get a line of input for the stream named by "stream".  The data on
176*9a747e4fSDavid du Colombier  *	the stream is put into the buffer "buf".
177*9a747e4fSDavid du Colombier  *
178*9a747e4fSDavid du Colombier  * PARAMETERS
179*9a747e4fSDavid du Colombier  *
180*9a747e4fSDavid du Colombier  *	FILE *stream		- Stream to get input from
181*9a747e4fSDavid du Colombier  *	char *buf		- Buffer to put input into
182*9a747e4fSDavid du Colombier  *
183*9a747e4fSDavid du Colombier  * RETURNS
184*9a747e4fSDavid du Colombier  *
185*9a747e4fSDavid du Colombier  * 	Returns 0 if successful, -1 at EOF.
186*9a747e4fSDavid du Colombier  */
187*9a747e4fSDavid du Colombier 
188*9a747e4fSDavid du Colombier #ifdef __STDC__
189*9a747e4fSDavid du Colombier 
lineget(FILE * stream,char * buf)190*9a747e4fSDavid du Colombier int lineget(FILE *stream, char *buf)
191*9a747e4fSDavid du Colombier 
192*9a747e4fSDavid du Colombier #else
193*9a747e4fSDavid du Colombier 
194*9a747e4fSDavid du Colombier int lineget(stream, buf)
195*9a747e4fSDavid du Colombier FILE           *stream;		/* stream to get input from */
196*9a747e4fSDavid du Colombier char           *buf;		/* buffer to put input into */
197*9a747e4fSDavid du Colombier 
198*9a747e4fSDavid du Colombier #endif
199*9a747e4fSDavid du Colombier {
200*9a747e4fSDavid du Colombier     int             c;
201*9a747e4fSDavid du Colombier 
202*9a747e4fSDavid du Colombier     for (;;) {
203*9a747e4fSDavid du Colombier 	if ((c = getc(stream)) == EOF) {
204*9a747e4fSDavid du Colombier 	    return (-1);
205*9a747e4fSDavid du Colombier 	}
206*9a747e4fSDavid du Colombier 	if (c == '\n') {
207*9a747e4fSDavid du Colombier 	    break;
208*9a747e4fSDavid du Colombier 	}
209*9a747e4fSDavid du Colombier 	*buf++ = c;
210*9a747e4fSDavid du Colombier     }
211*9a747e4fSDavid du Colombier     *buf = '\0';
212*9a747e4fSDavid du Colombier     return (0);
213*9a747e4fSDavid du Colombier }
214*9a747e4fSDavid du Colombier 
215*9a747e4fSDavid du Colombier 
216*9a747e4fSDavid du Colombier /* next - Advance to the next archive volume.
217*9a747e4fSDavid du Colombier  *
218*9a747e4fSDavid du Colombier  * DESCRIPTION
219*9a747e4fSDavid du Colombier  *
220*9a747e4fSDavid du Colombier  *	Prompts the user to replace the backup medium with a new volume
221*9a747e4fSDavid du Colombier  *	when the old one is full.  There are some cases, such as when
222*9a747e4fSDavid du Colombier  *	archiving to a file on a hard disk, that the message can be a
223*9a747e4fSDavid du Colombier  *	little surprising.  Assumes that background processes ignore
224*9a747e4fSDavid du Colombier  *	interrupts and that the open() or the isatty() will fail for
225*9a747e4fSDavid du Colombier  *	processes which are not attached to terminals. Returns a file
226*9a747e4fSDavid du Colombier  *	descriptor or -1 if unsuccessful.
227*9a747e4fSDavid du Colombier  *
228*9a747e4fSDavid du Colombier  * PARAMETERS
229*9a747e4fSDavid du Colombier  *
230*9a747e4fSDavid du Colombier  *	int mode	- mode of archive (READ, WRITE, PASS)
231*9a747e4fSDavid du Colombier  */
232*9a747e4fSDavid du Colombier 
233*9a747e4fSDavid du Colombier #ifdef __STDC__
234*9a747e4fSDavid du Colombier 
next(int mode)235*9a747e4fSDavid du Colombier void next(int mode)
236*9a747e4fSDavid du Colombier 
237*9a747e4fSDavid du Colombier #else
238*9a747e4fSDavid du Colombier 
239*9a747e4fSDavid du Colombier void next(mode)
240*9a747e4fSDavid du Colombier int             mode;		/* mode of archive (READ, WRITE, PASS) */
241*9a747e4fSDavid du Colombier 
242*9a747e4fSDavid du Colombier #endif
243*9a747e4fSDavid du Colombier {
244*9a747e4fSDavid du Colombier     char            msg[200];	/* buffer for message display */
245*9a747e4fSDavid du Colombier     char            answer[20];	/* buffer for user's answer */
246*9a747e4fSDavid du Colombier     int             ret;
247*9a747e4fSDavid du Colombier 
248*9a747e4fSDavid du Colombier     close_archive();
249*9a747e4fSDavid du Colombier 
250*9a747e4fSDavid du Colombier     sprintf(msg, "%s: Ready for volume %u\n%s: Type \"go\" when ready to proceed (or \"quit\" to abort): \07",
251*9a747e4fSDavid du Colombier 		   myname, arvolume + 1, myname);
252*9a747e4fSDavid du Colombier     for (;;) {
253*9a747e4fSDavid du Colombier 	ret = nextask(msg, answer, sizeof(answer));
254*9a747e4fSDavid du Colombier 	if (ret == -1 || strcmp(answer, "quit") == 0) {
255*9a747e4fSDavid du Colombier 	    fatal("Aborted");
256*9a747e4fSDavid du Colombier 	}
257*9a747e4fSDavid du Colombier 	if (strcmp(answer, "go") == 0 && open_archive(mode) == 0) {
258*9a747e4fSDavid du Colombier 	    break;
259*9a747e4fSDavid du Colombier 	}
260*9a747e4fSDavid du Colombier     }
261*9a747e4fSDavid du Colombier     warnarch("Continuing", (OFFSET) 0);
262*9a747e4fSDavid du Colombier }
263