GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libc/gen/posix_spawn.c Lines: 0 145 0.0 %
Date: 2017-11-07 Branches: 0 89 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: posix_spawn.c,v 1.9 2016/03/13 18:34:20 guenther Exp $	*/
2
/*-
3
 * Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 * 1. Redistributions of source code must retain the above copyright
10
 *    notice, this list of conditions and the following disclaimer.
11
 * 2. Redistributions in binary form must reproduce the above copyright
12
 *    notice, this list of conditions and the following disclaimer in the
13
 *    documentation and/or other materials provided with the distribution.
14
 *
15
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25
 * SUCH DAMAGE.
26
 */
27
28
#include <sys/queue.h>
29
30
#include <errno.h>
31
#include <fcntl.h>
32
#include <sched.h>
33
#include <spawn.h>
34
#include <signal.h>
35
#include <stdlib.h>
36
#include <string.h>
37
#include <unistd.h>
38
39
struct __posix_spawnattr {
40
	short			sa_flags;
41
	pid_t			sa_pgroup;
42
	struct sched_param	sa_schedparam;
43
	int			sa_schedpolicy;
44
	sigset_t		sa_sigdefault;
45
	sigset_t		sa_sigmask;
46
};
47
48
struct __posix_spawn_file_actions {
49
	SIMPLEQ_HEAD(, __posix_spawn_file_actions_entry) fa_list;
50
};
51
52
typedef struct __posix_spawn_file_actions_entry {
53
	SIMPLEQ_ENTRY(__posix_spawn_file_actions_entry) fae_list;
54
	enum { FAE_OPEN, FAE_DUP2, FAE_CLOSE } fae_action;
55
56
	int fae_fildes;
57
	union {
58
		struct {
59
			char *path;
60
#define fae_path	fae_data.open.path
61
			int oflag;
62
#define fae_oflag	fae_data.open.oflag
63
			mode_t mode;
64
#define fae_mode	fae_data.open.mode
65
		} open;
66
		struct {
67
			int newfildes;
68
#define fae_newfildes	fae_data.dup2.newfildes
69
		} dup2;
70
	} fae_data;
71
} posix_spawn_file_actions_entry_t;
72
73
/*
74
 * Spawn routines
75
 */
76
77
static int
78
process_spawnattr(const posix_spawnattr_t sa)
79
{
80
	struct sigaction sigact;
81
	int i;
82
83
	memset(&sigact, 0, sizeof(sigact));
84
	sigact.sa_handler = SIG_DFL;
85
86
	/*
87
	 * POSIX doesn't really describe in which order everything
88
	 * should be set. We'll just set them in the order in which they
89
	 * are mentioned.
90
	 */
91
92
	/* Set process group */
93
	if (sa->sa_flags & POSIX_SPAWN_SETPGROUP) {
94
		if (setpgid(0, sa->sa_pgroup) != 0)
95
			return (errno);
96
	}
97
98
#if 0 /* NOT IMPLEMENTED */
99
	/* Set scheduler policy */
100
	if (sa->sa_flags & POSIX_SPAWN_SETSCHEDULER) {
101
		if (sched_setscheduler(0, sa->sa_schedpolicy,
102
		    &sa->sa_schedparam) != 0)
103
			return (errno);
104
	} else if (sa->sa_flags & POSIX_SPAWN_SETSCHEDPARAM) {
105
		if (sched_setparam(0, &sa->sa_schedparam) != 0)
106
			return (errno);
107
	}
108
#endif
109
110
	/* Reset user ID's */
111
	if (sa->sa_flags & POSIX_SPAWN_RESETIDS) {
112
		if (setegid(getgid()) != 0)
113
			return (errno);
114
		if (seteuid(getuid()) != 0)
115
			return (errno);
116
	}
117
118
	/* Set signal masks/defaults */
119
	if (sa->sa_flags & POSIX_SPAWN_SETSIGMASK) {
120
		WRAP(sigprocmask)(SIG_SETMASK, &sa->sa_sigmask, NULL);
121
	}
122
123
	if (sa->sa_flags & POSIX_SPAWN_SETSIGDEF) {
124
		for (i = 1; i < _NSIG; i++) {
125
			/* silently ignore attempts to alter SIGTHR */
126
			if (sigismember(&sa->sa_sigdefault, i) && i != SIGTHR)
127
				if (sigaction(i, &sigact, NULL) != 0)
128
					return (errno);
129
		}
130
	}
131
132
	return (0);
133
}
134
135
static int
136
process_file_actions_entry(posix_spawn_file_actions_entry_t *fae)
137
{
138
	int fd;
139
140
	switch (fae->fae_action) {
141
	case FAE_OPEN:
142
		/* Perform an open(), make it use the right fd */
143
		fd = open(fae->fae_path, fae->fae_oflag, fae->fae_mode);
144
		if (fd < 0)
145
			return (errno);
146
		if (fd != fae->fae_fildes) {
147
			if (dup2(fd, fae->fae_fildes) == -1)
148
				return (errno);
149
			if (close(fd) != 0) {
150
				if (errno == EBADF)
151
					return (EBADF);
152
			}
153
		}
154
		break;
155
	case FAE_DUP2:
156
		/*
157
		 * Perform a dup2(), making sure the FD_CLOEXEC flag is clear
158
		 */
159
		fd = fae->fae_fildes;
160
		if (fd == fae->fae_newfildes) {
161
			int flags = fcntl(fd, F_GETFD);
162
163
			if (flags == -1 ||
164
			    ((flags & FD_CLOEXEC) &&
165
			    fcntl(fd, F_SETFD, flags & ~FD_CLOEXEC) == -1))
166
				return (errno);
167
		} else if (dup2(fd, fae->fae_newfildes) == -1)
168
			return (errno);
169
		break;
170
	case FAE_CLOSE:
171
		/* Perform a close(), do not fail if already closed */
172
		(void)close(fae->fae_fildes);
173
		break;
174
	}
175
	return (0);
176
}
177
178
static int
179
process_file_actions(const posix_spawn_file_actions_t fa)
180
{
181
	posix_spawn_file_actions_entry_t *fae;
182
	int error;
183
184
	/* Replay all file descriptor modifications */
185
	SIMPLEQ_FOREACH(fae, &fa->fa_list, fae_list) {
186
		error = process_file_actions_entry(fae);
187
		if (error)
188
			return (error);
189
	}
190
	return (0);
191
}
192
193
static int
194
do_posix_spawn(pid_t *pid, const char *path,
195
    const posix_spawn_file_actions_t *fa,
196
    const posix_spawnattr_t *sa,
197
    char *const argv[], char *const envp[], int use_env_path)
