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