summaryrefslogtreecommitdiffstats
path: root/libopkg/xsystem.c
blob: ae7ca87fe7ac2ee2221da1d529e20848ba58345d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
/* xsystem.c - system(3) with error messages

   Carl D. Worth

   Copyright (C) 2001 University of Southern California

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2, or (at
   your option) any later version.

   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.
*/

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#include "xsystem.h"
#include "libbb/libbb.h"

/* Like system(3), but with error messages printed if the fork fails
   or if the child process dies due to an uncaught signal. Also, the
   return value is a bit simpler:

   -1 if there was any problem
   Otherwise, the 8-bit return value of the program ala WEXITSTATUS
   as defined in <sys/wait.h>.
*/
int
xsystem(const char *argv[])
{
	int status;
	pid_t pid;

	pid = vfork();

	switch (pid) {
	case -1:
		opkg_perror(ERROR, "%s: vfork", argv[0]);
		return -1;
	case 0:
		/* child */
		execvp(argv[0], (char*const*)argv);
		_exit(-1);
	default:
		/* parent */
		break;
	}

	if (waitpid(pid, &status, 0) == -1) {
		opkg_perror(ERROR, "%s: waitpid", argv[0]);
		return -1;
	}

	if (WIFSIGNALED(status)) {
		opkg_msg(ERROR, "%s: Child killed by signal %d.\n",
			argv[0], WTERMSIG(status));
		return -1;
	}

	if (!WIFEXITED(status)) {
		/* shouldn't happen */
		opkg_msg(ERROR, "%s: Your system is broken: got status %d "
			"from waitpid.\n", argv[0], status);
		return -1;
	}

	return WEXITSTATUS(status);
}