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