1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21: #include "config.h"
22: #include "libiberty.h"
23: #include "pex-common.h"
24:
25: #include <stdio.h>
26: #include <errno.h>
27: #ifdef NEED_DECLARATION_ERRNO
28: extern int errno;
29: #endif
30: #ifdef HAVE_STDLIB_H
31: #include <stdlib.h>
32: #endif
33: #ifdef HAVE_STRING_H
34: #include <string.h>
35: #endif
36: #ifdef HAVE_UNISTD_H
37: #include <unistd.h>
38: #endif
39:
40: extern int mkstemps (char *, int);
41:
42:
43:
44:
45:
46: static void pex_add_remove (struct pex_obj *, const char *, int);
47: static int pex_get_status_and_time (struct pex_obj *, int, const char **,
48: int *);
49:
50:
51:
52: struct pex_obj *
53: pex_init_common (int flags, const char *pname, const char *tempbase,
54: const struct pex_funcs *funcs)
55: {
56: struct pex_obj *obj;
57:
58: obj = XNEW (struct pex_obj);
59: obj->flags = flags;
60: obj->pname = pname;
61: obj->tempbase = tempbase;
62: obj->next_input = STDIN_FILE_NO;
63: obj->next_input_name = NULL;
64: obj->next_input_name_allocated = 0;
65: obj->stderr_pipe = -1;
66: obj->count = 0;
67: obj->children = NULL;
68: obj->status = NULL;
69: obj->time = NULL;
70: obj->number_waited = 0;
71: obj->input_file = NULL;
72: obj->read_output = NULL;
73: obj->read_err = NULL;
74: obj->remove_count = 0;
75: obj->remove = NULL;
76: obj->funcs = funcs;
77: obj->sysdep = NULL;
78: return obj;
79: }
80:
81:
82:
83: static void
84: pex_add_remove (struct pex_obj *obj, const char *name, int allocated)
85: {
86: char *add;
87:
88: ++obj->remove_count;
89: obj->remove = XRESIZEVEC (char *, obj->remove, obj->remove_count);
90: if (allocated)
91: add = (char *) name;
92: else
93: add = xstrdup (name);
94: obj->remove[obj->remove_count - 1] = add;
95: }
96:
97:
98:
99:
100:
101:
102: static char *
103: temp_file (struct pex_obj *obj, int flags, char *name)
104: {
105: if (name == NULL)
106: {
107: if (obj->tempbase == NULL)
108: {
109: name = make_temp_file (NULL);
110: }
111: else
112: {
113: int len = strlen (obj->tempbase);
114: int out;
115:
116: if (len >= 6
117: && strcmp (obj->tempbase + len - 6, "XXXXXX") == 0)
118: name = xstrdup (obj->tempbase);
119: else
120: name = concat (obj->tempbase, "XXXXXX", NULL);
121:
122: out = mkstemps (name, 0);
123: if (out < 0)
124: {
125: free (name);
126: return NULL;
127: }
128:
129:
130:
131:
132:
133: close (out);
134: }
135: }
136: else if ((flags & PEX_SUFFIX) != 0)
137: {
138: if (obj->tempbase == NULL)
139: name = make_temp_file (name);
140: else
141: name = concat (obj->tempbase, name, NULL);
142: }
143:
144: return name;
145: }
146:
147:
148:
149:
150:
151: const char *
152: pex_run_in_environment (struct pex_obj *obj, int flags, const char *executable,
153: char * const * argv, char * const * env,
154: const char *orig_outname, const char *errname,
155: int *err)
156: {
157: const char *errmsg;
158: int in, out, errdes;
159: char *outname;
160: int outname_allocated;
161: int p[2];
162: int toclose;
163: long pid;
164:
165: in = -1;
166: out = -1;
167: errdes = -1;
168: outname = (char *) orig_outname;
169: outname_allocated = 0;
170:
171:
172: if (obj->input_file)
173: {
174: if (fclose (obj->input_file) == EOF)
175: {
176: errmsg = "closing pipeline input file";
177: goto error_exit;
178: }
179: obj->input_file = NULL;
180: }
181:
182:
183:
184: if (obj->next_input_name != NULL)
185: {
186:
187:
188: if (!pex_get_status_and_time (obj, 0, &errmsg, err))
189: goto error_exit;
190:
191: in = obj->funcs->open_read (obj, obj->next_input_name,
192: (flags & PEX_BINARY_INPUT) != 0);
193: if (in < 0)
194: {
195: *err = errno;
196: errmsg = "open temporary file";
197: goto error_exit;
198: }
199: if (obj->next_input_name_allocated)
200: {
201: free (obj->next_input_name);
202: obj->next_input_name_allocated = 0;
203: }
204: obj->next_input_name = NULL;
205: }
206: else
207: {
208: in = obj->next_input;
209: if (in < 0)
210: {
211: *err = 0;
212: errmsg = "pipeline already complete";
213: goto error_exit;
214: }
215: }
216:
217:
218:
219: if ((flags & PEX_LAST) != 0)
220: {
221: if (outname == NULL)
222: out = STDOUT_FILE_NO;
223: else if ((flags & PEX_SUFFIX) != 0)
224: {
225: outname = concat (obj->tempbase, outname, NULL);
226: outname_allocated = 1;
227: }
228: obj->next_input = -1;
229: }
230: else if ((obj->flags & PEX_USE_PIPES) == 0)
231: {
232: outname = temp_file (obj, flags, outname);
233: if (! outname)
234: {
235: *err = 0;
236: errmsg = "could not create temporary file";
237: goto error_exit;
238: }
239:
240: if (outname != orig_outname)
241: outname_allocated = 1;
242:
243: if ((obj->flags & PEX_SAVE_TEMPS) == 0)
244: {
245: pex_add_remove (obj, outname, outname_allocated);
246: outname_allocated = 0;
247: }
248:
249:
250: obj->next_input_name = outname;
251: obj->next_input_name_allocated = outname_allocated;
252: outname_allocated = 0;
253: }
254: else
255: {
256: if (obj->funcs->pipe (obj, p, (flags & PEX_BINARY_OUTPUT) != 0) < 0)
257: {
258: *err = errno;
259: errmsg = "pipe";
260: goto error_exit;
261: }
262:
263: out = p[WRITE_PORT];
264: obj->next_input = p[READ_PORT];
265: }
266:
267: if (out < 0)
268: {
269: out = obj->funcs->open_write (obj, outname,
270: (flags & PEX_BINARY_OUTPUT) != 0);
271: if (out < 0)
272: {
273: *err = errno;
274: errmsg = "open temporary output file";
275: goto error_exit;
276: }
277: }
278:
279: if (outname_allocated)
280: {
281: free (outname);
282: outname_allocated = 0;
283: }
284:
285:
286:
287: if (errname != NULL && (flags & PEX_STDERR_TO_PIPE) != 0)
288: {
289: *err = 0;
290: errmsg = "both ERRNAME and PEX_STDERR_TO_PIPE specified.";
291: goto error_exit;
292: }
293:
294: if (obj->stderr_pipe != -1)
295: {
296: *err = 0;
297: errmsg = "PEX_STDERR_TO_PIPE used in the middle of pipeline";
298: goto error_exit;
299: }
300:
301: if (errname == NULL)
302: {
303: if (flags & PEX_STDERR_TO_PIPE)
304: {
305: if (obj->funcs->pipe (obj, p, (flags & PEX_BINARY_ERROR) != 0) < 0)
306: {
307: *err = errno;
308: errmsg = "pipe";
309: goto error_exit;
310: }
311:
312: errdes = p[WRITE_PORT];
313: obj->stderr_pipe = p[READ_PORT];
314: }
315: else
316: {
317: errdes = STDERR_FILE_NO;
318: }
319: }
320: else
321: {
322: errdes = obj->funcs->open_write (obj, errname,
323: (flags & PEX_BINARY_ERROR) != 0);
324: if (errdes < 0)
325: {
326: *err = errno;
327: errmsg = "open error file";
328: goto error_exit;
329: }
330: }
331:
332:
333:
334:
335: if ((obj->flags & PEX_USE_PIPES) == 0)
336: toclose = -1;
337: else
338: toclose = obj->next_input;
339:
340:
341:
342: pid = obj->funcs->exec_child (obj, flags, executable, argv, env,
343: in, out, errdes, toclose, &errmsg, err);
344: if (pid < 0)
345: goto error_exit;
346:
347: ++obj->count;
348: obj->children = XRESIZEVEC (long, obj->children, obj->count);
349: obj->children[obj->count - 1] = pid;
350:
351: return NULL;
352:
353: error_exit:
354: if (in >= 0 && in != STDIN_FILE_NO)
355: obj->funcs->close (obj, in);
356: if (out >= 0 && out != STDOUT_FILE_NO)
357: obj->funcs->close (obj, out);
358: if (errdes >= 0 && errdes != STDERR_FILE_NO)
359: obj->funcs->close (obj, errdes);
360: if (outname_allocated)
361: free (outname);
362: return errmsg;
363: }
364:
365:
366:
367: const char *
368: pex_run (struct pex_obj *obj, int flags, const char *executable,
369: char * const * argv, const char *orig_outname, const char *errname,
370: int *err)
371: {
372: return pex_run_in_environment (obj, flags, executable, argv, NULL,
373: orig_outname, errname, err);
374: }
375:
376:
377:
378: FILE *
379: pex_input_file (struct pex_obj *obj, int flags, const char *in_name)
380: {
381: char *name = (char *) in_name;
382: FILE *f;
383:
384:
385:
386: if (obj->count != 0
387: || (obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO)
388: || obj->next_input_name)
389: {
390: errno = EINVAL;
391: return NULL;
392: }
393:
394: name = temp_file (obj, flags, name);
395: if (! name)
396: return NULL;
397:
398: f = fopen (name, (flags & PEX_BINARY_OUTPUT) ? "wb" : "w");
399: if (! f)
400: {
401: free (name);
402: return NULL;
403: }
404:
405: obj->input_file = f;
406: obj->next_input_name = name;
407: obj->next_input_name_allocated = (name != in_name);
408:
409: return f;
410: }
411:
412:
413:
414: FILE *
415: pex_input_pipe (struct pex_obj *obj, int binary)
416: {
417: int p[2];
418: FILE *f;
419:
420:
421: if (obj->count > 0)
422: goto usage_error;
423:
424:
425:
426: if (! (obj->flags & PEX_USE_PIPES))
427: goto usage_error;
428:
429:
430:
431: if ((obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO)
432: || obj->next_input_name)
433: goto usage_error;
434:
435: if (obj->funcs->pipe (obj, p, binary != 0) < 0)
436: return NULL;
437:
438: f = obj->funcs->fdopenw (obj, p[WRITE_PORT], binary != 0);
439: if (! f)
440: {
441: int saved_errno = errno;
442: obj->funcs->close (obj, p[READ_PORT]);
443: obj->funcs->close (obj, p[WRITE_PORT]);
444: errno = saved_errno;
445: return NULL;
446: }
447:
448: obj->next_input = p[READ_PORT];
449:
450: return f;
451:
452: usage_error:
453: errno = EINVAL;
454: return NULL;
455: }
456:
457:
458:
459:
460: FILE *
461: pex_read_output (struct pex_obj *obj, int binary)
462: {
463: if (obj->next_input_name != NULL)
464: {
465: const char *errmsg;
466: int err;
467:
468:
469:
470: if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
471: {
472: errno = err;
473: return NULL;
474: }
475:
476: obj->read_output = fopen (obj->next_input_name, binary ? "rb" : "r");
477:
478: if (obj->next_input_name_allocated)
479: {
480: free (obj->next_input_name);
481: obj->next_input_name_allocated = 0;
482: }
483: obj->next_input_name = NULL;
484: }
485: else
486: {
487: int o;
488:
489: o = obj->next_input;
490: if (o < 0 || o == STDIN_FILE_NO)
491: return NULL;
492: obj->read_output = obj->funcs->fdopenr (obj, o, binary);
493: obj->next_input = -1;
494: }
495:
496: return obj->read_output;
497: }
498:
499: FILE *
500: pex_read_err (struct pex_obj *obj, int binary)
501: {
502: int o;
503:
504: o = obj->stderr_pipe;
505: if (o < 0 || o == STDIN_FILE_NO)
506: return NULL;
507: obj->read_err = obj->funcs->fdopenr (obj, o, binary);
508: return obj->read_err;
509: }
510:
511:
512:
513:
514: static int
515: pex_get_status_and_time (struct pex_obj *obj, int done, const char **errmsg,
516: int *err)
517: {
518: int ret;
519: int i;
520:
521: if (obj->number_waited == obj->count)
522: return 1;
523:
524: obj->status = XRESIZEVEC (int, obj->status, obj->count);
525: if ((obj->flags & PEX_RECORD_TIMES) != 0)
526: obj->time = XRESIZEVEC (struct pex_time, obj->time, obj->count);
527:
528: ret = 1;
529: for (i = obj->number_waited; i < obj->count; ++i)
530: {
531: if (obj->funcs->wait (obj, obj->children[i], &obj->status[i],
532: obj->time == NULL ? NULL : &obj->time[i],
533: done, errmsg, err) < 0)
534: ret = 0;
535: }
536: obj->number_waited = i;
537:
538: return ret;
539: }
540:
541:
542:
543: int
544: pex_get_status (struct pex_obj *obj, int count, int *vector)
545: {
546: if (obj->status == NULL)
547: {
548: const char *errmsg;
549: int err;
550:
551: if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
552: return 0;
553: }
554:
555: if (count > obj->count)
556: {
557: memset (vector + obj->count, 0, (count - obj->count) * sizeof (int));
558: count = obj->count;
559: }
560:
561: memcpy (vector, obj->status, count * sizeof (int));
562:
563: return 1;
564: }
565:
566:
567:
568: int
569: pex_get_times (struct pex_obj *obj, int count, struct pex_time *vector)
570: {
571: if (obj->status == NULL)
572: {