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