luit.c revision a8fdb4bc
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*/
22a8fdb4bcSmrg/* $XFree86: xc/programs/luit/luit.c,v 1.9 2002/10/17 01:06:09 dawes Exp $ */
23a8fdb4bcSmrg
24a8fdb4bcSmrg#include <stdio.h>
25a8fdb4bcSmrg#include <stdlib.h>
26a8fdb4bcSmrg#include <string.h>
27a8fdb4bcSmrg#include <locale.h>
28a8fdb4bcSmrg#include <sys/types.h>
29a8fdb4bcSmrg#include <fcntl.h>
30a8fdb4bcSmrg#include <unistd.h>
31a8fdb4bcSmrg#include <errno.h>
32a8fdb4bcSmrg#include <assert.h>
33a8fdb4bcSmrg#include <stdarg.h>
34a8fdb4bcSmrg#include <sys/ioctl.h>
35a8fdb4bcSmrg#include <signal.h>
36a8fdb4bcSmrg
37a8fdb4bcSmrg#ifdef SVR4
38a8fdb4bcSmrg#include <stropts.h>
39a8fdb4bcSmrg#endif
40a8fdb4bcSmrg
41a8fdb4bcSmrg#include <X11/fonts/fontenc.h>
42a8fdb4bcSmrg#include "luit.h"
43a8fdb4bcSmrg#include "sys.h"
44a8fdb4bcSmrg#include "other.h"
45a8fdb4bcSmrg#include "charset.h"
46a8fdb4bcSmrg#include "iso2022.h"
47a8fdb4bcSmrg
48a8fdb4bcSmrgstatic Iso2022Ptr inputState = NULL, outputState = NULL;
49a8fdb4bcSmrg
50a8fdb4bcSmrgstatic char *child_argv0 = NULL;
51a8fdb4bcSmrgstatic char *locale_name = NULL;
52a8fdb4bcSmrgint ilog = -1;
53a8fdb4bcSmrgint olog = -1;
54a8fdb4bcSmrgint verbose = 0;
55a8fdb4bcSmrgint converter = 0;
56a8fdb4bcSmrgint exitOnChild = 0;
57a8fdb4bcSmrg
58a8fdb4bcSmrgvolatile int sigwinch_queued = 0;
59a8fdb4bcSmrgvolatile int sigchld_queued = 0;
60a8fdb4bcSmrg
61a8fdb4bcSmrgstatic int convert(int, int);
62a8fdb4bcSmrgstatic int condom(int, char**);
63a8fdb4bcSmrg
64a8fdb4bcSmrgstatic void
65a8fdb4bcSmrgErrorF(char *f, ...)
66a8fdb4bcSmrg{
67a8fdb4bcSmrg    va_list args;
68a8fdb4bcSmrg    va_start(args, f);
69a8fdb4bcSmrg    vfprintf(stderr, f, args);
70a8fdb4bcSmrg    va_end(args);
71a8fdb4bcSmrg}
72a8fdb4bcSmrg
73a8fdb4bcSmrgstatic void
74a8fdb4bcSmrgFatalError(char *f, ...)
75a8fdb4bcSmrg{
76a8fdb4bcSmrg    va_list args;
77a8fdb4bcSmrg    va_start(args, f);
78a8fdb4bcSmrg    vfprintf(stderr, f, args);
79a8fdb4bcSmrg    va_end(args);
80a8fdb4bcSmrg    exit(1);
81a8fdb4bcSmrg}
82a8fdb4bcSmrg
83a8fdb4bcSmrg
84a8fdb4bcSmrgstatic void
85a8fdb4bcSmrghelp(void)
86a8fdb4bcSmrg{
87a8fdb4bcSmrg    fprintf(stderr,
88a8fdb4bcSmrg            "luit\n"
89a8fdb4bcSmrg            "  [ -h ] [ -list ] [ -v ] [ -argv0 name ]\n"
90a8fdb4bcSmrg            "  [ -gl gn ] [-gr gk] "
91a8fdb4bcSmrg            "[ -g0 set ] [ -g1 set ] "
92a8fdb4bcSmrg            "[ -g2 set ] [ -g3 set ]\n"
93a8fdb4bcSmrg            "  [ -encoding encoding ] "
94a8fdb4bcSmrg            "[ +oss ] [ +ols ] [ +osl ] [ +ot ]\n"
95a8fdb4bcSmrg            "  [ -kgl gn ] [-kgr gk] "
96a8fdb4bcSmrg            "[ -kg0 set ] [ -kg1 set ] "
97a8fdb4bcSmrg            "[ -kg2 set ] [ -kg3 set ]\n"
98a8fdb4bcSmrg            "  [ -k7 ] [ +kss ] [ +kssgr ] [ -kls ]\n"
99a8fdb4bcSmrg            "  [ -c ] [ -x ] [ -ilog filename ] [ -olog filename ] [ -- ]\n"
100a8fdb4bcSmrg            "  [ program [ args ] ]\n");
101a8fdb4bcSmrg
102a8fdb4bcSmrg}
103a8fdb4bcSmrg
104a8fdb4bcSmrg
105a8fdb4bcSmrgstatic int
106a8fdb4bcSmrgparseOptions(int argc, char **argv)
107a8fdb4bcSmrg{
108a8fdb4bcSmrg    int i = 1;
109a8fdb4bcSmrg    while(i < argc) {
110a8fdb4bcSmrg        if(argv[i][0] != '-' && argv[i][0] != '+') {
111a8fdb4bcSmrg            break;
112a8fdb4bcSmrg        } else if(!strcmp(argv[i], "--")) {
113a8fdb4bcSmrg            i++;
114a8fdb4bcSmrg            break;
115a8fdb4bcSmrg        } else if(!strcmp(argv[i], "-v")) {
116a8fdb4bcSmrg            verbose++;
117a8fdb4bcSmrg            i++;
118a8fdb4bcSmrg        } else if(!strcmp(argv[i], "-h")) {
119a8fdb4bcSmrg            help();
120a8fdb4bcSmrg            exit(0);
121a8fdb4bcSmrg        } else if(!strcmp(argv[i], "-list")) {
122a8fdb4bcSmrg            reportCharsets();
123a8fdb4bcSmrg            exit(0);
124a8fdb4bcSmrg        } else if(!strcmp(argv[i], "+oss")) {
125a8fdb4bcSmrg            outputState->outputFlags &= ~OF_SS;
126a8fdb4bcSmrg            i++;
127a8fdb4bcSmrg        } else if(!strcmp(argv[i], "+ols")) {
128a8fdb4bcSmrg            outputState->outputFlags &= ~OF_LS;
129a8fdb4bcSmrg            i++;
130a8fdb4bcSmrg        } else if(!strcmp(argv[i], "+osl")) {
131a8fdb4bcSmrg            outputState->outputFlags &= ~OF_SELECT;
132a8fdb4bcSmrg            i++;
133a8fdb4bcSmrg        } else if(!strcmp(argv[i], "+ot")) {
134a8fdb4bcSmrg            outputState->outputFlags = OF_PASSTHRU;
135a8fdb4bcSmrg            i++;
136a8fdb4bcSmrg        } else if(!strcmp(argv[i], "-k7")) {
137a8fdb4bcSmrg            inputState->inputFlags &= ~IF_EIGHTBIT;
138a8fdb4bcSmrg            i++;
139a8fdb4bcSmrg        } else if(!strcmp(argv[i], "+kss")) {
140a8fdb4bcSmrg            inputState->inputFlags &= ~IF_SS;
141a8fdb4bcSmrg            i++;
142a8fdb4bcSmrg        } else if(!strcmp(argv[1], "+kssgr")) {
143a8fdb4bcSmrg            inputState->inputFlags &= ~IF_SSGR;
144a8fdb4bcSmrg            i++;
145a8fdb4bcSmrg        } else if(!strcmp(argv[i], "-kls")) {
146a8fdb4bcSmrg            inputState->inputFlags |= IF_LS;
147a8fdb4bcSmrg            i++;
148a8fdb4bcSmrg        } else if(!strcmp(argv[i], "-g0")) {
149a8fdb4bcSmrg            if(i + 1 >= argc)
150a8fdb4bcSmrg                FatalError("-g0 requires an argument\n");
151a8fdb4bcSmrg            G0(outputState) = getCharsetByName(argv[i + 1]);
152a8fdb4bcSmrg            i += 2;
153a8fdb4bcSmrg        } else if(!strcmp(argv[i], "-g1")) {
154a8fdb4bcSmrg            if(i + 1 >= argc)
155a8fdb4bcSmrg                FatalError("-g1 requires an argument\n");
156a8fdb4bcSmrg            G1(outputState) = getCharsetByName(argv[i + 1]);
157a8fdb4bcSmrg            i += 2;
158a8fdb4bcSmrg        } else if(!strcmp(argv[i], "-g2")) {
159a8fdb4bcSmrg            if(i + 1 >= argc)
160a8fdb4bcSmrg                FatalError("-g2 requires an argument\n");
161a8fdb4bcSmrg            G2(outputState) = getCharsetByName(argv[i + 1]);
162a8fdb4bcSmrg            i += 2;
163a8fdb4bcSmrg        } else if(!strcmp(argv[i], "-g3")) {
164a8fdb4bcSmrg            if(i + 1 >= argc)
165a8fdb4bcSmrg                FatalError("-g3 requires an argument\n");
166a8fdb4bcSmrg            G3(outputState) = getCharsetByName(argv[i + 1]);
167a8fdb4bcSmrg
168a8fdb4bcSmrg            i += 2;
169a8fdb4bcSmrg        } else if(!strcmp(argv[i], "-gl")) {
170a8fdb4bcSmrg            int j;
171a8fdb4bcSmrg            if(i + 1 >= argc)
172a8fdb4bcSmrg                FatalError("-gl requires an argument\n");
173a8fdb4bcSmrg            if(strlen(argv[i + 1]) != 2 ||
174a8fdb4bcSmrg               argv[i + 1][0] != 'g')
175a8fdb4bcSmrg                j = -1;
176a8fdb4bcSmrg            else
177a8fdb4bcSmrg                j = argv[i + 1][1] - '0';
178a8fdb4bcSmrg            if(j < 0 || j > 3)
179a8fdb4bcSmrg                FatalError("The argument of -gl "
180a8fdb4bcSmrg                           "should be one of g0 through g3,\n"
181a8fdb4bcSmrg                           "not %s\n", argv[i + 1]);
182a8fdb4bcSmrg            else
183a8fdb4bcSmrg                outputState->glp = &outputState->g[j];
184a8fdb4bcSmrg            i += 2;
185a8fdb4bcSmrg        } else if(!strcmp(argv[i], "-gr")) {
186a8fdb4bcSmrg            int j;
187a8fdb4bcSmrg            if(i + 1 >= argc)
188a8fdb4bcSmrg                FatalError("-gr requires an argument\n");
189a8fdb4bcSmrg            if(strlen(argv[i + 1]) != 2 ||
190a8fdb4bcSmrg               argv[i + 1][0] != 'g')
191a8fdb4bcSmrg                j = -1;
192a8fdb4bcSmrg            else
193a8fdb4bcSmrg                j = argv[i + 1][1] - '0';
194a8fdb4bcSmrg            if(j < 0 || j > 3)
195a8fdb4bcSmrg                FatalError("The argument of -gl "
196a8fdb4bcSmrg                           "should be one of g0 through g3,\n"
197a8fdb4bcSmrg                           "not %s\n", argv[i + 1]);
198a8fdb4bcSmrg            else
199a8fdb4bcSmrg                outputState->grp = &outputState->g[j];
200a8fdb4bcSmrg            i += 2;
201a8fdb4bcSmrg        } else if(!strcmp(argv[i], "-kg0")) {
202a8fdb4bcSmrg            if(i + 1 >= argc)
203a8fdb4bcSmrg                FatalError("-kg0 requires an argument\n");
204a8fdb4bcSmrg            G0(inputState) = getCharsetByName(argv[i + 1]);
205a8fdb4bcSmrg            i += 2;
206a8fdb4bcSmrg        } else if(!strcmp(argv[i], "-kg1")) {
207a8fdb4bcSmrg            if(i + 1 >= argc)
208a8fdb4bcSmrg                FatalError("-kg1 requires an argument\n");
209a8fdb4bcSmrg            G1(inputState) = getCharsetByName(argv[i + 1]);
210a8fdb4bcSmrg            i += 2;
211a8fdb4bcSmrg        } else if(!strcmp(argv[i], "-kg2")) {
212a8fdb4bcSmrg            if(i + 1 >= argc)
213a8fdb4bcSmrg                FatalError("-kg2 requires an argument\n");
214a8fdb4bcSmrg            G2(inputState) = getCharsetByName(argv[i + 1]);
215a8fdb4bcSmrg            i += 2;
216a8fdb4bcSmrg        } else if(!strcmp(argv[i], "-kg3")) {
217a8fdb4bcSmrg            if(i + 1 >= argc)
218a8fdb4bcSmrg                FatalError("-kg3 requires an argument\n");
219a8fdb4bcSmrg            G3(inputState) = getCharsetByName(argv[i + 1]);
220a8fdb4bcSmrg
221a8fdb4bcSmrg            i += 2;
222a8fdb4bcSmrg        } else if(!strcmp(argv[i], "-kgl")) {
223a8fdb4bcSmrg            int j;
224a8fdb4bcSmrg            if(i + 1 >= argc)
225a8fdb4bcSmrg                FatalError("-kgl requires an argument\n");
226a8fdb4bcSmrg            if(strlen(argv[i + 1]) != 2 ||
227a8fdb4bcSmrg               argv[i + 1][0] != 'g')
228a8fdb4bcSmrg                j = -1;
229a8fdb4bcSmrg            else
230a8fdb4bcSmrg                j = argv[i + 1][1] - '0';
231a8fdb4bcSmrg            if(j < 0 || j > 3)
232a8fdb4bcSmrg                FatalError("The argument of -kgl "
233a8fdb4bcSmrg                           "should be one of g0 through g3,\n"
234a8fdb4bcSmrg                           "not %s\n", argv[i + 1]);
235a8fdb4bcSmrg            else
236a8fdb4bcSmrg                inputState->glp = &inputState->g[j];
237a8fdb4bcSmrg            i += 2;
238a8fdb4bcSmrg        } else if(!strcmp(argv[i], "-kgr")) {
239a8fdb4bcSmrg            int j;
240a8fdb4bcSmrg            if(i + 1 >= argc)
241a8fdb4bcSmrg                FatalError("-kgl requires an argument\n");
242a8fdb4bcSmrg            if(strlen(argv[i + 1]) != 2 ||
243a8fdb4bcSmrg               argv[i + 1][0] != 'g')
244a8fdb4bcSmrg                j = -1;
245a8fdb4bcSmrg            else
246a8fdb4bcSmrg                j = argv[i + 1][1] - '0';
247a8fdb4bcSmrg            if(j < 0 || j > 3)
248a8fdb4bcSmrg                FatalError("The argument of -kgl "
249a8fdb4bcSmrg                           "should be one of g0 through g3,\n"
250a8fdb4bcSmrg                           "not %s\n", argv[i + 1]);
251a8fdb4bcSmrg            else
252a8fdb4bcSmrg                inputState->grp = &inputState->g[j];
253a8fdb4bcSmrg            i += 2;
254a8fdb4bcSmrg        } else if(!strcmp(argv[i], "-argv0")) {
255a8fdb4bcSmrg            if(i + 1 >= argc)
256a8fdb4bcSmrg                FatalError("-argv0 requires an argument\n");
257a8fdb4bcSmrg            child_argv0 = argv[i + 1];
258a8fdb4bcSmrg            i += 2;
259a8fdb4bcSmrg        } else if(!strcmp(argv[i], "-x")) {
260a8fdb4bcSmrg            exitOnChild = 1;
261a8fdb4bcSmrg            i++;
262a8fdb4bcSmrg        } else if(!strcmp(argv[i], "-c")) {
263a8fdb4bcSmrg            converter = 1;
264a8fdb4bcSmrg            i++;
265a8fdb4bcSmrg        } else if(!strcmp(argv[i], "-ilog")) {
266a8fdb4bcSmrg            if(i + 1 >= argc)
267a8fdb4bcSmrg                FatalError("-ilog requires an argument\n");
268a8fdb4bcSmrg            ilog = open(argv[i + 1], O_WRONLY | O_CREAT | O_TRUNC, 0777);
269a8fdb4bcSmrg            if(ilog < 0) {
270a8fdb4bcSmrg                perror("Couldn't open input log");
271a8fdb4bcSmrg                exit(1);
272a8fdb4bcSmrg            }
273a8fdb4bcSmrg            i += 2;
274a8fdb4bcSmrg        } else if(!strcmp(argv[i], "-olog")) {
275a8fdb4bcSmrg            if(i + 1 >= argc)
276a8fdb4bcSmrg                FatalError("-olog requires an argument\n");
277a8fdb4bcSmrg            olog = open(argv[i + 1], O_WRONLY | O_CREAT | O_TRUNC, 0777);
278a8fdb4bcSmrg            if(olog < 0) {
279a8fdb4bcSmrg                perror("Couldn't open output log");
280a8fdb4bcSmrg                exit(1);
281a8fdb4bcSmrg            }
282a8fdb4bcSmrg            i += 2;
283a8fdb4bcSmrg        } else if(!strcmp(argv[i], "-encoding")) {
284a8fdb4bcSmrg            int rc;
285a8fdb4bcSmrg            if(i + 1 >= argc)
286a8fdb4bcSmrg                FatalError("-encoding requires an argument\n");
287a8fdb4bcSmrg            rc = initIso2022(NULL, argv[i + 1], outputState);
288a8fdb4bcSmrg            if(rc < 0)
289a8fdb4bcSmrg                FatalError("Couldn't init output state\n");
290a8fdb4bcSmrg            i += 2;
291a8fdb4bcSmrg        } else {
292a8fdb4bcSmrg            FatalError("Unknown option %s\n", argv[i]);
293a8fdb4bcSmrg        }
294a8fdb4bcSmrg    }
295a8fdb4bcSmrg    return i;
296a8fdb4bcSmrg}
297a8fdb4bcSmrg
298a8fdb4bcSmrgstatic int
299a8fdb4bcSmrgparseArgs(int argc, char **argv, char *argv0,
300a8fdb4bcSmrg          char **path_return, char ***argv_return)
301a8fdb4bcSmrg{
302a8fdb4bcSmrg    char *path = NULL;
303a8fdb4bcSmrg    char **child_argv = NULL;
304a8fdb4bcSmrg
305a8fdb4bcSmrg    if(argc <= 0) {
306a8fdb4bcSmrg        char *shell;
307a8fdb4bcSmrg        shell = getenv("SHELL");
308a8fdb4bcSmrg        if(shell) {
309a8fdb4bcSmrg            path = strdup(shell);
310a8fdb4bcSmrg        } else {
311a8fdb4bcSmrg            path = strdup("/bin/sh");
312a8fdb4bcSmrg        }
313a8fdb4bcSmrg        if(!path)
314a8fdb4bcSmrg            goto bail;
315a8fdb4bcSmrg        child_argv = malloc(2 * sizeof(char*));
316a8fdb4bcSmrg        if(!child_argv)
317a8fdb4bcSmrg            goto bail;
318a8fdb4bcSmrg        if(argv0)
319a8fdb4bcSmrg            child_argv[0] = argv0;
320a8fdb4bcSmrg        else
321a8fdb4bcSmrg            child_argv[0] = my_basename(path);
322a8fdb4bcSmrg        child_argv[1] = NULL;
323a8fdb4bcSmrg    } else {
324a8fdb4bcSmrg        path = strdup(argv[0]);
325a8fdb4bcSmrg        if(!path)
326a8fdb4bcSmrg            goto bail;
327a8fdb4bcSmrg        child_argv = malloc((argc + 1) * sizeof(char*));
328a8fdb4bcSmrg        if(!child_argv) {
329a8fdb4bcSmrg            goto bail;
330a8fdb4bcSmrg        }
331a8fdb4bcSmrg        if(child_argv0)
332a8fdb4bcSmrg            child_argv[0] = argv0;
333a8fdb4bcSmrg        else
334a8fdb4bcSmrg            child_argv[0] = my_basename(argv[0]);
335a8fdb4bcSmrg        memcpy(child_argv + 1, argv + 1, (argc - 1) * sizeof(char*));
336a8fdb4bcSmrg        child_argv[argc] = NULL;
337a8fdb4bcSmrg    }
338a8fdb4bcSmrg
339a8fdb4bcSmrg    *path_return = path;
340a8fdb4bcSmrg    *argv_return = child_argv;
341a8fdb4bcSmrg    return 0;
342a8fdb4bcSmrg
343a8fdb4bcSmrg  bail:
344a8fdb4bcSmrg    if(path)
345a8fdb4bcSmrg        free(path);
346a8fdb4bcSmrg    if(argv)
347a8fdb4bcSmrg        free(argv);
348a8fdb4bcSmrg    return -1;
349a8fdb4bcSmrg}
350a8fdb4bcSmrg
351a8fdb4bcSmrg
352a8fdb4bcSmrgint
353a8fdb4bcSmrgmain(int argc, char **argv)
354a8fdb4bcSmrg{
355a8fdb4bcSmrg    int rc;
356a8fdb4bcSmrg    int i;
357a8fdb4bcSmrg    char *l;
358a8fdb4bcSmrg
359a8fdb4bcSmrg    l = setlocale(LC_ALL, "");
360a8fdb4bcSmrg    if(!l)
361a8fdb4bcSmrg        ErrorF("Warning: couldn't set locale.\n");
362a8fdb4bcSmrg
363a8fdb4bcSmrg    inputState = allocIso2022();
364a8fdb4bcSmrg    if(!inputState)
365a8fdb4bcSmrg        FatalError("Couldn't create input state\n");
366a8fdb4bcSmrg
367a8fdb4bcSmrg    outputState = allocIso2022();
368a8fdb4bcSmrg    if(!outputState)
369a8fdb4bcSmrg        FatalError("Couldn't create output state\n");
370a8fdb4bcSmrg
371a8fdb4bcSmrg    if(l) {
372a8fdb4bcSmrg        locale_name = setlocale(LC_CTYPE, NULL);
373a8fdb4bcSmrg    } else {
374a8fdb4bcSmrg        locale_name = getenv("LC_ALL");
375a8fdb4bcSmrg        if(locale_name == NULL) {
376a8fdb4bcSmrg            locale_name = getenv("LC_CTYPE");
377a8fdb4bcSmrg            if(locale_name == NULL) {
378a8fdb4bcSmrg                locale_name = getenv("LANG");
379a8fdb4bcSmrg            }
380a8fdb4bcSmrg        }
381a8fdb4bcSmrg    }
382a8fdb4bcSmrg
383a8fdb4bcSmrg    if(locale_name == NULL) {
384a8fdb4bcSmrg        ErrorF("Couldn't get locale name -- using C\n");
385a8fdb4bcSmrg        locale_name = "C";
386a8fdb4bcSmrg    }
387a8fdb4bcSmrg
388a8fdb4bcSmrg    rc = initIso2022(locale_name, NULL, outputState);
389a8fdb4bcSmrg    if(rc < 0)
390a8fdb4bcSmrg        FatalError("Couldn't init output state\n");
391a8fdb4bcSmrg
392a8fdb4bcSmrg    i = parseOptions(argc, argv);
393a8fdb4bcSmrg    if(i < 0)
394a8fdb4bcSmrg        FatalError("Couldn't parse options\n");
395a8fdb4bcSmrg
396a8fdb4bcSmrg    rc = mergeIso2022(inputState, outputState);
397a8fdb4bcSmrg    if(rc < 0)
398a8fdb4bcSmrg        FatalError("Couldn't init input state\n");
399a8fdb4bcSmrg
400a8fdb4bcSmrg    if(converter)
401a8fdb4bcSmrg        return convert(0, 1);
402a8fdb4bcSmrg    else
403a8fdb4bcSmrg        return condom(argc - i, argv + i);
404a8fdb4bcSmrg}
405a8fdb4bcSmrg
406a8fdb4bcSmrgstatic int
407a8fdb4bcSmrgconvert(int ifd, int ofd)
408a8fdb4bcSmrg{
409a8fdb4bcSmrg    int rc, i;
410a8fdb4bcSmrg    unsigned char buf[BUFFER_SIZE];
411a8fdb4bcSmrg
412a8fdb4bcSmrg    rc = droppriv();
413a8fdb4bcSmrg    if(rc < 0) {
414a8fdb4bcSmrg        perror("Couldn't drop priviledges");
415a8fdb4bcSmrg        exit(1);
416a8fdb4bcSmrg    }
417a8fdb4bcSmrg
418a8fdb4bcSmrg    while(1) {
419a8fdb4bcSmrg        i = read(ifd, buf, BUFFER_SIZE);
420a8fdb4bcSmrg        if(i <= 0) {
421a8fdb4bcSmrg            if(i < 0) {
422a8fdb4bcSmrg                perror("Read error");
423a8fdb4bcSmrg                exit(1);
424a8fdb4bcSmrg            }
425a8fdb4bcSmrg            break;
426a8fdb4bcSmrg        }
427a8fdb4bcSmrg        copyOut(outputState, ofd, buf, i);
428a8fdb4bcSmrg    }
429a8fdb4bcSmrg    return 0;
430a8fdb4bcSmrg}
431a8fdb4bcSmrg
432a8fdb4bcSmrgstatic void
433a8fdb4bcSmrgsigwinchHandler(int sig)
434a8fdb4bcSmrg{
435a8fdb4bcSmrg    sigwinch_queued = 1;
436a8fdb4bcSmrg}
437a8fdb4bcSmrg
438a8fdb4bcSmrgstatic void
439a8fdb4bcSmrgsigchldHandler(int sig)
440a8fdb4bcSmrg{
441a8fdb4bcSmrg    sigchld_queued = 1;
442a8fdb4bcSmrg}
443a8fdb4bcSmrg
444a8fdb4bcSmrgstatic int
445a8fdb4bcSmrgcondom(int argc, char **argv)
446a8fdb4bcSmrg{
447a8fdb4bcSmrg    int pty;
448a8fdb4bcSmrg    int pid;
449a8fdb4bcSmrg    char *line;
450a8fdb4bcSmrg    char *path;
451a8fdb4bcSmrg    char **child_argv;
452a8fdb4bcSmrg    int rc;
453a8fdb4bcSmrg    int val;
454a8fdb4bcSmrg
455a8fdb4bcSmrg    rc = parseArgs(argc, argv, child_argv0,
456a8fdb4bcSmrg                   &path, &child_argv);
457a8fdb4bcSmrg    if(rc < 0)
458a8fdb4bcSmrg        FatalError("Couldn't parse arguments\n");
459a8fdb4bcSmrg
460a8fdb4bcSmrg    rc = allocatePty(&pty, &line);
461a8fdb4bcSmrg    if(rc < 0) {
462a8fdb4bcSmrg        perror("Couldn't allocate pty");
463a8fdb4bcSmrg        exit(1);
464a8fdb4bcSmrg    }
465a8fdb4bcSmrg
466a8fdb4bcSmrg    rc = droppriv();
467a8fdb4bcSmrg    if(rc < 0) {
468a8fdb4bcSmrg        perror("Couldn't drop priviledges");
469a8fdb4bcSmrg        exit(1);
470a8fdb4bcSmrg    }
471a8fdb4bcSmrg#ifdef SIGWINCH
472a8fdb4bcSmrg    installHandler(SIGWINCH, sigwinchHandler);
473a8fdb4bcSmrg#endif
474a8fdb4bcSmrg    installHandler(SIGCHLD, sigchldHandler);
475a8fdb4bcSmrg
476a8fdb4bcSmrg    rc = copyTermios(0, pty);
477a8fdb4bcSmrg    if(rc < 0)
478a8fdb4bcSmrg        FatalError("Couldn't copy terminal settings\n");
479a8fdb4bcSmrg
480a8fdb4bcSmrg    rc = setRawTermios();
481a8fdb4bcSmrg    if(rc < 0)
482a8fdb4bcSmrg        FatalError("Couldn't set terminal to raw\n");
483a8fdb4bcSmrg
484a8fdb4bcSmrg    val = fcntl(0, F_GETFL, 0);
485a8fdb4bcSmrg    if(val >= 0) {
486a8fdb4bcSmrg        fcntl(0, F_SETFL, val | O_NONBLOCK);
487a8fdb4bcSmrg    }
488a8fdb4bcSmrg    val = fcntl(pty, F_GETFL, 0);
489a8fdb4bcSmrg    if(val >= 0) {
490a8fdb4bcSmrg        fcntl(pty, F_SETFL, val | O_NONBLOCK);
491a8fdb4bcSmrg    }
492a8fdb4bcSmrg
493a8fdb4bcSmrg    setWindowSize(0, pty);
494a8fdb4bcSmrg
495a8fdb4bcSmrg    pid = fork();
496a8fdb4bcSmrg    if(pid < 0) {
497a8fdb4bcSmrg        perror("Couldn't fork");
498a8fdb4bcSmrg        exit(1);
499a8fdb4bcSmrg    }
500a8fdb4bcSmrg
501a8fdb4bcSmrg    if(pid == 0) {
502a8fdb4bcSmrg        close(pty);
503a8fdb4bcSmrg#ifdef SIGWINCH
504a8fdb4bcSmrg        installHandler(SIGWINCH, SIG_DFL);
505a8fdb4bcSmrg#endif
506a8fdb4bcSmrg        installHandler(SIGCHLD, SIG_DFL);
507a8fdb4bcSmrg        child(line, path, child_argv);
508a8fdb4bcSmrg    } else {
509a8fdb4bcSmrg        free(child_argv);
510a8fdb4bcSmrg        free(path);
511a8fdb4bcSmrg        free(line);
512a8fdb4bcSmrg        parent(pid, pty);
513a8fdb4bcSmrg    }
514a8fdb4bcSmrg
515a8fdb4bcSmrg    return 0;
516a8fdb4bcSmrg}
517a8fdb4bcSmrg
518a8fdb4bcSmrgvoid
519a8fdb4bcSmrgchild(char *line, char *path, char **argv)
520a8fdb4bcSmrg{
521a8fdb4bcSmrg    int tty;
522a8fdb4bcSmrg    int pgrp;
523a8fdb4bcSmrg
524a8fdb4bcSmrg    close(0);
525a8fdb4bcSmrg    close(1);
526a8fdb4bcSmrg    close(2);
527a8fdb4bcSmrg
528a8fdb4bcSmrg    pgrp = setsid();
529a8fdb4bcSmrg    if(pgrp < 0) {
530a8fdb4bcSmrg        kill(getppid(), SIGABRT);
531a8fdb4bcSmrg        exit(1);
532a8fdb4bcSmrg    }
533a8fdb4bcSmrg
534a8fdb4bcSmrg    tty = openTty(line);
535a8fdb4bcSmrg    if(tty < 0) {
536a8fdb4bcSmrg        kill(getppid(), SIGABRT);
537a8fdb4bcSmrg        exit(1);
538a8fdb4bcSmrg    }
539a8fdb4bcSmrg
540a8fdb4bcSmrg    if(tty != 0)
541a8fdb4bcSmrg        dup2(tty, 0);
542a8fdb4bcSmrg    if(tty != 1)
543a8fdb4bcSmrg        dup2(tty, 1);
544a8fdb4bcSmrg    if(tty != 2)
545a8fdb4bcSmrg        dup2(tty, 2);
546a8fdb4bcSmrg
547a8fdb4bcSmrg    if(tty > 2)
548a8fdb4bcSmrg        close(tty);
549a8fdb4bcSmrg
550a8fdb4bcSmrg    execvp(path, argv);
551a8fdb4bcSmrg    perror("Couldn't exec");
552a8fdb4bcSmrg    exit(1);
553a8fdb4bcSmrg}
554a8fdb4bcSmrg
555a8fdb4bcSmrgvoid
556a8fdb4bcSmrgparent(int pid, int pty)
557a8fdb4bcSmrg{
558a8fdb4bcSmrg    unsigned char buf[BUFFER_SIZE];
559a8fdb4bcSmrg    int i;
560a8fdb4bcSmrg    int rc;
561a8fdb4bcSmrg
562a8fdb4bcSmrg    if(verbose) {
563a8fdb4bcSmrg        reportIso2022(outputState);
564a8fdb4bcSmrg    }
565a8fdb4bcSmrg
566a8fdb4bcSmrg    for(;;) {
567a8fdb4bcSmrg        rc = waitForInput(0, pty);
568a8fdb4bcSmrg
569a8fdb4bcSmrg        if(sigwinch_queued) {
570a8fdb4bcSmrg            sigwinch_queued = 0;
571a8fdb4bcSmrg            setWindowSize(0, pty);
572a8fdb4bcSmrg        }
573a8fdb4bcSmrg
574a8fdb4bcSmrg        if(sigchld_queued && exitOnChild)
575a8fdb4bcSmrg            break;
576a8fdb4bcSmrg
577a8fdb4bcSmrg        if(rc > 0) {
578a8fdb4bcSmrg            if(rc & 2) {
579a8fdb4bcSmrg                i = read(pty, buf, BUFFER_SIZE);
580a8fdb4bcSmrg                if((i == 0) || ((i < 0) && (errno != EAGAIN)))
581a8fdb4bcSmrg                    break;
582a8fdb4bcSmrg                if(i > 0)
583a8fdb4bcSmrg                    copyOut(outputState, 0, buf, i);
584a8fdb4bcSmrg            }
585a8fdb4bcSmrg            if(rc & 1) {
586a8fdb4bcSmrg                i = read(0, buf, BUFFER_SIZE);
587a8fdb4bcSmrg                if((i == 0) || ((i < 0) && (errno != EAGAIN)))
588a8fdb4bcSmrg                    break;
589a8fdb4bcSmrg                if(i > 0)
590a8fdb4bcSmrg                    copyIn(inputState, pty, buf, i);
591a8fdb4bcSmrg            }
592a8fdb4bcSmrg        }
593a8fdb4bcSmrg    }
594a8fdb4bcSmrg
595a8fdb4bcSmrg    restoreTermios();
596a8fdb4bcSmrg}
597