198
{
199
	pid_t p;
200
201
	p = fork();
202
	switch (p) {
203
	case -1:
204
		return (errno);
205
	case 0: {
206
		int error;
207
		if (sa != NULL) {
208
			error = process_spawnattr(*sa);
209
			if (error)
210
				_exit(127);
211
		}
212
		if (fa != NULL) {
213
			error = process_file_actions(*fa);
214
			if (error)
215
				_exit(127);
216
		}
217
		if (use_env_path)
218
			execvpe(path, argv, envp != NULL ? envp : environ);
219
		else
220
			execve(path, argv, envp != NULL ? envp : environ);
221
		_exit(127);
222
	}
223
	default:
224
		if (pid != NULL)
225
			*pid = p;
226
		return (0);
227
	}
228
}
229
230
int
231
posix_spawn(pid_t *pid, const char *path,
232
    const posix_spawn_file_actions_t *fa,
233
    const posix_spawnattr_t *sa,
234
    char *const argv[], char *const envp[])
235
{
236
	return do_posix_spawn(pid, path, fa, sa, argv, envp, 0);
237
}
238
239
int
240
posix_spawnp(pid_t *pid, const char *path,
241
    const posix_spawn_file_actions_t *fa,
242
    const posix_spawnattr_t *sa,
243
    char *const argv[], char *const envp[])
244
{
245
	return do_posix_spawn(pid, path, fa, sa, argv, envp, 1);
246
}
247
248
/*
249
 * File descriptor actions
250
 */
251
252
int
253
posix_spawn_file_actions_init(posix_spawn_file_actions_t *ret)
254
{
255
	posix_spawn_file_actions_t fa;
256
257
	fa = malloc(sizeof(struct __posix_spawn_file_actions));
258
	if (fa == NULL)
259
		return (errno);
260
261
	SIMPLEQ_INIT(&fa->fa_list);
262
	*ret = fa;
263
	return (0);
264
}
265
266
int
267
posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *fa)
268
{
269
	posix_spawn_file_actions_entry_t *fae;
270
271
	while ((fae = SIMPLEQ_FIRST(&(*fa)->fa_list)) != NULL) {
272
		/* Remove file action entry from the queue */
273
		SIMPLEQ_REMOVE_HEAD(&(*fa)->fa_list, fae_list);
274
275
		/* Deallocate file action entry */
276
		if (fae->fae_action == FAE_OPEN)
277
			free(fae->fae_path);
278
		free(fae);
279
	}
280
281
	free(*fa);
282
	return (0);
283
}
284
285
int
286
posix_spawn_file_actions_addopen(posix_spawn_file_actions_t *__restrict fa,
287
    int fildes, const char *__restrict path, int oflag, mode_t mode)
288
{
289
	posix_spawn_file_actions_entry_t *fae;
290
	int error;
291
292
	if (fildes < 0)
293
		return (EBADF);
294
295
	/* Allocate object */
296
	fae = malloc(sizeof(posix_spawn_file_actions_entry_t));
297
	if (fae == NULL)
298
		return (errno);
299
300
	/* Set values and store in queue */
301
	fae->fae_action = FAE_OPEN;
302
	fae->fae_path = strdup(path);
303
	if (fae->fae_path == NULL) {
304
		error = errno;
305
		free(fae);
306
		return (error);
307
	}
308
	fae->fae_fildes = fildes;
309
	fae->fae_oflag = oflag;
310
	fae->fae_mode = mode;
311
312
	SIMPLEQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list);
