Annotation of dgamelaunch-openbsd/ttyrec.c, Revision 1.1.1.1
1.1 rubenllo 1: /*
2: * Copyright (c) 1980 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: * 3. All advertising materials mentioning features or use of this software
14: * must display the following acknowledgement:
15: * This product includes software developed by the University of
16: * California, Berkeley and its contributors.
17: * 4. Neither the name of the University nor the names of its contributors
18: * may be used to endorse or promote products derived from this software
19: * without specific prior written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31: * SUCH DAMAGE.
32: */
33:
34: /* 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
35: * - added Native Language Support
36: */
37:
38: /* 2000-12-27 Satoru Takabayashi <satoru@namazu.org>
39: * - modify `script' to create `ttyrec'.
40: */
41:
42: /*
43: * script
44: */
45:
46: #include "dgamelaunch.h"
47: #include "config.h"
48:
49: #include <sys/types.h>
50: #include <sys/stat.h>
51: #include <sys/ioctl.h>
52: #include <sys/time.h>
53: #include <sys/wait.h>
54: #include <fcntl.h>
55:
56: #include <termios.h>
57: #include <time.h>
58: #include <signal.h>
59: #include <stdio.h>
60: #include <unistd.h>
61: #include <string.h>
62: #ifndef NOSTREAMS
63: # include <stropts.h>
64: #endif
65: #include <stdlib.h>
66: #include <stdint.h>
67:
68: #include "ttyrec.h"
69: #include "io.h"
70:
71: #ifndef XCASE
72: # define XCASE 0
73: #endif
74: static void query_encoding(int game, char *username);
75:
76: int slave;
77: pid_t dgl_parent;
78: pid_t child, subchild;
79: pid_t input_child;
80: char* ipfile = NULL;
81:
82: volatile int wait_for_menu = 0;
83:
84: FILE *fscript;
85: int master;
86:
87: struct termios tt;
88: struct winsize win;
89:
90: char last_ttyrec[512] = { '\0' };
91:
92: int ancient_encoding = 0;
93:
94: void
95: ttyrec_id(int game, char *username, char *ttyrec_filename)
96: {
97: int i;
98: time_t tstamp;
99: Header h;
100: char *buf = (char *)malloc(1024);
101: char tmpbuf[256];
102: char *server_id = banner_var_value("$SERVERID");
103: if (!buf) return;
104:
105: tstamp = time(NULL);
106:
107: #define dCLRSCR "\033[2J"
108: #define dCRLF "\r\n"
109: snprintf(buf, 1024,
110: dCLRSCR "\033[1;1H" dCRLF
111: "Player: %s" dCRLF
112: "Game: %s" dCRLF
113: "Server: %s" dCRLF
114: "Filename: %s" dCRLF
115: "Time: (%lu) %s" dCRLF
116: dCLRSCR,
117: username,
118: myconfig[game]->game_name,
119: (server_id ? server_id : "Unknown"),
120: ttyrec_filename,
121: tstamp, ctime(&tstamp)
122: );
123: #undef dCLRSCR
124: #undef dCRLF
125: h.len = strlen(buf);
126: gettimeofday (&h.tv, NULL);
127:
128: (void) write_header(fscript, &h);
129: (void) fwrite(buf, 1, h.len, fscript);
130:
131: free(buf);
132: }
133:
134: int
135: ttyrec_main (int game, char *username, char *ttyrec_path, char* ttyrec_filename)
136: {
137: char dirname[100];
138:
139: /* Note our PID to let children kill the main dgl process for idling */
140: dgl_parent = getpid();
141: child = subchild = input_child = 0;
142:
143: if (!ttyrec_path) {
144: child = fork();
145: if (child < 0) {
146: perror ("fork");
147: fail ();
148: }
149: if (child == 0) {
150: execvp (myconfig[game]->game_path, myconfig[game]->bin_args);
151: } else {
152: int status;
153: (void) wait(&status);
154: }
155: return 0;
156: }
157:
158: if (ttyrec_path[strlen(ttyrec_path)-1] == '/')
159: snprintf (dirname, 100, "%s%s", ttyrec_path, ttyrec_filename);
160: else
161: snprintf (dirname, 100, "%s/%s", ttyrec_path, ttyrec_filename);
162: ancient_encoding = myconfig[game]->encoding;
163: if (ancient_encoding == -1)
164: query_encoding(game, username);
165:
166: snprintf(last_ttyrec, 512, "%s", dirname);
167:
168: atexit(&remove_ipfile);
169: if ((fscript = fopen (dirname, "w")) == NULL)
170: {
171: perror (dirname);
172: fail ();
173: }
174: setbuf (fscript, NULL);
175:
176: fixtty ();
177:
178: (void) signal (SIGCHLD, finish);
179: child = fork ();
180: if (child < 0)
181: {
182: perror ("fork");
183: fail ();
184: }
185: if (child == 0)
186: {
187: subchild = child = fork ();
188: if (child < 0)
189: {
190: perror ("fork");
191: fail ();
192: }
193: if (child)
194: {
195: close (slave);
196: ipfile = gen_inprogress_lock (game, child, ttyrec_filename);
197: ttyrec_id(game, username, ttyrec_filename);
198: dooutput (myconfig[game]->max_idle_time);
199: }
200: else
201: doshell (game, username);
202: }
203:
204: (void) fclose (fscript);
205:
206: wait_for_menu = 1;
207: input_child = fork();
208: if (input_child < 0)
209: {
210: perror ("fork2");
211: fail ();
212: }
213: if (!input_child)
214: doinput ();
215: else
216: {
217: while (wait_for_menu)
218: sleep(1);
219: }
220:
221: remove_ipfile();
222: child = 0;
223:
224: return 0;
225: }
226:
227: void
228: doinput ()
229: {
230: register int cc;
231: char ibuf[BUFSIZ];
232:
233: while ((cc = read (0, ibuf, BUFSIZ)) > 0)
234: (void) write (master, ibuf, cc);
235: done ();
236: }
237:
238: void
239: finish (int sig)
240: {
241: int status;
242: register int pid;
243: register int die = 0;
244:
245: (void)sig; /* unused */
246:
247: while ((pid = wait3 (&status, WNOHANG, 0)) > 0)
248: {
249: if (pid == child)
250: die = 1;
251: }
252:
253: if (die)
254: {
255: if (input_child)
256: {
257: // Need to kill the child that's writing input to pty.
258: kill(input_child, SIGTERM);
259: while ((pid = wait3(&status, WNOHANG, 0)) > 0);
260: }
261: else
262: done ();
263: }
264: wait_for_menu = 0;
265: }
266:
267: void
268: game_idle_kill(int signal)
269: {
270: kill(child, SIGHUP);
271: kill(dgl_parent, SIGHUP);
272: }
273:
274: static unsigned short charset_vt100[128] =
275: {
276: 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
277: 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
278: 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
279: 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
280: 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
281: 0x0028, 0x0029, 0x002a, 0x2192, 0x2190, 0x2191, 0x2193, 0x002f,
282: 0x2588, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
283: 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
284: 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
285: 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
286: 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
287: 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x00a0,
288: #if 0
289: 0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1,
290: 0x2591, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0xf800,
291: 0xf801, 0x2500, 0xf803, 0xf804, 0x251c, 0x2524, 0x2534, 0x252c,
292: 0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, 0x007f,
293: #endif
294: 0x2666, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1,
295: 0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba,
296: 0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c,
297: 0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, 0x0020,
298: };
299:
300: static unsigned short charset_cp437[256] =
301: {
302: // Real IBM charset has no control codes, but they are needed by
303: // terminals.
304: 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
305: 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
306: 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
307: 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
308: #if 0
309: 0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022,
310: 0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c,
311: 0x25b6, 0x25c0, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac, 0x21a8,
312: 0x2191, 0x2193, 0x2192, 0x2190, 0x221f, 0x2194, 0x25b2, 0x25bc,
313: #endif
314: 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
315: 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
316: 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
317: 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
318: 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
319: 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
320: 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
321: 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
322: 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
323: 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
324: 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
325: 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302,
326: 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
327: 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
328: 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
329: 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
330: 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba,
331: 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
332: 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
333: 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
334: 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
335: 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
336: 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b,
337: 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
338: 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
339: 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229,
340: 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248,
341: 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0,
342: };
343:
344: // there must be at least 4 bytes free, NOT CHECKED!
345: static int wctoutf8(char *d, uint32_t s)
346: {
347: if (s < 0x80)
348: {
349: d[0] = s;
350: return 1;
351: }
352: if (s < 0x800)
353: {
354: d[0] = ( s >> 6) | 0xc0;
355: d[1] = ( s & 0x3f) | 0x80;
356: return 2;
357: }
358: if (s < 0x10000)
359: {
360: d[0] = ( s >> 12) | 0xe0;
361: d[1] = ((s >> 6) & 0x3f) | 0x80;
362: d[2] = ( s & 0x3f) | 0x80;
363: return 3;
364: }
365: if (s < 0x110000)
366: {
367: d[0] = ( s >> 18) | 0xf0;
368: d[1] = ((s >> 12) & 0x3f) | 0x80;
369: d[2] = ((s >> 6) & 0x3f) | 0x80;
370: d[3] = ( s & 0x3f) | 0x80;
371: return 4;
372: }
373: // Invalid char marker (U+FFFD).
374: d[0] = 0xef;
375: d[1] = 0xbf;
376: d[2] = 0xbd;
377: return 3;
378: }
379:
380: void
381: dooutput (int max_idle_time)
382: {
383: int cc, i, len;
384: time_t tvec, time ();
385: char obuf[BUFSIZ], ubuf[BUFSIZ*4+2], *ctime (), *out;
386: int galt = 0; // vt100 G switch
387:
388: setbuf (stdout, NULL);
389: (void) close (0);
390: tvec = time ((time_t *) NULL);
391: /* Set up SIGALRM handler to kill idle games */
392: signal(SIGALRM, game_idle_kill);
393: for (;;)
394: {
395: Header h;
396:
397: cc = read (master, obuf, BUFSIZ);
398: if (cc <= 0)
399: break;
400:
401: if (max_idle_time)
402: alarm(max_idle_time);
403:
404: switch (ancient_encoding)
405: {
406: case 0: // UTF-8
407: default:
408: h.len = cc;
409: gettimeofday (&h.tv, NULL);
410: (void) write (1, obuf, cc);
411: (void) write_header (fscript, &h);
412: (void) fwrite (obuf, 1, cc, fscript);
413: break;
414: case 1: // IBM
415: out = ubuf;
416: // Old Crawl emits useless toggles of vt100 mode, even though it
417: // never uses them in this mode. And they break stuff...
418: for (i = 0; i < cc; i++)
419: {
420: if (galt == 2) // ignore "ESC ( 0", "ESC ( B" and anything such
421: {
422: galt = 0;
423: continue;
424: }
425: else if (galt == 1)
426: if (obuf[i] == '(')
427: {
428: galt = 2;
429: continue;
430: }
431: else
432: {
433: galt = 0; // false alarm, emit ESC and continue
434: *out ++ = 27;
435: }
436: else if (obuf[i] == 27)
437: {
438: galt = 1;
439: continue;
440: }
441: else if (obuf[i] == 14 || obuf[i] == 15)
442: continue;
443: out += wctoutf8(out, charset_cp437[(unsigned char)obuf[i]]);
444: }
445: h.len = len = out - ubuf;
446: gettimeofday(&h.tv, NULL);
447: write(1, ubuf, len);
448: write_header(fscript, &h);
449: fwrite(ubuf, 1, len, fscript);
450: break;
451: case 2: // DEC
452: out = ubuf;
453: for (i = 0; i < cc; i++)
454: {
455: if (obuf[i] == 14)
456: galt = 1;
457: else if (obuf[i] == 15)
458: galt = 0;
459: else if (obuf[i] & 0x80) // strictly 7-bit
460: out += wctoutf8(out, 0xFFFD); // or we could assume some other charset
461: else if (galt)
462: out += wctoutf8(out, charset_vt100[(int)obuf[i]]);
463: else
464: *out++ = obuf[i];
465: }
466: h.len = len = out - ubuf;
467: gettimeofday(&h.tv, NULL);
468: write(1, ubuf, len);
469: write_header(fscript, &h);
470: fwrite(ubuf, 1, len, fscript);
471: break;
472: }
473: }
474: done ();
475: }
476:
477: void
478: doshell (int game, char *username)
479: {
480: getslave ();
481: (void) close (master);
482: (void) fclose (fscript);
483: (void) dup2 (slave, 0);
484: (void) dup2 (slave, 1);
485: (void) dup2 (slave, 2);
486: (void) close (slave);
487:
488: /*
489: if (myconfig[game]->mkdir)
490: (void) mkdir(myconfig[game]->mkdir, 0755);
491:
492: if (myconfig[game]->chdir)
493: (void) chdir(myconfig[game]->chdir);
494: */
495:
496: execvp (myconfig[game]->game_path, myconfig[game]->bin_args);
497:
498: fail ();
499: }
500:
501: void
502: fixtty ()
503: {
504: struct termios rtt;
505:
506: rtt = tt;
507: rtt.c_iflag = 0;
508: rtt.c_lflag &= ~(ISIG | ICANON | XCASE | ECHO | ECHOE | ECHOK | ECHONL);
509: rtt.c_oflag = OPOST;
510: rtt.c_cc[VINTR] = _POSIX_VDISABLE;
511: rtt.c_cc[VQUIT] = _POSIX_VDISABLE;
512: rtt.c_cc[VERASE] = _POSIX_VDISABLE;
513: rtt.c_cc[VKILL] = _POSIX_VDISABLE;
514: rtt.c_cc[VEOF] = 1;
515: rtt.c_cc[VEOL] = 0;
516: rtt.c_cc[VMIN] = 1;
517: rtt.c_cc[VTIME] = 0;
518: (void) tcsetattr (0, TCSAFLUSH, &rtt);
519: }
520:
521: void
522: fail ()
523: {
524:
525: (void) kill (0, SIGTERM);
526: done ();
527: }
528:
529: void
530: done ()
531: {
532: time_t tvec, time ();
533: char *ctime ();
534:
535: if (subchild)
536: {
537: tvec = time ((time_t *) NULL);
538: (void) fclose (fscript);
539: (void) close (master);
540: }
541: else
542: {
543: (void) tcsetattr (0, TCSAFLUSH, &tt);
544: }
545:
546: remove_ipfile();
547: graceful_exit (0);
548: }
549:
550: void
551: getslave ()
552: {
553: (void) setsid ();
554: /* grantpt( master);
555: unlockpt(master);
556: if ((slave = open((const char *)ptsname(master), O_RDWR)) < 0) {
557: perror((const char *)ptsname(master));
558: fail();
559: perror("open(fd, O_RDWR)");
560: fail();
561: } */
562: #ifndef NOSTREAMS
563: if (isastream (slave))
564: {
565: if (ioctl (slave, I_PUSH, "ptem") < 0)
566: {
567: perror ("ioctl(fd, I_PUSH, ptem)");
568: fail ();
569: }
570: if (ioctl (slave, I_PUSH, "ldterm") < 0)
571: {
572: perror ("ioctl(fd, I_PUSH, ldterm)");
573: fail ();
574: }
575: #ifndef _HPUX_SOURCE
576: if (ioctl (slave, I_PUSH, "ttcompat") < 0)
577: {
578: perror ("ioctl(fd, I_PUSH, ttcompat)");
579: fail ();
580: }
581: #endif
582: }
583: #endif /* !NOSTREAMS */
584: (void) ioctl (0, TIOCGWINSZ, (char *) &win);
585: }
586:
587: void
588: remove_ipfile (void)
589: {
590: if (ipfile != NULL) {
591: unlink (ipfile);
592: free(ipfile);
593: ipfile = NULL;
594: }
595: signal(SIGALRM, SIG_IGN);
596: }
597:
598: int encoding_by_name(const char *enc)
599: {
600: if (!strcasecmp(enc, "UTF-8") || !strcasecmp(enc, "UNICODE"))
601: return 0;
602: if (!strcasecmp(enc, "IBM") || !strcasecmp(enc, "CP437"))
603: return 1;
604: if (!strcasecmp(enc, "DEC"))
605: return 2;
606: if (!strcasecmp(enc, "ASCII"))
607: return 1; // what to do with invalid chars?
608: return -1;
609: }
610:
611: static void call_print_charset(char *exe, char **args)
612: {
613: char **args2, **a;
614: int nargs = 0;
615: for (args2 = args; *args2; args2++)
616: nargs++;
617: args2 = calloc(nargs + 1, sizeof(char*));
618: for (a = args2; *args; args++)
619: *a++ = *args;
620:
621: *a++ = "--print-charset";
622: *a = 0;
623: execvp(exe, args2);
624: }
625:
626: static void query_encoding(int game, char *username)
627: {
628: int son;
629: int p[2];
630: int null;
631: struct timeval tv;
632: fd_set se;
633: char buf[128];
634:
635: if (pipe(p))
636: perror("pipe");
637: switch(son = fork())
638: {
639: case -1:
640: perror("fork");
641: fail();
642: case 0:
643: null = open("/dev/null", O_RDONLY);
644: if (null != -1)
645: dup2(null, 0), close(null);
646: else
647: {
648: fprintf(stderr, "Error: can't open /dev/null\n");
649: // non-fatal, but if the child opens some other file, it might
650: // get confused
651: close(0);
652: }
653: dup2(p[1], 1);
654: close(p[1]);
655: close(p[0]);
656: call_print_charset(myconfig[game]->game_path, myconfig[game]->bin_args);
657: exit(1);
658: }
659: close(p[1]);
660:
661: FD_ZERO(&se);
662: FD_SET(p[0],&se);
663: tv.tv_sec = 60; // FIXME: a huge delay, in case there's a db rebuild
664: tv.tv_usec = 0;
665: if (select(p[0]+1,&se,NULL,NULL,&tv) != 1)
666: {
667: fprintf(stderr, "Error: can't obtain charset info.\nPress any key...\n");
668: read(0, buf, 1);
669: close(p[0]); // SIGPIPE
670: kill(son, SIGTERM); // and SIGTERM for a good measure
671: waitpid(son, 0, 0);
672: ancient_encoding = 0;
673: return;
674: }
675:
676: // Sending _one_ short message over a pipe is atomic on all systems I know.
677: // Don't assume this on about any other file descriptor.
678: read(p[0], buf, sizeof(buf)-1);
679: buf[sizeof(buf)-1] = 0;
680: close(p[0]);
681: kill(son, SIGTERM);
682: waitpid(son, 0, 0);
683: if (strchr(buf, '\n'))
684: *strchr(buf, '\n') = 0;
685: ancient_encoding = encoding_by_name(buf);
686: if (ancient_encoding == -1)
687: {
688: fprintf(stderr, "Error: unknown encoding \"%s\"\nPress any key...\n", buf);
689: read(0, buf, 1);
690: }
691: }
CVSweb