Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * shell buffered IO and formatted output
3
 */
4
 
5
#include <ctype.h>
6
#include "sh.h"
7
#include "ksh_stat.h"
8
 
9
static int initio_done;
10
 
11
/*
12
 * formatted output functions
13
 */
14
 
15
 
16
/* A shell error occured (eg, syntax error, etc.) */
17
void
18
#ifdef HAVE_PROTOTYPES
19
errorf(const char *fmt, ...)
20
#else
21
errorf(fmt, va_alist)
22
	const char *fmt;
23
	va_dcl
24
#endif
25
{
26
	va_list va;
27
 
28
	shl_stdout_ok = 0;	/* debugging: note that stdout not valid */
29
	exstat = 1;
30
	if (*fmt) {
31
		error_prefix(TRUE);
32
		SH_VA_START(va, fmt);
33
		shf_vfprintf(shl_out, fmt, va);
34
		va_end(va);
35
		shf_putchar('\n', shl_out);
36
	}
37
	shf_flush(shl_out);
38
	unwind(LERROR);
39
}
40
 
41
/* like errorf(), but no unwind is done */
42
void
43
#ifdef HAVE_PROTOTYPES
44
warningf(int fileline, const char *fmt, ...)
45
#else
46
warningf(fileline, fmt, va_alist)
47
	int fileline;
48
	const char *fmt;
49
	va_dcl
50
#endif
51
{
52
	va_list va;
53
 
54
	error_prefix(fileline);
55
	SH_VA_START(va, fmt);
56
	shf_vfprintf(shl_out, fmt, va);
57
	va_end(va);
58
	shf_putchar('\n', shl_out);
59
	shf_flush(shl_out);
60
}
61
 
62
/* Used by built-in utilities to prefix shell and utility name to message
63
 * (also unwinds environments for special builtins).
64
 */
65
void
66
#ifdef HAVE_PROTOTYPES
67
bi_errorf(const char *fmt, ...)
68
#else
69
bi_errorf(fmt, va_alist)
70
	const char *fmt;
71
	va_dcl
72
#endif
73
{
74
	va_list va;
75
 
76
	shl_stdout_ok = 0;	/* debugging: note that stdout not valid */
77
	exstat = 1;
78
	if (*fmt) {
79
		error_prefix(TRUE);
80
		/* not set when main() calls parse_args() */
81
		if (builtin_argv0)
82
			shf_fprintf(shl_out, "%s: ", builtin_argv0);
83
		SH_VA_START(va, fmt);
84
		shf_vfprintf(shl_out, fmt, va);
85
		va_end(va);
86
		shf_putchar('\n', shl_out);
87
	}
88
	shf_flush(shl_out);
89
	/* POSIX special builtins and ksh special builtins cause
90
	 * non-interactive shells to exit.
91
	 * XXX odd use of KEEPASN; also may not want LERROR here
92
	 */
93
	if ((builtin_flag & SPEC_BI)
94
	    || (Flag(FPOSIX) && (builtin_flag & KEEPASN)))
95
	{
96
		builtin_argv0 = (char *) 0;
97
		unwind(LERROR);
98
	}
99
}
100
 
101
/* Called when something that shouldn't happen does */
102
void
103
#ifdef HAVE_PROTOTYPES
104
internal_errorf(int jump, const char *fmt, ...)
105
#else
106
internal_errorf(jump, fmt, va_alist)
107
	int jump;
108
	const char *fmt;
109
	va_dcl
110
#endif
111
{
112
	va_list va;
113
 
114
	error_prefix(TRUE);
115
	shf_fprintf(shl_out, "internal error: ");
116
	SH_VA_START(va, fmt);
117
	shf_vfprintf(shl_out, fmt, va);
118
	va_end(va);
119
	shf_putchar('\n', shl_out);
120
	shf_flush(shl_out);
121
	if (jump)
122
		unwind(LERROR);
123
}
124
 
125
/* used by error reporting functions to print "ksh: .kshrc[25]: " */
126
void
127
error_prefix(fileline)
128
	int fileline;
129
{
130
	/* Avoid foo: foo[2]: ... */
131
	if (!fileline || !source || !source->file
132
	    || strcmp(source->file, kshname) != 0)
133
		shf_fprintf(shl_out, "%s: ", kshname + (*kshname == '-'));
134
	if (fileline && source && source->file != NULL) {
135
		shf_fprintf(shl_out, "%s[%d]: ", source->file,
136
			source->errline > 0 ? source->errline : source->line);
137
		source->errline = 0;
138
	}
139
}
140
 
