luit.c revision 4ed31819
1a8fdb4bcSmrg/*
2a8fdb4bcSmrgCopyright (c) 2001 by Juliusz Chroboczek
3a8fdb4bcSmrg
4a8fdb4bcSmrgPermission is hereby granted, free of charge, to any person obtaining a copy
5a8fdb4bcSmrgof this software and associated documentation files (the "Software"), to deal
6a8fdb4bcSmrgin the Software without restriction, including without limitation the rights
7a8fdb4bcSmrgto use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8a8fdb4bcSmrgcopies of the Software, and to permit persons to whom the Software is
9a8fdb4bcSmrgfurnished to do so, subject to the following conditions:
10a8fdb4bcSmrg
11a8fdb4bcSmrgThe above copyright notice and this permission notice shall be included in
12a8fdb4bcSmrgall copies or substantial portions of the Software.
13a8fdb4bcSmrg
14a8fdb4bcSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15a8fdb4bcSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16a8fdb4bcSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17a8fdb4bcSmrgAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18a8fdb4bcSmrgLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19a8fdb4bcSmrgOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20a8fdb4bcSmrgTHE SOFTWARE.
21a8fdb4bcSmrg*/
2277683534Smrg
2377683534Smrg#ifdef HAVE_CONFIG_H
2477683534Smrg# include "config.h"
2577683534Smrg#endif
26a8fdb4bcSmrg
27a8fdb4bcSmrg#include <stdio.h>
28a8fdb4bcSmrg#include <stdlib.h>
29a8fdb4bcSmrg#include <string.h>
30a8fdb4bcSmrg#include <locale.h>
31a8fdb4bcSmrg#include <sys/types.h>
32a8fdb4bcSmrg#include <fcntl.h>
33a8fdb4bcSmrg#include <unistd.h>
34a8fdb4bcSmrg#include <errno.h>
35a8fdb4bcSmrg#include <assert.h>
36a8fdb4bcSmrg#include <stdarg.h>
37a8fdb4bcSmrg#include <sys/ioctl.h>
38a8fdb4bcSmrg#include <signal.h>
39a8fdb4bcSmrg
40a8fdb4bcSmrg#include "luit.h"
41a8fdb4bcSmrg#include "sys.h"
42a8fdb4bcSmrg#include "other.h"
4377683534Smrg#include "parser.h"
44a8fdb4bcSmrg#include "iso2022.h"
45a8fdb4bcSmrg
4677683534Smrgstatic int pipe_option = 0;
4777683534Smrgstatic int p2c_waitpipe[2];
4877683534Smrgstatic int c2p_waitpipe[2];
4977683534Smrg
50a8fdb4bcSmrgstatic Iso2022Ptr inputState = NULL, outputState = NULL;
51a8fdb4bcSmrg
52a8fdb4bcSmrgstatic char *child_argv0 = NULL;
5377683534Smrgstatic const char *locale_name = NULL;
5477683534Smrgstatic int exitOnChild = 0;
5577683534Smrgstatic int converter = 0;
5677683534Smrg
5777683534Smrgconst char *locale_alias = LOCALE_ALIAS_FILE;
5877683534Smrg
59a8fdb4bcSmrgint ilog = -1;
60a8fdb4bcSmrgint olog = -1;
61a8fdb4bcSmrgint verbose = 0;
62a8fdb4bcSmrg
63dbe7da2eSmrgstatic volatile int sigwinch_queued = 0;
64dbe7da2eSmrgstatic volatile int sigchld_queued = 0;
65a8fdb4bcSmrg
66a8fdb4bcSmrgstatic int convert(int, int);
6777683534Smrgstatic int condom(int, char **);
68a8fdb4bcSmrg
694ed31819Smrgvoid
7077683534SmrgErrorF(const char *f,...)
71a8fdb4bcSmrg{
72a8fdb4bcSmrg    va_list args;
73a8fdb4bcSmrg    va_start(args, f);
74a8fdb4bcSmrg    vfprintf(stderr, f, args);
75a8fdb4bcSmrg    va_end(args);
76a8fdb4bcSmrg}
77a8fdb4bcSmrg
784ed31819Smrgvoid
7977683534SmrgFatalError(const char *f,...)
80a8fdb4bcSmrg{
81a8fdb4bcSmrg    va_list args;
82a8fdb4bcSmrg    va_start(args, f);
83a8fdb4bcSmrg    vfprintf(stderr, f, args);
84a8fdb4bcSmrg    va_end(args);
8577683534Smrg    ExitProgram(1);
86a8fdb4bcSmrg}
87a8fdb4bcSmrg
88a8fdb4bcSmrgstatic void
89a8fdb4bcSmrghelp(void)
90a8fdb4bcSmrg{
9177683534Smrg    fprintf(stderr,
9277683534Smrg	    "luit\n"
9377683534Smrg	    "  [ -V ] [ -h ] [ -list ] [ -v ] [ -argv0 name ]\n"
9477683534Smrg	    "  [ -gl gn ] [-gr gk] "
9577683534Smrg	    "[ -g0 set ] [ -g1 set ] "
9677683534Smrg	    "[ -g2 set ] [ -g3 set ]\n"
9777683534Smrg	    "  [ -encoding encoding ] "
9877683534Smrg	    "[ +oss ] [ +ols ] [ +osl ] [ +ot ]\n"
9977683534Smrg	    "  [ -kgl gn ] [-kgr gk] "
10077683534Smrg	    "[ -kg0 set ] [ -kg1 set ] "
10177683534Smrg	    "[ -kg2 set ] [ -kg3 set ]\n"
10277683534Smrg	    "  [ -k7 ] [ +kss ] [ +kssgr ] [ -kls ]\n"
10377683534Smrg	    "  [ -c ] "
10477683534Smrg	    "[ -p ] "
10577683534Smrg	    "[ -x ] "
10677683534Smrg	    "[ -ilog filename ] "
10777683534Smrg	    "[ -olog filename ] "
10877683534Smrg	    "[ -alias filename ] "
10977683534Smrg	    "[ -- ]\n"
11077683534Smrg	    "  [ program [ args ] ]\n");
111a8fdb4bcSmrg}
112a8fdb4bcSmrg
113a8fdb4bcSmrgstatic int
114a8fdb4bcSmrgparseOptions(int argc, char **argv)
115a8fdb4bcSmrg{
116a8fdb4bcSmrg    int i = 1;
11777683534Smrg    while (i < argc) {
11877683534Smrg	if (argv[i][0] != '-' && argv[i][0] != '+') {
11977683534Smrg	    break;
12077683534Smrg	} else if (!strcmp(argv[i], "--")) {
12177683534Smrg	    i++;
12277683534Smrg	    break;
12377683534Smrg	} else if (!strcmp(argv[i], "-v")) {
12477683534Smrg	    verbose++;
12577683534Smrg	    i++;
12677683534Smrg	} else if (!strcmp(argv[i], "-V")) {
12777683534Smrg	    printf("%s - %s\n", argv[0], VERSION);
12877683534Smrg	    ExitProgram(0);
12977683534Smrg	} else if (!strcmp(argv[i], "-h")) {
13077683534Smrg	    help();
13177683534Smrg	    ExitProgram(0);
13277683534Smrg	} else if (!strcmp(argv[i], "-list")) {
13377683534Smrg	    reportCharsets();
13477683534Smrg	    ExitProgram(0);
13577683534Smrg	} else if (!strcmp(argv[i], "+oss")) {
13677683534Smrg	    outputState->outputFlags &= ~OF_SS;
13777683534Smrg	    i++;
13877683534Smrg	} else if (!strcmp(argv[i], "+ols")) {
13977683534Smrg	    outputState->outputFlags &= ~OF_LS;
14077683534Smrg	    i++;
14177683534Smrg	} else if (!strcmp(argv[i], "+osl")) {
14277683534Smrg	    outputState->outputFlags &= ~OF_SELECT;
14377683534Smrg	    i++;
14477683534Smrg	} else if (!strcmp(argv[i], "+ot")) {
14577683534Smrg	    outputState->outputFlags = OF_PASSTHRU;
14677683534Smrg	    i++;
14777683534Smrg	} else if (!strcmp(argv[i], "-k7")) {
14877683534Smrg	    inputState->inputFlags &= ~IF_EIGHTBIT;
14977683534Smrg	    i++;
15077683534Smrg	} else if (!strcmp(argv[i], "+kss")) {
15177683534Smrg	    inputState->inputFlags &= ~IF_SS;
15277683534Smrg	    i++;
15377683534Smrg	} else if (!strcmp(argv[1], "+kssgr")) {
15477683534Smrg	    inputState->inputFlags &= ~IF_SSGR;
15577683534Smrg	    i++;
15677683534Smrg	} else if (!strcmp(argv[i], "-kls")) {
15777683534Smrg	    inputState->inputFlags |= IF_LS;
15877683534Smrg	    i++;
15977683534Smrg	} else if (!strcmp(argv[i], "-g0")) {
16077683534Smrg	    if (i + 1 >= argc)
16177683534Smrg		FatalError("-g0 requires an argument\n");
16277683534Smrg	    G0(outputState) = getCharsetByName(argv[i + 1]);
16377683534Smrg	    i += 2;
16477683534Smrg	} else if (!strcmp(argv[i], "-g1")) {
16577683534Smrg	    if (i + 1 >= argc)
16677683534Smrg		FatalError("-g1 requires an argument\n");
16777683534Smrg	    G1(outputState) = getCharsetByName(argv[i + 1]);
16877683534Smrg	    i += 2;
16977683534Smrg	} else if (!strcmp(argv[i], "-g2")) {
17077683534Smrg	    if (i + 1 >= argc)
17177683534Smrg		FatalError("-g2 requires an argument\n");
17277683534Smrg	    G2(outputState) = getCharsetByName(argv[i + 1]);
17377683534Smrg	    i += 2;
17477683534Smrg	} else if (!strcmp(argv[i], "-g3")) {
17577683534Smrg	    if (i + 1 >= argc)
17677683534Smrg		FatalError("-g3 requires an argument\n");
17777683534Smrg	    G3(outputState) = getCharsetByName(argv[i + 1]);
17877683534Smrg
17977683534Smrg	    i += 2;
18077683534Smrg	} else if (!strcmp(argv[i], "-gl")) {
18177683534Smrg	    int j;
18277683534Smrg	    if (i + 1 >= argc)
18377683534Smrg		FatalError("-gl requires an argument\n");
18477683534Smrg	    if (strlen(argv[i + 1]) != 2 ||
18577683534Smrg		argv[i + 1][0] != 'g')
18677683534Smrg		j = -1;
18777683534Smrg	    else
18877683534Smrg		j = argv[i + 1][1] - '0';
18977683534Smrg	    if (j < 0 || j > 3)
19077683534Smrg		FatalError("The argument of -gl "
19177683534Smrg			   "should be one of g0 through g3,\n"
19277683534Smrg			   "not %s\n", argv[i + 1]);
19377683534Smrg	    else
19477683534Smrg		outputState->glp = &outputState->g[j];
19577683534Smrg	    i += 2;
19677683534Smrg	} else if (!strcmp(argv[i], "-gr")) {
19777683534Smrg	    int j;
19877683534Smrg	    if (i + 1 >= argc)
19977683534Smrg		FatalError("-gr requires an argument\n");
20077683534Smrg	    if (strlen(argv[i + 1]) != 2 ||
20177683534Smrg		argv[i + 1][0] != 'g')
20277683534Smrg		j = -1;
20377683534Smrg	    else
20477683534Smrg		j = argv[i + 1][1] - '0';
20577683534Smrg	    if (j < 0 || j > 3)
20677683534Smrg		FatalError("The argument of -gl "
20777683534Smrg			   "should be one of g0 through g3,\n"
20877683534Smrg			   "not %s\n", argv[i + 1]);
20977683534Smrg	    else
21077683534Smrg		outputState->grp = &outputState->g[j];
21177683534Smrg	    i += 2;
21277683534Smrg	} else if (!strcmp(argv[i], "-kg0")) {
21377683534Smrg	    if (i + 1 >= argc)
21477683534Smrg		FatalError("-kg0 requires an argument\n");
21577683534Smrg	    G0(inputState) = getCharsetByName(argv[i + 1]);
21677683534Smrg	    i += 2;
21777683534Smrg	} else if (!strcmp(argv[i], "-kg1")) {
21877683534Smrg	    if (i + 1 >= argc)
21977683534Smrg		FatalError("-kg1 requires an argument\n");
22077683534Smrg	    G1(inputState) = getCharsetByName(argv[i + 1]);
22177683534Smrg	    i += 2;
22277683534Smrg	} else if (!strcmp(argv[i], "-kg2")) {
22377683534Smrg	    if (i + 1 >= argc)
22477683534Smrg		FatalError("-kg2 requires an argument\n");
22577683534Smrg	    G2(inputState) = getCharsetByName(argv[i + 1]);
22677683534Smrg	    i += 2;
22777683534Smrg	} else if (!strcmp(argv[i], "-kg3")) {
22877683534Smrg	    if (i + 1 >= argc)
22977683534Smrg		FatalError("-kg3 requires an argument\n");
23077683534Smrg	    G3(inputState) = getCharsetByName(argv[i + 1]);
23177683534Smrg
23277683534Smrg	    i += 2;
23377683534Smrg	} else if (!strcmp(argv[i], "-kgl")) {
23477683534Smrg	    int j;
23577683534Smrg	    if (i + 1 >= argc)
23677683534Smrg		FatalError("-kgl requires an argument\n");
23777683534Smrg	    if (strlen(argv[i + 1]) != 2 ||
23877683534Smrg		argv[i + 1][0] != 'g')
23977683534Smrg		j = -1;
24077683534Smrg	    else
24177683534Smrg		j = argv[i + 1][1] - '0';
24277683534Smrg	    if (j < 0 || j > 3)
24377683534Smrg		FatalError("The argument of -kgl "
24477683534Smrg			   "should be one of g0 through g3,\n"
24577683534Smrg			   "not %s\n", argv[i + 1]);
24677683534Smrg	    else
24777683534Smrg		inputState->glp = &inputState->g[j];
24877683534Smrg	    i += 2;
24977683534Smrg	} else if (!strcmp(argv[i], "-kgr")) {
25077683534Smrg	    int j;
25177683534Smrg	    if (i + 1 >= argc)
25277683534Smrg		FatalError("-kgl requires an argument\n");
25377683534Smrg	    if (strlen(argv[i + 1]) != 2 ||
25477683534Smrg		argv[i + 1][0] != 'g')
25577683534Smrg		j = -1;
25677683534Smrg	    else
25777683534Smrg		j = argv[i + 1][1] - '0';
25877683534Smrg	    if (j < 0 || j > 3)
25977683534Smrg		FatalError("The argument of -kgl "
26077683534Smrg			   "should be one of g0 through g3,\n"
26177683534Smrg			   "not %s\n", argv[i + 1]);
26277683534Smrg	    else
26377683534Smrg		inputState->grp = &inputState->g[j];
26477683534Smrg	    i += 2;
26577683534Smrg	} else if (!strcmp(argv[i], "-argv0")) {
26677683534Smrg	    if (i + 1 >= argc)
26777683534Smrg		FatalError("-argv0 requires an argument\n");
26877683534Smrg	    child_argv0 = argv[i + 1];
26977683534Smrg	    i += 2;
27077683534Smrg	} else if (!strcmp(argv[i], "-x")) {
27177683534Smrg	    exitOnChild = 1;
27277683534Smrg	    i++;
27377683534Smrg	} else if (!strcmp(argv[i], "-c")) {
27477683534Smrg	    converter = 1;
27577683534Smrg	    i++;
27677683534Smrg	} else if (!strcmp(argv[i], "-ilog")) {
27777683534Smrg	    if (i + 1 >= argc)
27877683534Smrg		FatalError("-ilog requires an argument\n");
27977683534Smrg	    ilog = open(argv[i + 1], O_WRONLY | O_CREAT | O_TRUNC, 0777);
28077683534Smrg	    if (ilog < 0) {
28177683534Smrg		perror("Couldn't open input log");
28277683534Smrg		ExitProgram(1);
28377683534Smrg	    }
28477683534Smrg	    i += 2;
28577683534Smrg	} else if (!strcmp(argv[i], "-olog")) {
28677683534Smrg	    if (i + 1 >= argc)
28777683534Smrg		FatalError("-olog requires an argument\n");
28877683534Smrg	    olog = open(argv[i + 1], O_WRONLY | O_CREAT | O_TRUNC, 0777);
28977683534Smrg	    if (olog < 0) {
29077683534Smrg		perror("Couldn't open output log");
29177683534Smrg		ExitProgram(1);
29277683534Smrg	    }
29377683534Smrg	    i += 2;
29477683534Smrg	} else if (!strcmp(argv[i], "-alias")) {
29577683534Smrg	    if (i + 1 >= argc)
29677683534Smrg		FatalError("-alias requires an argument\n");
29777683534Smrg	    locale_alias = argv[i + 1];
29877683534Smrg	    i += 2;
29977683534Smrg	} else if (!strcmp(argv[i], "-encoding")) {
30077683534Smrg	    if (i + 1 >= argc)
30177683534Smrg		FatalError("-encoding requires an argument\n");
30277683534Smrg	    locale_name = argv[i + 1];
30377683534Smrg	    i += 2;
30477683534Smrg	} else if (!strcmp(argv[i], "-p")) {
30577683534Smrg	    pipe_option = 1;
30677683534Smrg	    i += 1;
30777683534Smrg	} else {
30877683534Smrg	    FatalError("Unknown option %s\n", argv[i]);
30977683534Smrg	}
310a8fdb4bcSmrg    }
311a8fdb4bcSmrg    return i;
312a8fdb4bcSmrg}
313a8fdb4bcSmrg
314a8fdb4bcSmrgstatic int
31577683534SmrgparseArgs(int argc, char **argv,
31677683534Smrg	  char *argv0,
31777683534Smrg	  char **path_return,
31877683534Smrg	  char ***argv_return)
319a8fdb4bcSmrg{
320a8fdb4bcSmrg    char *path = NULL;
321a8fdb4bcSmrg    char **child_argv = NULL;
322a8fdb4bcSmrg
32377683534Smrg    if (argc <= 0) {
32477683534Smrg	char *shell;
32577683534Smrg	shell = getenv("SHELL");
32677683534Smrg	if (shell) {
32777683534Smrg	    path = strmalloc(shell);
32877683534Smrg	    if (!path)
32977683534Smrg		goto bail;
33077683534Smrg	} else {
33177683534Smrg	    path = strmalloc("/bin/sh");
33277683534Smrg	    if (!path)
33377683534Smrg		goto bail;
33477683534Smrg	}
33577683534Smrg	child_argv = malloc(2 * sizeof(char *));
33677683534Smrg	if (!child_argv)
33777683534Smrg	    goto bail;
33877683534Smrg	if (argv0)
33977683534Smrg	    child_argv[0] = argv0;
34077683534Smrg	else
34177683534Smrg	    child_argv[0] = my_basename(path);
34277683534Smrg	child_argv[1] = NULL;
343a8fdb4bcSmrg    } else {
34477683534Smrg	path = strmalloc(argv[0]);
34577683534Smrg	if (!path)
34677683534Smrg	    goto bail;
34777683534Smrg	child_argv = malloc((unsigned) (argc + 1) * sizeof(char *));
34877683534Smrg	if (!child_argv) {
34977683534Smrg	    goto bail;
35077683534Smrg	}
35177683534Smrg	if (child_argv0)
35277683534Smrg	    child_argv[0] = argv0;
35377683534Smrg	else
35477683534Smrg	    child_argv[0] = my_basename(argv[0]);
35577683534Smrg	memcpy(child_argv + 1, argv + 1, (unsigned) (argc - 1) * sizeof(char *));
35677683534Smrg	child_argv[argc] = NULL;
357a8fdb4bcSmrg    }
358a8fdb4bcSmrg
359a8fdb4bcSmrg    *path_return = path;
360a8fdb4bcSmrg    *argv_return = child_argv;
361a8fdb4bcSmrg    return 0;
362a8fdb4bcSmrg
363a8fdb4bcSmrg  bail:
36477683534Smrg    if (path)
36577683534Smrg	free(path);
36677683534Smrg    if (argv)
36777683534Smrg	free(argv);
368a8fdb4bcSmrg    return -1;
369a8fdb4bcSmrg}
370a8fdb4bcSmrg
371a8fdb4bcSmrgint
372a8fdb4bcSmrgmain(int argc, char **argv)
373a8fdb4bcSmrg{
374a8fdb4bcSmrg    int rc;
375a8fdb4bcSmrg    int i;
376a8fdb4bcSmrg    char *l;
377a8fdb4bcSmrg
37877683534Smrg#ifdef HAVE_PUTENV
37977683534Smrg    if ((l = strmalloc("NCURSES_NO_UTF8_ACS=1")) != 0)
38077683534Smrg	putenv(l);
38177683534Smrg#endif
38277683534Smrg
383a8fdb4bcSmrg    l = setlocale(LC_ALL, "");
38477683534Smrg    if (!l)
38577683534Smrg	ErrorF("Warning: couldn't set locale.\n");
386a8fdb4bcSmrg
387a8fdb4bcSmrg    inputState = allocIso2022();
38877683534Smrg    if (!inputState)
38977683534Smrg	FatalError("Couldn't create input state\n");
39077683534Smrg
391a8fdb4bcSmrg    outputState = allocIso2022();
39277683534Smrg    if (!outputState)
39377683534Smrg	FatalError("Couldn't create output state\n");
39477683534Smrg
39577683534Smrg    if (l) {
39677683534Smrg	locale_name = setlocale(LC_CTYPE, NULL);
397a8fdb4bcSmrg    } else {
39877683534Smrg	locale_name = getenv("LC_ALL");
39977683534Smrg	if (locale_name == NULL) {
40077683534Smrg	    locale_name = getenv("LC_CTYPE");
40177683534Smrg	    if (locale_name == NULL) {
40277683534Smrg		locale_name = getenv("LANG");
40377683534Smrg	    }
40477683534Smrg	}
405a8fdb4bcSmrg    }
406a8fdb4bcSmrg
40777683534Smrg    if (locale_name == NULL) {
40877683534Smrg	ErrorF("Couldn't get locale name -- using C\n");
40977683534Smrg	locale_name = "C";
410a8fdb4bcSmrg    }
411a8fdb4bcSmrg
412a8fdb4bcSmrg    i = parseOptions(argc, argv);
41377683534Smrg    if (i < 0)
41477683534Smrg	FatalError("Couldn't parse options\n");
41577683534Smrg
41677683534Smrg    rc = initIso2022(locale_name, NULL, outputState);
41777683534Smrg    if (rc < 0)
41877683534Smrg	FatalError("Couldn't init output state\n");
419a8fdb4bcSmrg
420a8fdb4bcSmrg    rc = mergeIso2022(inputState, outputState);
42177683534Smrg    if (rc < 0)
42277683534Smrg	FatalError("Couldn't init input state\n");
423a8fdb4bcSmrg
42477683534Smrg    if (converter)
42577683534Smrg	rc = convert(0, 1);
426a8fdb4bcSmrg    else
42777683534Smrg	rc = condom(argc - i, argv + i);
42877683534Smrg
42977683534Smrg#ifdef NO_LEAKS
43077683534Smrg    ExitProgram(rc);
43177683534Smrg#endif
43277683534Smrg    return rc;
433a8fdb4bcSmrg}
434a8fdb4bcSmrg
435a8fdb4bcSmrgstatic int
436a8fdb4bcSmrgconvert(int ifd, int ofd)
437a8fdb4bcSmrg{
438a8fdb4bcSmrg    int rc, i;
439a8fdb4bcSmrg    unsigned char buf[BUFFER_SIZE];
440a8fdb4bcSmrg
441a8fdb4bcSmrg    rc = droppriv();
44277683534Smrg    if (rc < 0) {
44377683534Smrg	perror("Couldn't drop privileges");
44477683534Smrg	ExitProgram(1);
445a8fdb4bcSmrg    }
446a8fdb4bcSmrg
44777683534Smrg    while (1) {
44877683534Smrg	i = (int) read(ifd, buf, (size_t) BUFFER_SIZE);
44977683534Smrg	if (i <= 0) {
45077683534Smrg	    if (i < 0) {
45177683534Smrg		perror("Read error");
45277683534Smrg		ExitProgram(1);
45377683534Smrg	    }
45477683534Smrg	    break;
45577683534Smrg	}
45677683534Smrg	copyOut(outputState, ofd, buf, (unsigned) i);
457a8fdb4bcSmrg    }
458a8fdb4bcSmrg    return 0;
459a8fdb4bcSmrg}
46077683534Smrg
46177683534Smrg#ifdef SIGWINCH
462a8fdb4bcSmrgstatic void
46377683534SmrgsigwinchHandler(int sig GCC_UNUSED)
464a8fdb4bcSmrg{
465a8fdb4bcSmrg    sigwinch_queued = 1;
466a8fdb4bcSmrg}
46777683534Smrg#endif
468a8fdb4bcSmrg
469a8fdb4bcSmrgstatic void
47077683534SmrgsigchldHandler(int sig GCC_UNUSED)
471a8fdb4bcSmrg{
472a8fdb4bcSmrg    sigchld_queued = 1;
473a8fdb4bcSmrg}
474a8fdb4bcSmrg
475a8fdb4bcSmrgstatic int
47677683534Smrgsetup_io(int pty)
477a8fdb4bcSmrg{
478a8fdb4bcSmrg    int rc;
479a8fdb4bcSmrg    int val;
480a8fdb4bcSmrg
481a8fdb4bcSmrg#ifdef SIGWINCH
482a8fdb4bcSmrg    installHandler(SIGWINCH, sigwinchHandler);
483a8fdb4bcSmrg#endif
484a8fdb4bcSmrg    installHandler(SIGCHLD, sigchldHandler);
485a8fdb4bcSmrg
486a8fdb4bcSmrg    rc = copyTermios(0, pty);
48777683534Smrg    if (rc < 0)
48877683534Smrg	FatalError("Couldn't copy terminal settings\n");
489a8fdb4bcSmrg
490a8fdb4bcSmrg    rc = setRawTermios();
49177683534Smrg    if (rc < 0)
49277683534Smrg	FatalError("Couldn't set terminal to raw\n");
493a8fdb4bcSmrg
494a8fdb4bcSmrg    val = fcntl(0, F_GETFL, 0);
49577683534Smrg    if (val >= 0) {
49677683534Smrg	fcntl(0, F_SETFL, val | O_NONBLOCK);
497a8fdb4bcSmrg    }
498a8fdb4bcSmrg    val = fcntl(pty, F_GETFL, 0);
49977683534Smrg    if (val >= 0) {
50077683534Smrg	fcntl(pty, F_SETFL, val | O_NONBLOCK);
501a8fdb4bcSmrg    }
502a8fdb4bcSmrg
503a8fdb4bcSmrg    setWindowSize(0, pty);
504a8fdb4bcSmrg
50577683534Smrg    return rc;
50677683534Smrg}
50777683534Smrg
50877683534Smrgstatic void
50977683534Smrgcleanup_io(int pty)
51077683534Smrg{
51177683534Smrg    int val;
512a8fdb4bcSmrg
513a8fdb4bcSmrg#ifdef SIGWINCH
51477683534Smrg    installHandler(SIGWINCH, SIG_DFL);
515a8fdb4bcSmrg#endif
51677683534Smrg    installHandler(SIGCHLD, SIG_DFL);
51777683534Smrg
51877683534Smrg    val = fcntl(0, F_GETFL, 0);
51977683534Smrg    if (val >= 0) {
52077683534Smrg	fcntl(0, F_SETFL, val & ~O_NONBLOCK);
52177683534Smrg    }
52277683534Smrg    val = fcntl(pty, F_GETFL, 0);
52377683534Smrg    if (val >= 0) {
52477683534Smrg	fcntl(pty, F_SETFL, val & ~O_NONBLOCK);
52577683534Smrg    }
52677683534Smrg}
52777683534Smrg
52877683534Smrgstatic void
52977683534Smrgclose_waitpipe(int which)
53077683534Smrg{
53177683534Smrg    close(p2c_waitpipe[which]);
53277683534Smrg    close(c2p_waitpipe[!which]);
53377683534Smrg}
53477683534Smrg
53577683534Smrgstatic void
53677683534Smrgwrite_waitpipe(int fds[2])
53777683534Smrg{
53877683534Smrg    IGNORE_RC(write(fds[1], "1", (size_t) 1));
53977683534Smrg}
54077683534Smrg
54177683534Smrgstatic void
54277683534Smrgread_waitpipe(int fds[2])
54377683534Smrg{
54477683534Smrg    char tmp[10];
54577683534Smrg    IGNORE_RC(read(fds[0], tmp, (size_t) 1));
54677683534Smrg}
54777683534Smrg
54877683534Smrgstatic int
54977683534Smrgcondom(int argc, char **argv)
55077683534Smrg{
55177683534Smrg    int pty;
55277683534Smrg    int pid;
55377683534Smrg    char *line;
55477683534Smrg    char *path = 0;
55577683534Smrg    char **child_argv = 0;
55677683534Smrg    int rc;
55777683534Smrg
55877683534Smrg    rc = parseArgs(argc, argv, child_argv0,
55977683534Smrg		   &path, &child_argv);
56077683534Smrg    if (rc < 0)
56177683534Smrg	FatalError("Couldn't parse arguments\n");
56277683534Smrg
56377683534Smrg    rc = allocatePty(&pty, &line);
56477683534Smrg    if (rc < 0) {
56577683534Smrg	perror("Couldn't allocate pty");
56677683534Smrg	ExitProgram(1);
56777683534Smrg    }
56877683534Smrg
56977683534Smrg    rc = droppriv();
57077683534Smrg    if (rc < 0) {
57177683534Smrg	perror("Couldn't drop privileges");
57277683534Smrg	ExitProgram(1);
57377683534Smrg    }
57477683534Smrg
57577683534Smrg    if (pipe_option) {
57677683534Smrg	IGNORE_RC(pipe(p2c_waitpipe));
57777683534Smrg	IGNORE_RC(pipe(c2p_waitpipe));
57877683534Smrg    }
57977683534Smrg
58077683534Smrg    pid = fork();
58177683534Smrg    if (pid < 0) {
58277683534Smrg	perror("Couldn't fork");
58377683534Smrg	ExitProgram(1);
58477683534Smrg    }
58577683534Smrg
58677683534Smrg    if (pid == 0) {
58777683534Smrg	close(pty);
58877683534Smrg	if (pipe_option) {
58977683534Smrg	    close_waitpipe(1);
59077683534Smrg	}
59177683534Smrg	child(line, path, child_argv);
592a8fdb4bcSmrg    } else {
59377683534Smrg	if (pipe_option) {
59477683534Smrg	    close_waitpipe(0);
59577683534Smrg	}
59677683534Smrg	free(child_argv);
59777683534Smrg	free(path);
59877683534Smrg	free(line);
59977683534Smrg	parent(pid, pty);
600a8fdb4bcSmrg    }
601a8fdb4bcSmrg
602a8fdb4bcSmrg    return 0;
603a8fdb4bcSmrg}
604a8fdb4bcSmrg
605a8fdb4bcSmrgvoid
60677683534Smrgchild(char *line, char *path, char *const argv[])
607a8fdb4bcSmrg{
608a8fdb4bcSmrg    int tty;
609a8fdb4bcSmrg    int pgrp;
610a8fdb4bcSmrg
611a8fdb4bcSmrg    close(0);
612a8fdb4bcSmrg    close(1);
613a8fdb4bcSmrg    close(2);
614a8fdb4bcSmrg
615a8fdb4bcSmrg    pgrp = setsid();
61677683534Smrg    if (pgrp < 0) {
61777683534Smrg	kill(getppid(), SIGABRT);
61877683534Smrg	ExitProgram(1);
619a8fdb4bcSmrg    }
620a8fdb4bcSmrg
621a8fdb4bcSmrg    tty = openTty(line);
62277683534Smrg    if (tty < 0) {
62377683534Smrg	kill(getppid(), SIGABRT);
62477683534Smrg	ExitProgram(1);
62577683534Smrg    }
62677683534Smrg    if (pipe_option) {
62777683534Smrg	write_waitpipe(c2p_waitpipe);
62877683534Smrg    }
62977683534Smrg
63077683534Smrg    if (tty != 0)
63177683534Smrg	dup2(tty, 0);
63277683534Smrg    if (tty != 1)
63377683534Smrg	dup2(tty, 1);
63477683534Smrg    if (tty != 2)
63577683534Smrg	dup2(tty, 2);
63677683534Smrg
63777683534Smrg    if (tty > 2)
63877683534Smrg	close(tty);
63977683534Smrg
64077683534Smrg    if (pipe_option) {
64177683534Smrg	read_waitpipe(p2c_waitpipe);
64277683534Smrg	close_waitpipe(0);
643a8fdb4bcSmrg    }
64477683534Smrg
645a8fdb4bcSmrg    execvp(path, argv);
646a8fdb4bcSmrg    perror("Couldn't exec");
64777683534Smrg    ExitProgram(1);
648a8fdb4bcSmrg}
649a8fdb4bcSmrg
650a8fdb4bcSmrgvoid
65177683534Smrgparent(int pid GCC_UNUSED, int pty)
652a8fdb4bcSmrg{
653a8fdb4bcSmrg    unsigned char buf[BUFFER_SIZE];
654a8fdb4bcSmrg    int i;
655a8fdb4bcSmrg    int rc;
656a8fdb4bcSmrg
65777683534Smrg    if (pipe_option) {
65877683534Smrg	read_waitpipe(c2p_waitpipe);
659a8fdb4bcSmrg    }
660a8fdb4bcSmrg
66177683534Smrg    if (verbose) {
66277683534Smrg	reportIso2022(outputState);
66377683534Smrg    }
66477683534Smrg    setup_io(pty);
66577683534Smrg
66677683534Smrg    if (pipe_option) {
66777683534Smrg	write_waitpipe(p2c_waitpipe);
66877683534Smrg	close_waitpipe(1);
66977683534Smrg    }
67077683534Smrg
67177683534Smrg    for (;;) {
67277683534Smrg	rc = waitForInput(0, pty);
67377683534Smrg
67477683534Smrg	if (sigwinch_queued) {
67577683534Smrg	    sigwinch_queued = 0;
67677683534Smrg	    setWindowSize(0, pty);
67777683534Smrg	}
67877683534Smrg
67977683534Smrg	if (sigchld_queued && exitOnChild)
68077683534Smrg	    break;
68177683534Smrg
68277683534Smrg	if (rc > 0) {
68377683534Smrg	    if (rc & 2) {
68477683534Smrg		i = (int) read(pty, buf, (size_t) BUFFER_SIZE);
68577683534Smrg		if ((i == 0) || ((i < 0) && (errno != EAGAIN)))
68677683534Smrg		    break;
68777683534Smrg		if (i > 0)
68877683534Smrg		    copyOut(outputState, 0, buf, (unsigned) i);
68977683534Smrg	    }
69077683534Smrg	    if (rc & 1) {
69177683534Smrg		i = (int) read(0, buf, (size_t) BUFFER_SIZE);
69277683534Smrg		if ((i == 0) || ((i < 0) && (errno != EAGAIN)))
69377683534Smrg		    break;
69477683534Smrg		if (i > 0)
69577683534Smrg		    copyIn(inputState, pty, buf, i);
69677683534Smrg	    }
69777683534Smrg	}
698a8fdb4bcSmrg    }
699a8fdb4bcSmrg
700a8fdb4bcSmrg    restoreTermios();
70177683534Smrg    cleanup_io(pty);
70277683534Smrg}
70377683534Smrg
70477683534Smrg#ifdef NO_LEAKS
70577683534Smrgvoid
70677683534Smrgluit_leaks(void)
70777683534Smrg{
70877683534Smrg    destroyIso2022(inputState);
70977683534Smrg    destroyIso2022(outputState);
710a8fdb4bcSmrg}
71177683534Smrg#endif
712