minit-update.c (5298B)
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 21 static struct process* root; 22 23 static int infd, outfd; 24 static int maxprocess = -1; 25 static int processalloc; 26 27 static char buf[BUFLEN + 1]; 28 29 static unsigned int verbose; 30 static int do_update; 31 32 void feed_struct_to_minit(struct process* data); 33 34 ssize_t read_outfd(void* buf, size_t count); 35 36 void addprocess(struct process* p); 37 38 39 void 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 52 void 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 62 void* xmalloc(size_t size) { 63 void* ptr = malloc(size); 64 if (!ptr) die("malloc() failed\n"); 65 return ptr; 66 } 67 68 69 void copywrite(const char* service) { 70 strncpy(buf + 1, service, BUFLEN); 71 buf[BUFLEN] = 0; 72 write(infd, buf, strlen(buf)); 73 } 74 75 76 int 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 88 void 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 161 ret: 162 if (service) free(service); 163 chdir(MINITROOT); 164 if (parent) chdir(parent); 165 } 166 167 168 int 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 240 ssize_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 248 void 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 }