141
/* printf to shl_out (stderr) with flush */
142
void
143
#ifdef HAVE_PROTOTYPES
144
shellf(const char *fmt, ...)
145
#else
146
shellf(fmt, va_alist)
147
	const char *fmt;
148
	va_dcl
149
#endif
150
{
151
	va_list va;
152
 
153
	if (!initio_done) /* shl_out may not be set up yet... */
154
		return;
155
	SH_VA_START(va, fmt);
156
	shf_vfprintf(shl_out, fmt, va);
157
	va_end(va);
158
	shf_flush(shl_out);
159
}
160
 
161
/* printf to shl_stdout (stdout) */
162
void
163
#ifdef HAVE_PROTOTYPES
164
shprintf(const char *fmt, ...)
165
#else
166
shprintf(fmt, va_alist)
167
	const char *fmt;
168
	va_dcl
169
#endif
170
{
171
	va_list va;
172
 
173
	if (!shl_stdout_ok)
174
		internal_errorf(1, "shl_stdout not valid");
175
	SH_VA_START(va, fmt);
176
	shf_vfprintf(shl_stdout, fmt, va);
177
	va_end(va);
178
}
179
 
180
#ifdef KSH_DEBUG
181
static struct shf *kshdebug_shf;
182
 
183
void
184
kshdebug_init_()
185
{
186
	if (kshdebug_shf)
187
		shf_close(kshdebug_shf);
188
	kshdebug_shf = shf_open("/tmp/ksh-debug.log",
189
				O_WRONLY|O_APPEND|O_CREAT, 0600,
190
				SHF_WR|SHF_MAPHI);
191
	if (kshdebug_shf) {
192
		shf_fprintf(kshdebug_shf, "\nNew shell[pid %d]\n", getpid());
193
		shf_flush(kshdebug_shf);
194
	}
195
}
196
 
197
/* print to debugging log */
198
void
199
# ifdef HAVE_PROTOTYPES
200
kshdebug_printf_(const char *fmt, ...)
201
# else
202
kshdebug_printf_(fmt, va_alist)
203
	const char *fmt;
204
	va_dcl
205
# endif
206
{
207
	va_list va;
208
 
209
	if (!kshdebug_shf)
210
		return;
211
	SH_VA_START(va, fmt);
212
	shf_fprintf(kshdebug_shf, "[%d] ", getpid());
213
	shf_vfprintf(kshdebug_shf, fmt, va);
214
	va_end(va);
215
	shf_flush(kshdebug_shf);
216
}
217
 
218
void
219
kshdebug_dump_(str, mem, nbytes)
220
	const char *str;
221
	const void *mem;
222
	int nbytes;
223
{
224
	int i, j;
225
	int nprow = 16;
226
 
227
	if (!kshdebug_shf)
228
		return;
229
	shf_fprintf(kshdebug_shf, "[%d] %s:\n", getpid(), str);
230
	for (i = 0; i < nbytes; i += nprow) {
231
		char c = '\t';
232
		for (j = 0; j < nprow && i + j < nbytes; j++) {
233
			shf_fprintf(kshdebug_shf, "%c%02x",
234
				c, ((const unsigned char *) mem)[i + j]);
235
			c = ' ';
236
		}
237
		shf_fprintf(kshdebug_shf, "\n");
238
	}
239
	shf_flush(kshdebug_shf);
240
}
241
#endif /* KSH_DEBUG */
242
 
243
/* test if we can seek backwards fd (returns 0 or SHF_UNBUF) */
244
int
245
can_seek(fd)
246
	int fd;
247
{
248
	struct stat statb;
249
 
250
	return fstat(fd, &statb) == 0 && !S_ISREG(statb.st_mode) ?
251
		SHF_UNBUF : 0;
252
}
253
 
254
struct shf	shf_iob[3];
255
 
256
void
257
initio()
258
{
259
	shf_fdopen(1, SHF_WR, shl_stdout);	/* force buffer allocation */
260
	shf_fdopen(2, SHF_WR, shl_out);
261
	shf_fdopen(2, SHF_WR, shl_spare);	/* force buffer allocation */
262
	initio_done = 1;
263
	kshdebug_init();
264
}
265
 
266
/* A dup2() with error checking */
267
int
268
ksh_dup2(ofd, nfd, errok)
269
	int ofd;
270
	int nfd;
