xref: /illumos-gate/usr/src/cmd/sh/io.c (revision e0ddff35438f277370a2eae5c6718cd5ba0fe3ab)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 
23 /*
24  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
29 /*	  All Rights Reserved  	*/
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 /*
33  * UNIX shell
34  */
35 
36 #include	"defs.h"
37 #include	"dup.h"
38 #include	<stdio.h>
39 #include	<fcntl.h>
40 #include	<sys/types.h>
41 #include	<sys/stat.h>
42 #include	<errno.h>
43 
44 short topfd;
45 
46 /* ========	input output and file copying ======== */
47 
48 void
49 initf(int fd)
50 {
51 	struct fileblk *f = standin;
52 
53 	f->fdes = fd;
54 	f->fsiz = ((flags & oneflg) == 0 ? BUFFERSIZE : 1);
55 	f->fnxt = f->fend = f->fbuf;
56 	f->nxtoff = f->endoff = 0;
57 	f->feval = 0;
58 	f->flin = 1;
59 	f->feof = FALSE;
60 }
61 
62 int
63 estabf(unsigned char *s)
64 {
65 	struct fileblk *f;
66 
67 	(f = standin)->fdes = -1;
68 	f->fend = length(s) + (f->fnxt = s);
69 	f->nxtoff = 0;
70 	f->endoff = length(s);
71 	f->flin = 1;
72 	return (f->feof = (s == 0));
73 }
74 
75 void
76 push(struct fileblk *af)
77 {
78 	struct fileblk *f;
79 
80 	(f = af)->fstak = standin;
81 	f->feof = 0;
82 	f->feval = 0;
83 	standin = f;
84 }
85 
86 int
87 pop(void)
88 {
89 	struct fileblk *f;
90 
91 	if ((f = standin)->fstak)
92 	{
93 		if (f->fdes >= 0)
94 			close(f->fdes);
95 		standin = f->fstak;
96 		return (TRUE);
97 	}else
98 		return (FALSE);
99 }
100 
101 struct tempblk *tmpfptr;
102 
103 void
104 pushtemp(int fd, struct tempblk *tb)
105 {
106 	tb->fdes = fd;
107 	tb->fstak = tmpfptr;
108 	tmpfptr = tb;
109 }
110 
111 int
112 poptemp(void)
113 {
114 	if (tmpfptr){
115 		close(tmpfptr->fdes);
116 		tmpfptr = tmpfptr->fstak;
117 		return (TRUE);
118 	}else
119 		return (FALSE);
120 }
121 
122 void
123 chkpipe(int *pv)
124 {
125 	if (pipe(pv) < 0 || pv[INPIPE] < 0 || pv[OTPIPE] < 0)
126 		error(piperr);
127 }
128 
129 int
130 chkopen(unsigned char *idf, int mode)
131 {
132 	int	rc;
133 
134 	if ((rc = open((char *)idf, mode, 0666)) < 0)
135 		failed(idf, badopen);
136 	else
137 		return (rc);
138 }
139 
140 /*
141  * Make f2 be a synonym (including the close-on-exec flag) for f1, which is
142  * then closed.  If f2 is descriptor 0, modify the global ioset variable
143  * accordingly.
144  */
145 void
146 renamef(int f1, int f2)
147 {
148 #ifdef RES
149 	if (f1 != f2)
150 	{
151 		dup(f1 | DUPFLG, f2);
152 		close(f1);
153 		if (f2 == 0)
154 			ioset |= 1;
155 	}
156 #else
157 	int	fs;
158 
159 	if (f1 != f2)
160 	{
161 		fs = fcntl(f2, 1, 0);
162 		close(f2);
163 		fcntl(f1, 0, f2);
164 		close(f1);
165 		if (fs == 1)
166 			fcntl(f2, 2, 1);
167 		if (f2 == 0)
168 			ioset |= 1;
169 	}
170 #endif
171 }
172 
173 int
174 create(unsigned char *s)
175 {
176 	int	rc;
177 
178 	if ((rc = creat((char *)s, 0666)) < 0)
179 		failed(s, badcreate);
180 	else
181 		return (rc);
182 }
183 
184 
185 int
186 tmpfil(struct tempblk *tb)
187 {
188 	int fd;
189 	int len;
190 	size_t size_left = TMPOUTSZ - tmpout_offset;
191 
192 	/* make sure tmp file does not already exist. */
193 	do {
194 		len = snprintf((char *)&tmpout[tmpout_offset], size_left,
195 		    "%u", serial);
196 		fd = open((char *)tmpout, O_RDWR|O_CREAT|O_EXCL, 0600);
197 		serial++;
198 		if ((serial >= UINT_MAX) || (len >= size_left)) {
199 			/*
200 			 * We've already cycled through all the possible
201 			 * numbers or the tmp file name is being
202 			 * truncated anyway (although TMPOUTSZ should be
203 			 * big enough), so start over.
204 			 */
205 			serial = 0;
206 			break;
207 		}
208 	} while ((fd == -1) && (errno == EEXIST));
209 	if (fd != -1) {
210 		pushtemp(fd, tb);
211 		return (fd);
212 	}
213 	else
214 		failed(tmpout, badcreate);
215 }
216 
217 /*
218  * set by trim
219  */
220 extern BOOL		nosubst;
221 #define			CPYSIZ		512
222 
223 void
224 copy(struct ionod	*ioparg)
225 {
226 	unsigned char	*cline;
227 	unsigned char	*clinep;
228 	struct ionod	*iop;
229 	unsigned int	c;
230 	unsigned char	*ends;
231 	unsigned char	*start;
232 	int		fd;
233 	int		i;
234 	int		stripflg;
235 	unsigned char	*pc;
236 
237 
238 	if (iop = ioparg)
239 	{
240 		struct tempblk tb;
241 		copy(iop->iolst);
242 		ends = mactrim(iop->ioname);
243 		stripflg = iop->iofile & IOSTRIP;
244 		if (nosubst)
245 			iop->iofile &= ~IODOC;
246 		fd = tmpfil(&tb);
247 
248 		if (fndef)
249 			iop->ioname = (char *) make(tmpout);
250 		else
251 			iop->ioname = (char *) cpystak(tmpout);
252 
253 		iop->iolst = iotemp;
254 		iotemp = iop;
255 
256 		cline = clinep = start = locstak();
257 		if (stripflg)
258 		{
259 			iop->iofile &= ~IOSTRIP;
260 			while (*ends == '\t')
261 				ends++;
262 		}
263 		for (;;)
264 		{
265 			chkpr();
266 			if (nosubst)
267 			{
268 				c = readwc();
269 				if (stripflg)
270 					while (c == '\t')
271 						c = readwc();
272 
273 				while (!eolchar(c))
274 				{
275 					pc = readw(c);
276 					while (*pc) {
277 						if (clinep >= brkend)
278 							growstak(clinep);
279 						*clinep++ = *pc++;
280 					}
281 					c = readwc();
282 				}
283 			}else{
284 				c = nextwc();
285 				if (stripflg)
286 					while (c == '\t')
287 						c = nextwc();
288 
289 				while (!eolchar(c))
290 				{
291 					pc = readw(c);
292 					while (*pc) {
293 						if (clinep >= brkend)
294 							growstak(clinep);
295 						*clinep++ = *pc++;
296 					}
297 					if (c == '\\')
298 					{
299 						pc = readw(readwc());
300 						/* *pc might be NULL */
301 						if (*pc) {
302 							while (*pc) {
303 								if (clinep >= brkend)
304 									growstak(clinep);
305 								*clinep++ = *pc++;
306 							}
307 						} else {
308 							if (clinep >= brkend)
309 								growstak(clinep);
310 							*clinep++ = *pc;
311 						}
312 					}
313 					c = nextwc();
314 				}
315 			}
316 
317 			if (clinep >= brkend)
318 				growstak(clinep);
319 			*clinep = 0;
320 			if (eof || eq(cline, ends))
321 			{
322 				if ((i = cline - start) > 0)
323 					write(fd, start, i);
324 				break;
325 			}else{
326 				if (clinep >= brkend)
327 					growstak(clinep);
328 				*clinep++ = NL;
329 			}
330 
331 			if ((i = clinep - start) < CPYSIZ)
332 				cline = clinep;
333 			else
334 			{
335 				write(fd, start, i);
336 				cline = clinep = start;
337 			}
338 		}
339 
340 		poptemp();	/*
341 				 * pushed in tmpfil -- bug fix for problem
342 				 * deleting in-line scripts
343 				 */
344 	}
345 }
346 
347 void
348 link_iodocs(struct ionod *i)
349 {
350 	int r;
351 	int len;
352 	size_t size_left = TMPOUTSZ - tmpout_offset;
353 
354 	while (i) {
355 		free(i->iolink);
356 
357 		/* make sure tmp file does not already exist. */
358 		do {
359 			len = snprintf((char *)&tmpout[tmpout_offset],
360 			    size_left, "%u", serial);
361 			serial++;
362 			r = link(i->ioname, (char *)tmpout);
363 			if ((serial >= UINT_MAX) || (len >= size_left)) {
364 			/*
365 			 * We've already cycled through all the possible
366 			 * numbers or the tmp file name is being
367 			 * truncated anyway, so start over.
368 			 */
369 				serial = 0;
370 				break;
371 			}
372 		} while (r == -1 && errno == EEXIST);
373 
374 		if (r != -1) {
375 			i->iolink = (char *)make(tmpout);
376 			i = i->iolst;
377 		} else
378 			failed(tmpout, badcreate);
379 
380 	}
381 }
382 
383 void
384 swap_iodoc_nm(struct ionod *i)
385 {
386 	while (i)
387 	{
388 		free(i->ioname);
389 		i->ioname = i->iolink;
390 		i->iolink = 0;
391 
392 		i = i->iolst;
393 	}
394 }
395 
396 int
397 savefd(int fd)
398 {
399 	int	f;
400 
401 	f = fcntl(fd, F_DUPFD, 10);
402 	return (f);
403 }
404 
405 void
406 restore(int last)
407 {
408 	int 	i;
409 	int	dupfd;
410 
411 	for (i = topfd - 1; i >= last; i--)
412 	{
413 		if ((dupfd = fdmap[i].dup_fd) > 0)
414 			renamef(dupfd, fdmap[i].org_fd);
415 		else
416 			close(fdmap[i].org_fd);
417 	}
418 	topfd = last;
419 }
420