minit-update.c (5298B) download
1#include "minit.h"
2
3#include <dirent.h>
4#include <errno.h>
5#include <fcntl.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#include <sys/file.h>
10#include <sys/stat.h>
11#include <sys/types.h>
12#include <unistd.h>
13
14#define USAGE "Usage: minit-update [ -v [ -u ] ]\n"
15#define BUFLEN 1500
16
17/*
18 increases file size by almost 4k
19#define WITH_STRERROR */
20
21static struct process* root;
22
23static int infd, outfd;
24static int maxprocess = -1;
25static int processalloc;
26
27static char buf[BUFLEN + 1];
28
29static unsigned int verbose;
30static int do_update;
31
32void feed_struct_to_minit(struct process* data);
33
34ssize_t read_outfd(void* buf, size_t count);
35
36void addprocess(struct process* p);
37
38
39void die(const char* msg) {
40 fputs(msg, stderr);
41 _exit(111);
42}
43
44
45// void buffer_putsnlflush(buffer* b, const char* msg) {
46// fputs(msg, b);
47// buffer_putflush(b, "\n", 1);
48// }
49
50
51#ifdef WITH_STRERROR
52void buffer_puts_strerror(const char* msg) {
53 fputs("minit-update: ", stderr);
54 fputs(msg, stderr);
55 buffer_putsnlflush(stderr, strerror(errno));
56}
57#else
58# define buffer_puts_strerror(a) fputs(a, stderr)
59#endif
60
61
62void* xmalloc(size_t size) {
63 void* ptr = malloc(size);
64 if (!ptr) die("malloc() failed\n");
65 return ptr;
66}
67
68
69void copywrite(const char* service) {
70 strncpy(buf + 1, service, BUFLEN);
71 buf[BUFLEN] = 0;
72 write(infd, buf, strlen(buf));
73}
74
75
76int read_reply_from_minit(void) {
77 if (read_outfd(buf, BUFLEN) == 1) {
78 if (buf[0] == '1') return 1;
79 if (buf[0] == '0') fputs("expected '1' from minit, got '0' - minit too old?\n", stderr);
80 }
81 /* XXX: Uuuh. Should this be checked?
82 else fputs("minit response not understood\n", stderr);
83 */
84 return 0;
85}
86
87
88void find_service(int subdir, char* name, char* parent) {
89 struct stat statbuf;
90 char* service = 0;
91 DIR* dirstream = 0;
92 struct dirent* dir;
93
94 if (chdir(name)) return;
95
96 if (parent) {
97 service = xmalloc(strlen(parent) + strlen(name) + 2);
98 strcpy(service, parent);
99 strcat(service, "/");
100 strcat(service, name);
101 } else {
102 if (subdir) {
103 service = xmalloc(strlen(name) + 1);
104 strcpy(service, name);
105 }
106 }
107#if 0
108 buffer_putsnlflush(stdout,service);
109#endif
110
111 if (service) { /* request and read a "struct process" from minit */
112 struct process tmp;
113
114 if (verbose) {
115 fputs("minit-update: status for ", stdout);
116 fputs(service, stdout);
117 }
118
119 buf[0] = 'D';
120 copywrite(service);
121
122 switch (read_outfd(&tmp, sizeof(tmp))) {
123 case sizeof(tmp):
124 tmp.name = strdup(service);
125 addprocess(&tmp);
126 if (verbose) fputs(" saved.\n", stdout);
127 break;
128 case 1:
129 if (verbose) fputs(" failed - minit has no information on this service\n", stdout);
130#if 0
131 break;
132 default:
133 fputs(" failed - read incomplete structure!\n", stdout);
134#endif
135 }
136 }
137
138 dirstream = opendir(".");
139 if (!dirstream) goto ret;
140
141 while ((dir = readdir(dirstream))) {
142 if (dir->d_name[0] != '.') {
143 if (!lstat(dir->d_name, &statbuf)) {
144 if (S_ISDIR(statbuf.st_mode)) {
145 find_service(1, dir->d_name, service);
146#if 0
147 } else {
148 buffer_putsnlflush(stdout,dir->d_name);
149#endif
150 }
151 } else {
152 fputs(dir->d_name, stderr);
153 fputs(": cannot stat\n", stderr);
154 fprintf(stderr, "lstat() failed: %s\n", strerror(errno));
155 }
156 }
157 } /* while */
158
159 closedir(dirstream);
160
161ret:
162 if (service) free(service);
163 chdir(MINITROOT);
164 if (parent) chdir(parent);
165}
166
167
168int main(int argc, char** argv) {
169 int i;
170
171 if (argc < 2) die(USAGE);
172
173 while (argc > 1) {
174 argc--;
175 if (argv[argc][0] == '-') {
176 switch (argv[argc][1]) {
177 case 'v':
178 verbose++;
179 break;
180 case 'u':
181 do_update = 1;
182 break;
183 default:
184 fputs("minit-update: Unknown Option: ", stderr);
185 fprintf(stderr, "%s\n", argv[argc]);
186 }
187 } else
188 die(USAGE);
189 }
190
191 infd = open(MINITROOT "/in", O_WRONLY);
192 outfd = open(MINITROOT "/out", O_RDONLY);
193
194 if (infd < 0 || outfd < 0) die("could not open " MINITROOT "/in or " MINITROOT "/out\n");
195
196 while (lockf(infd, F_TLOCK, 1)) {
197 fprintf(stderr, "could not acquire lock: %s\n", strerror(errno));
198 sleep(1);
199 }
200
201 find_service(0, MINITROOT, 0);
202
203 if (maxprocess == -1)
204 die("Could not extract running services from minit\n");
205
206 if (verbose) fputs("minit-update: telling minit to execve itself\n", stdout);
207
208 if (!do_update) {
209 fputs("Test mode: No update done.\n", stderr);
210 return 0;
211 }
212
213 write(infd, "update", 6);
214 sleep(1);
215
216 for (i = 0; i <= maxprocess; i++) {
217 if (verbose) {
218 fputs("minit-update: restoring status for ", stdout);
219 printf("%s\n", root[i].name);
220 }
221
222 buf[0] = 'U';
223 copywrite(root[i].name);
224
225 read_reply_from_minit();
226
227 write(infd, &root[i], sizeof(struct process));
228
229 if (read_reply_from_minit() && verbose) {
230 fputs("minit-update: restored service ", stdout);
231 printf("%s\n", root[i].name);
232 }
233
234 } /* for() */
235
236 return 0;
237}
238
239
240ssize_t read_outfd(void* buf, size_t count) {
241 ssize_t br = read(outfd, buf, count);
242
243 if (br < 0) buffer_puts_strerror("Error reading from outfd: ");
244 return br;
245}
246
247
248void addprocess(struct process* p) {
249 if (maxprocess + 1 >= processalloc) {
250 struct process* fump;
251 processalloc += 8;
252 if ((fump = (struct process*) realloc(root, processalloc * sizeof(struct process))) == 0) die("realloc() failed\n ");
253 root = fump;
254 }
255 memmove(&root[++maxprocess], p, sizeof(struct process));
256}