271
	int errok;
272
{
273
	int ret = dup2(ofd, nfd);
274
 
275
	if (ret < 0 && errno != EBADF && !errok)
276
		errorf("too many files open in shell");
277
 
278
#ifdef DUP2_BROKEN
279
	/* Ultrix systems like to preserve the close-on-exec flag */
280
	if (ret >= 0)
281
		(void) fcntl(nfd, F_SETFD, 0);
282
#endif /* DUP2_BROKEN */
283
 
284
	return ret;
285
}
286
 
287
/*
288
 * move fd from user space (0<=fd<10) to shell space (fd>=10),
289
 * set close-on-exec flag.
290
 */
291
int
292
savefd(fd, noclose)
293
	int fd;
294
	int noclose;
295
{
296
	int nfd;
297
 
298
	if (fd < FDBASE) {
299
		nfd = ksh_dupbase(fd, FDBASE);
300
		if (nfd < 0)
301
			if (errno == EBADF)
302
				return -1;
303
			else
304
				errorf("too many files open in shell");
305
		if (!noclose)
306
			close(fd);
307
	} else
308
		nfd = fd;
309
	fd_clexec(nfd);
310
	return nfd;
311
}
312
 
313
void
314
restfd(fd, ofd)
315
	int fd, ofd;
316
{
317
	if (fd == 2)
318
		shf_flush(&shf_iob[fd]);
319
	if (ofd < 0)		/* original fd closed */
320
		close(fd);
321
	else {
322
		ksh_dup2(ofd, fd, TRUE); /* XXX: what to do if this fails? */
323
		close(ofd);
324
	}
325
}
326
 
327
void
328
openpipe(pv)
329
	register int *pv;
330
{
331
	if (pipe(pv) < 0)
332
		errorf("can't create pipe - try again");
333
	pv[0] = savefd(pv[0], 0);
334
	pv[1] = savefd(pv[1], 0);
335
}
336
 
337
void
338
closepipe(pv)
339
	register int *pv;
340
{
341
	close(pv[0]);
342
	close(pv[1]);
343
}
344
 
345
/* Called by iosetup() (deals with 2>&4, etc.), c_read, c_print to turn
346
 * a string (the X in 2>&X, read -uX, print -uX) into a file descriptor.
347
 */
348
int
349
check_fd(name, mode, emsgp)
350
	char *name;
351
	int mode;
352
	const char **emsgp;
353
{
354
	int fd, fl;
355
 
356
	if (isdigit(name[0]) && !name[1]) {
357
		fd = name[0] - '0';
358
		if ((fl = fcntl(fd = name[0] - '0', F_GETFL, 0)) < 0) {
359
			if (emsgp)
360
				*emsgp = "bad file descriptor";
361
			return -1;
362
		}
363
		fl &= O_ACCMODE;
364
#ifdef OS2
365
		if (mode == W_OK ) { 
366
		       if (setmode(fd, O_TEXT) == -1) {
367
				if (emsgp)
368
					*emsgp = "couldn't set write mode";
369
				return -1;
370
			}
371
		 } else if (mode == R_OK)
372
	      		if (setmode(fd, O_BINARY) == -1) {
373
				if (emsgp)
374
					*emsgp = "couldn't set read mode";
375
				return -1; 
376
			}
377
#else /* OS2 */
378
		/* X_OK is a kludge to disable this check for dups (x<&1):
379
		 * historical shells never did this check (XXX don't know what
380
		 * posix has to say).
381
		 */
382
		if (!(mode & X_OK) && fl != O_RDWR
383
		    && (((mode & R_OK) && fl != O_RDONLY)
384
			|| ((mode & W_OK) && fl != O_WRONLY)))
385
		{
386
			if (emsgp)
387
				*emsgp = (fl == O_WRONLY) ?
388
						"fd not open for reading"
389
					      : "fd not open for writing";
390
			return -1;
391
		}
392
#endif /* OS2 */
393
		return fd;
394
	}
395
#ifdef KSH
396
	else if (name[0] == 'p' && !name[1])
397
		return coproc_getfd(mode, emsgp);
398
#endif /* KSH */
399
	if (emsgp)
400
		*emsgp = "illegal file descriptor name";
401
	return -1;
402
}
403
 
404
#ifdef KSH
405
/* Called once from main */
406
void
407
coproc_init()
408
{
409
	coproc.read = coproc.readw = coproc.write = -1;
410
	coproc.njobs = 0;
411
	coproc.id = 0;
412
}
413
 
