Log child output
[petitboot] / lib / system / system.c
1
2 #if defined(HAVE_CONFIG_H)
3 #include "config.h"
4 #endif
5
6 #include <assert.h>
7 #include <errno.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <sys/stat.h>
12 #include <sys/types.h>
13 #include <sys/wait.h>
14
15 #include "log/log.h"
16 #include <talloc/talloc.h>
17 #include "system.h"
18
19 const struct pb_system_apps pb_system_apps = {
20         .cp = "/bin/cp",
21         .kexec = "/sbin/kexec",
22         .mount = "/bin/mount",
23         .sftp = "/usr/bin/sftp",
24         .tftp = "/usr/bin/tftp",
25         .umount = "/bin/umount",
26         .wget = "/usr/bin/wget",
27 };
28
29 int pb_mkdir_recursive(const char *dir)
30 {
31         struct stat statbuf;
32         char *str, *sep;
33         int mode = 0755;
34
35         if (!*dir)
36                 return 0;
37
38         if (!stat(dir, &statbuf)) {
39                 if (!S_ISDIR(statbuf.st_mode)) {
40                         pb_log("%s: %s exists, but isn't a directory\n",
41                                         __func__, dir);
42                         return -1;
43                 }
44                 return 0;
45         }
46
47         str = talloc_strdup(NULL, dir);
48         sep = strchr(*str == '/' ? str + 1 : str, '/');
49
50         while (1) {
51
52                 /* terminate the path at sep */
53                 if (sep)
54                         *sep = '\0';
55
56                 if (mkdir(str, mode) && errno != EEXIST) {
57                         pb_log("mkdir(%s): %s\n", str, strerror(errno));
58                         return -1;
59                 }
60
61                 if (!sep)
62                         break;
63
64                 /* reset dir to the full path */
65                 strcpy(str, dir);
66                 sep = strchr(sep + 1, '/');
67         }
68
69         talloc_free(str);
70
71         return 0;
72 }
73
74 int pb_rmdir_recursive(const char *base, const char *dir)
75 {
76         char *cur, *pos;
77
78         /* sanity check: make sure that dir is within base */
79         if (strncmp(base, dir, strlen(base)))
80                 return -1;
81
82         cur = talloc_strdup(NULL, dir);
83
84         while (strcmp(base, dir)) {
85
86                 rmdir(dir);
87
88                 /* null-terminate at the last slash */
89                 pos = strrchr(dir, '/');
90                 if (!pos)
91                         break;
92
93                 *pos = '\0';
94         }
95
96         talloc_free(cur);
97
98         return 0;
99 }
100
101 /**
102  * pb_run_cmd - Run the supplied command.
103  * @cmd_argv: An argument list array for execv.
104  */
105
106 int pb_run_cmd(const char *const *cmd_argv)
107 {
108 #if defined(DEBUG)
109         enum {do_debug = 1};
110 #else
111         enum {do_debug = 0};
112 #endif
113         int status;
114         pid_t pid;
115
116         if (do_debug) {
117                 const char *const *p = cmd_argv;
118
119                 pb_log("%s: ", __func__);
120                 while (*p) {
121                         pb_log("%s ", *p);
122                         p++;
123                 }
124                 pb_log("\n");
125         } else
126                 pb_log("%s: %s\n", __func__, cmd_argv[0]);
127
128         pid = fork();
129
130         if (pid == -1) {
131                 pb_log("%s: fork failed: %s\n", __func__, strerror(errno));
132                 return -1;
133         }
134
135         if (pid == 0) {
136                 int log = fileno(pb_log_get_stream());
137
138                 /* Redirect child output to log. */
139
140                 status = dup2(log, STDOUT_FILENO);
141                 assert(status != -1);
142
143                 status = dup2(log, STDERR_FILENO);
144                 assert(status != -1);
145
146                 execvp(cmd_argv[0], (char *const *)cmd_argv);
147                 pb_log("%s: exec failed: %s\n", __func__, strerror(errno));
148                 exit(EXIT_FAILURE);
149         }
150
151         if (waitpid(pid, &status, 0) == -1) {
152                 pb_log("%s: waitpid failed: %s\n", __func__,
153                                 strerror(errno));
154                 return -1;
155         }
156
157         if (do_debug && WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
158                 pb_log("%s: signaled\n", __func__);
159
160         if (!WIFEXITED(status)) {
161                 pb_log("%s: %s failed\n", __func__, cmd_argv[0]);
162                 return -1;
163         }
164
165         if (WEXITSTATUS(status))
166                 pb_log("%s: WEXITSTATUS %d\n", __func__, WEXITSTATUS(status));
167
168         return WEXITSTATUS(status);
169 }