313
	return (0);
314
}
315
316
int
317
posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *fa,
318
    int fildes, int newfildes)
319
{
320
	posix_spawn_file_actions_entry_t *fae;
321
322
	if (fildes < 0 || newfildes < 0)
323
		return (EBADF);
324
325
	/* Allocate object */
326
	fae = malloc(sizeof(posix_spawn_file_actions_entry_t));
327
	if (fae == NULL)
328
		return (errno);
329
330
	/* Set values and store in queue */
331
	fae->fae_action = FAE_DUP2;
332
	fae->fae_fildes = fildes;
333
	fae->fae_newfildes = newfildes;
334
335
	SIMPLEQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list);
336
	return (0);
337
}
338
339
int
340
posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *fa,
341
    int fildes)
342
{
343
	posix_spawn_file_actions_entry_t *fae;
344
345
	if (fildes < 0)
346
		return (EBADF);
347
348
	/* Allocate object */
349
	fae = malloc(sizeof(posix_spawn_file_actions_entry_t));
350
	if (fae == NULL)
351
		return (errno);
352
353
	/* Set values and store in queue */
354
	fae->fae_action = FAE_CLOSE;
355
	fae->fae_fildes = fildes;
356
357
	SIMPLEQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list);
358
	return (0);
359
}
360
361
/*
362
 * Spawn attributes
363
 */
364
365
int
366
posix_spawnattr_init(posix_spawnattr_t *ret)
367
{
368
	posix_spawnattr_t sa;
369
370
	sa = calloc(1, sizeof(struct __posix_spawnattr));
371
	if (sa == NULL)
372
		return (errno);
373
374
	/* Set defaults as specified by POSIX, cleared above */
375
	*ret = sa;
376
	return (0);
377
}
378
379
int
380
posix_spawnattr_destroy(posix_spawnattr_t *sa)
381
{
382
	free(*sa);
383
	return (0);
384
}
385
386
int
387
posix_spawnattr_getflags(const posix_spawnattr_t *__restrict sa,
388
    short *__restrict flags)
389
{
390
	*flags = (*sa)->sa_flags;
391
	return (0);
392
}
393
394
int
395
posix_spawnattr_getpgroup(const posix_spawnattr_t *__restrict sa,
396
    pid_t *__restrict pgroup)
397
{
398
	*pgroup = (*sa)->sa_pgroup;
399
	return (0);
400
}
401
402
int
403
posix_spawnattr_getschedparam(const posix_spawnattr_t *__restrict sa,
404
    struct sched_param *__restrict schedparam)
405
{
406
	*schedparam = (*sa)->sa_schedparam;
407
	return (0);
408
}
409
410
int
411
posix_spawnattr_getschedpolicy(const posix_spawnattr_t *__restrict sa,
412
    int *__restrict schedpolicy)
413
{
414
	*schedpolicy = (*sa)->sa_schedpolicy;
415
	return (0);
416
}
417
418
int
419
posix_spawnattr_getsigdefault(const posix_spawnattr_t *__restrict sa,
420
    sigset_t *__restrict sigdefault)
421
{
422
	*sigdefault = (*sa)->sa_sigdefault;
423
	return (0);
424
}
425
426
int
427
posix_spawnattr_getsigmask(const posix_spawnattr_t *__restrict sa,
428
    sigset_t *__restrict sigmask)
429
{
430
	*sigmask = (*sa)->sa_sigmask;
431
	return (0);
432
}
433
434
int
435
posix_spawnattr_setflags(posix_spawnattr_t *sa, short flags)
436
{
437
	(*sa)->sa_flags = flags;
438
	return (0);
439
}
440
441
int
442
posix_spawnattr_setpgroup(posix_spawnattr_t *sa, pid_t pgroup)
443
{
444
	(*sa)->sa_pgroup = pgroup;
445
	return (0);
446
}
447
448
int
449
posix_spawnattr_setschedparam(posix_spawnattr_t *__restrict sa,
450
    const struct sched_param *__restrict schedparam)
451
{
452
	(*sa)->sa_schedparam = *schedparam;
453
	return (0);
454
}
455
456
int
457
posix_spawnattr_setschedpolicy(posix_spawnattr_t *sa, int schedpolicy)
458
{
459
	(*sa)->sa_schedpolicy = schedpolicy;
460
	return (0);
461
}
462
463
int
464
posix_spawnattr_setsigdefault(posix_spawnattr_t *__restrict sa,
465
    const sigset_t *__restrict sigdefault)
466
{
467
	(*sa)->sa_sigdefault = *sigdefault;
468
	return (0);
469
}
470
471
int
472
posix_spawnattr_setsigmask(posix_spawnattr_t *__restrict sa,
473
    const sigset_t *__restrict sigmask)
474
{
475
	(*sa)->sa_sigmask = *sigmask;
476
	return (0);
477
}