414
/* Called by c_read() when eof is read - close fd if it is the co-process fd */
415
void
416
coproc_read_close(fd)
417
	int fd;
418
{
419
	if (coproc.read >= 0 && fd == coproc.read) {
420
		coproc_readw_close(fd);
421
		close(coproc.read);
422
		coproc.read = -1;
423
	}
424
}
425
 
426
/* Called by c_read() and by iosetup() to close the other side of the
427
 * read pipe, so reads will actually terminate.
428
 */
429
void
430
coproc_readw_close(fd)
431
	int fd;
432
{
433
	if (coproc.readw >= 0 && coproc.read >= 0 && fd == coproc.read) {
434
		close(coproc.readw);
435
		coproc.readw = -1;
436
	}
437
}
438
 
439
/* Called by c_print when a write to a fd fails with EPIPE and by iosetup
440
 * when co-process input is dup'd
441
 */
442
void
443
coproc_write_close(fd)
444
	int fd;
445
{
446
	if (coproc.write >= 0 && fd == coproc.write) {
447
		close(coproc.write);
448
		coproc.write = -1;
449
	}
450
}
451
 
452
/* Called to check for existance of/value of the co-process file descriptor.
453
 * (Used by check_fd() and by c_read/c_print to deal with -p option).
454
 */
455
int
456
coproc_getfd(mode, emsgp)
457
	int mode;
458
	const char **emsgp;
459
{
460
	int fd = (mode & R_OK) ? coproc.read : coproc.write;
461
 
462
	if (fd >= 0)
463
		return fd;
464
	if (emsgp)
465
		*emsgp = "no coprocess";
466
	return -1;
467
}
468
 
469
/* called to close file descriptors related to the coprocess (if any)
470
 * Should be called with SIGCHLD blocked.
471
 */
472
void
473
coproc_cleanup(reuse)
474
	int reuse;
475
{
476
	/* This to allow co-processes to share output pipe */
477
	if (!reuse || coproc.readw < 0 || coproc.read < 0) {
478
		if (coproc.read >= 0) {
479
			close(coproc.read);
480
			coproc.read = -1;
481
		}
482
		if (coproc.readw >= 0) {
483
			close(coproc.readw);
484
			coproc.readw = -1;
485
		}
486
	}
487
	if (coproc.write >= 0) {
488
		close(coproc.write);
489
		coproc.write = -1;
490
	}
491
}
492
#endif /* KSH */
493
 
494
 
495
/*
496
 * temporary files
497
 */
498
 
499
struct temp *
500
maketemp(ap, type, tlist)
501
	Area *ap;
502
	Temp_type type;
503
	struct temp **tlist;
504
{
505
	static unsigned int inc;
506
	struct temp *tp;
507
	int len;
508
	int fd;
509
	char *path;
510
	const char *dir;
511
 
512
	dir = tmpdir ? tmpdir : "/tmp";
513
	/* The 20 + 20 is a paranoid worst case for pid/inc */
514
	len = strlen(dir) + 3 + 20 + 20 + 1;
515
	tp = (struct temp *) alloc(sizeof(struct temp) + len, ap);
516
	tp->name = path = (char *) &tp[1];
517
	tp->shf = (struct shf *) 0;
518
	tp->type = type;
519
	while (1) {
520
		/* Note that temp files need to fit 8.3 DOS limits */
521
		shf_snprintf(path, len, "%s/sh%05u.%03x",
522
			     dir, (unsigned) procpid, inc++);
523
		/* Mode 0600 to be paranoid, O_TRUNC in case O_EXCL isn't
524
		 * really there.
525
		 */
526
		fd = open(path, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0600);
527
		if (fd >= 0) {
528
			tp->shf = shf_fdopen(fd, SHF_WR, (struct shf *) 0);
529
			break;
530
		}
531
		if (errno != EINTR
532
#ifdef EEXIST
533
		    && errno != EEXIST
534
#endif /* EEXIST */
535
#ifdef EISDIR
536
		    && errno != EISDIR
537
#endif /* EISDIR */
538
			)
539
			/* Error must be printed by caller: don't know here if
540
			 * errorf() or bi_errorf() should be used.
541
			 */
542
			break;
543
	}
544
	tp->next = NULL;
545
	tp->pid = procpid;
546
 
547
	tp->next = *tlist;
548
	*tlist = tp;
549
 
550
	return tp;
551
}