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