]>
Commit | Line | Data |
---|---|---|
d79ec8e9 AS |
1 | /* |
2 | * Copyright (C) 2012 Andreas Steffen | |
3 | * HSR Hochschule fuer Technik Rapperswil | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify it | |
6 | * under the terms of the GNU General Public License as published by the | |
7 | * Free Software Foundation; either version 2 of the License, or (at your | |
8 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, but | |
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
13 | * for more details. | |
14 | */ | |
15 | ||
16 | #define _GNU_SOURCE | |
17 | #include <getopt.h> | |
18 | #include <unistd.h> | |
19 | #include <stdio.h> | |
20 | #include <string.h> | |
21 | #include <errno.h> | |
22 | #include <syslog.h> | |
60e26e0f | 23 | #include <time.h> |
45eb318e | 24 | #include <sys/stat.h> |
d79ec8e9 | 25 | |
a95959cc AS |
26 | #include "imv_os_state.h" |
27 | ||
d79ec8e9 AS |
28 | #include <library.h> |
29 | #include <utils/debug.h> | |
30 | ||
45eb318e AS |
31 | typedef enum pacman_state_t pacman_state_t; |
32 | ||
33 | enum pacman_state_t { | |
34 | PACMAN_STATE_BEGIN_PACKAGE, | |
35 | PACMAN_STATE_VERSION, | |
36 | PACMAN_STATE_END_PACKAGE | |
37 | }; | |
38 | ||
39 | typedef struct stats_t stats_t; | |
40 | ||
41 | struct stats_t { | |
42 | time_t release; | |
43 | int product; | |
44 | int packages; | |
45 | int new_packages; | |
46 | int new_versions; | |
47 | int updated_versions; | |
48 | int deleted_versions; | |
49 | }; | |
50 | ||
d79ec8e9 AS |
51 | /** |
52 | * global debug output variables | |
53 | */ | |
54 | static int debug_level = 1; | |
55 | static bool stderr_quiet = TRUE; | |
56 | ||
57 | /** | |
58 | * pacman dbg function | |
59 | */ | |
60 | static void pacman_dbg(debug_t group, level_t level, char *fmt, ...) | |
61 | { | |
62 | int priority = LOG_INFO; | |
63 | char buffer[8192]; | |
64 | char *current = buffer, *next; | |
65 | va_list args; | |
66 | ||
67 | if (level <= debug_level) | |
68 | { | |
69 | if (!stderr_quiet) | |
70 | { | |
71 | va_start(args, fmt); | |
72 | vfprintf(stderr, fmt, args); | |
73 | fprintf(stderr, "\n"); | |
74 | va_end(args); | |
75 | } | |
76 | ||
77 | /* write in memory buffer first */ | |
78 | va_start(args, fmt); | |
79 | vsnprintf(buffer, sizeof(buffer), fmt, args); | |
80 | va_end(args); | |
81 | ||
82 | /* do a syslog with every line */ | |
83 | while (current) | |
84 | { | |
85 | next = strchr(current, '\n'); | |
86 | if (next) | |
87 | { | |
88 | *(next++) = '\0'; | |
89 | } | |
90 | syslog(priority, "%s\n", current); | |
91 | current = next; | |
92 | } | |
93 | } | |
94 | } | |
95 | ||
96 | /** | |
97 | * atexit handler to close everything on shutdown | |
98 | */ | |
99 | static void cleanup(void) | |
100 | { | |
101 | closelog(); | |
102 | library_deinit(); | |
103 | } | |
104 | ||
105 | static void usage(void) | |
106 | { | |
107 | printf("Usage:\n" | |
b18b924b | 108 | "ipsec pacman --product <name> --file <filename> [--update]\n"); |
d79ec8e9 AS |
109 | } |
110 | ||
60e26e0f | 111 | /** |
45eb318e | 112 | * Update the package database |
60e26e0f | 113 | */ |
45eb318e AS |
114 | static bool update_database(database_t *db, char *package, char *version, |
115 | bool security, stats_t *stats) | |
60e26e0f | 116 | { |
45eb318e AS |
117 | char *cur_version, *version_update = NULL, *version_delete = NULL; |
118 | int cur_security, security_update = 0, security_delete = 0; | |
119 | int pac_id = 0, vid = 0, vid_update = 0, vid_delete = 0; | |
120 | u_int cur_time; | |
121 | bool add_version = TRUE; | |
122 | enumerator_t *e; | |
123 | ||
124 | /* increment package count */ | |
125 | stats->packages++; | |
126 | ||
127 | /* check if package is already in database */ | |
128 | e = db->query(db, "SELECT id FROM packages WHERE name = ?", | |
129 | DB_TEXT, package, DB_INT); | |
130 | if (!e) | |
131 | { | |
132 | return FALSE; | |
133 | } | |
134 | if (!e->enumerate(e, &pac_id)) | |
135 | { | |
136 | pac_id = 0; | |
137 | } | |
138 | e->destroy(e); | |
139 | ||
140 | if (!pac_id && security) | |
141 | { | |
142 | if (db->execute(db, &pac_id, "INSERT INTO packages (name) VALUES (?)", | |
143 | DB_TEXT, package) != 1) | |
144 | { | |
145 | fprintf(stderr, "could not store package '%s' to database\n", | |
146 | package); | |
147 | return FALSE; | |
148 | } | |
149 | stats->new_packages++; | |
150 | } | |
151 | ||
152 | /* check for package versions already in database */ | |
153 | e = db->query(db, | |
154 | "SELECT id, release, security, time FROM versions " | |
155 | "WHERE package = ? AND product = ?", DB_INT, pac_id, | |
156 | DB_INT, stats->product, DB_INT, DB_TEXT, DB_INT, DB_UINT); | |
157 | if (!e) | |
60e26e0f | 158 | { |
45eb318e | 159 | return FALSE; |
60e26e0f | 160 | } |
60e26e0f | 161 | |
45eb318e | 162 | while (e->enumerate(e, &vid, &cur_version, &cur_security, &cur_time)) |
60e26e0f | 163 | { |
45eb318e | 164 | if (streq(version, cur_version)) |
60e26e0f | 165 | { |
45eb318e AS |
166 | /* already in data base */ |
167 | add_version = FALSE; | |
60e26e0f AS |
168 | break; |
169 | } | |
45eb318e AS |
170 | else if (stats->release >= cur_time) |
171 | { | |
172 | if (security) | |
173 | { | |
174 | if (cur_security) | |
175 | { | |
176 | vid_update = vid; | |
177 | version_update = strdup(cur_version); | |
178 | security_update = cur_security; | |
179 | } | |
180 | else | |
181 | { | |
182 | vid_delete = vid; | |
183 | version_delete = strdup(cur_version); | |
184 | security_delete = cur_security; | |
185 | } | |
186 | } | |
187 | else | |
188 | { | |
189 | if (!cur_security) | |
190 | { | |
191 | vid_update = vid; | |
192 | version_update = strdup(cur_version); | |
193 | security_update = cur_security; | |
194 | } | |
195 | } | |
196 | } | |
197 | else | |
198 | { | |
199 | if (security == cur_security) | |
200 | { | |
201 | add_version = FALSE; | |
202 | } | |
203 | } | |
204 | } | |
205 | e->destroy(e); | |
206 | ||
207 | if ((!vid && !security) || (vid && !add_version)) | |
208 | { | |
209 | free(version_update); | |
210 | free(version_delete); | |
211 | return TRUE; | |
212 | } | |
213 | ||
214 | if ((!vid && security) || (vid && !vid_update)) | |
215 | { | |
216 | printf("%s (%s) %s\n", package, version, security ? "[s]" : ""); | |
217 | ||
218 | if (db->execute(db, &vid, | |
219 | "INSERT INTO versions " | |
220 | "(package, product, release, security, time) " | |
221 | "VALUES (?, ?, ?, ?, ?)", DB_INT, pac_id, DB_INT, stats->product, | |
222 | DB_TEXT, version, DB_INT, security, DB_INT, stats->release) != 1) | |
223 | { | |
224 | fprintf(stderr, "could not store version '%s' to database\n", | |
225 | version); | |
226 | free(version_update); | |
227 | free(version_delete); | |
228 | return FALSE; | |
229 | } | |
230 | stats->new_versions++; | |
60e26e0f | 231 | } |
45eb318e | 232 | else |
60e26e0f | 233 | { |
45eb318e AS |
234 | printf("%s (%s) %s updated by\n", |
235 | package, version_update, security_update ? "[s]" : ""); | |
236 | printf("%s (%s) %s\n", package, version, security ? "[s]" : ""); | |
237 | ||
238 | if (db->execute(db, NULL, | |
239 | "UPDATE versions SET release = ?, time = ? WHERE id = ?", | |
240 | DB_TEXT, version, DB_INT, stats->release, DB_INT, vid_update) <= 0) | |
241 | { | |
242 | fprintf(stderr, "could not update version '%s' to database\n", | |
243 | version); | |
244 | free(version_update); | |
245 | free(version_delete); | |
246 | return FALSE; | |
247 | } | |
248 | stats->updated_versions++; | |
60e26e0f AS |
249 | } |
250 | ||
45eb318e AS |
251 | if (vid_delete) |
252 | { | |
253 | printf("%s (%s) %s deleted\n", | |
254 | package, version_delete, security_delete ? "[s]" : ""); | |
255 | if (db->execute(db, NULL, | |
256 | "DELETE FROM versions WHERE id = ?", | |
257 | DB_INT, vid_delete) <= 0) | |
258 | { | |
259 | fprintf(stderr, "could not delete version '%s' from database\n", | |
260 | version_delete); | |
261 | free(version_update); | |
262 | free(version_delete); | |
263 | return FALSE; | |
264 | } | |
265 | stats->deleted_versions++; | |
266 | } | |
267 | free(version_update); | |
268 | free(version_delete); | |
269 | ||
270 | return TRUE; | |
60e26e0f AS |
271 | } |
272 | ||
d79ec8e9 AS |
273 | /** |
274 | * Process a package file and store updates in the database | |
275 | */ | |
45eb318e | 276 | static void process_packages(char *filename, char *product, bool security) |
d79ec8e9 | 277 | { |
45eb318e AS |
278 | char *uri, line[BUF_LEN], *pos, *package = NULL, *version = NULL; |
279 | pacman_state_t pacman_state; | |
d79ec8e9 AS |
280 | enumerator_t *e; |
281 | database_t *db; | |
45eb318e | 282 | int pid; |
d79ec8e9 | 283 | FILE *file; |
45eb318e AS |
284 | stats_t stats; |
285 | bool success; | |
286 | ||
287 | /* initialize statistics */ | |
288 | memset(&stats, 0x00, sizeof(stats_t)); | |
289 | ||
02497901 AS |
290 | /* Set release date to current time */ |
291 | stats.release = time(NULL); | |
d79ec8e9 AS |
292 | |
293 | /* opening package file */ | |
294 | printf("loading\"%s\"\n", filename); | |
295 | file = fopen(filename, "r"); | |
296 | if (!file) | |
297 | { | |
60e26e0f | 298 | fprintf(stderr, "could not open \"%s\"\n", filename); |
d79ec8e9 AS |
299 | exit(EXIT_FAILURE); |
300 | } | |
301 | ||
302 | /* connect package database */ | |
303 | uri = lib->settings->get_str(lib->settings, "pacman.database", NULL); | |
304 | if (!uri) | |
305 | { | |
306 | fprintf(stderr, "database URI pacman.database not set\n"); | |
307 | fclose(file); | |
308 | exit(EXIT_FAILURE); | |
309 | } | |
310 | db = lib->db->create(lib->db, uri); | |
311 | if (!db) | |
312 | { | |
313 | fprintf(stderr, "could not connect to database '%s'\n", uri); | |
314 | fclose(file); | |
315 | exit(EXIT_FAILURE); | |
316 | } | |
317 | ||
318 | /* check if product is already in database */ | |
319 | e = db->query(db, "SELECT id FROM products WHERE name = ?", | |
320 | DB_TEXT, product, DB_INT); | |
321 | if (e) | |
322 | { | |
45eb318e | 323 | if (e->enumerate(e, &pid)) |
d79ec8e9 | 324 | { |
45eb318e | 325 | stats.product = pid; |
d79ec8e9 AS |
326 | } |
327 | e->destroy(e); | |
328 | } | |
45eb318e | 329 | if (!stats.product) |
677812dc | 330 | { |
d79ec8e9 AS |
331 | if (db->execute(db, &pid, "INSERT INTO products (name) VALUES (?)", |
332 | DB_TEXT, product) != 1) | |
333 | { | |
334 | fprintf(stderr, "could not store product '%s' to database\n", | |
335 | product); | |
336 | fclose(file); | |
337 | db->destroy(db); | |
338 | exit(EXIT_FAILURE); | |
339 | } | |
45eb318e | 340 | stats.product = pid; |
d79ec8e9 AS |
341 | } |
342 | ||
45eb318e AS |
343 | pacman_state = PACMAN_STATE_BEGIN_PACKAGE; |
344 | ||
d79ec8e9 AS |
345 | while (fgets(line, sizeof(line), file)) |
346 | { | |
45eb318e AS |
347 | /* set read pointer to beginning of line */ |
348 | pos = line; | |
60e26e0f | 349 | |
45eb318e | 350 | switch (pacman_state) |
d79ec8e9 | 351 | { |
45eb318e AS |
352 | case PACMAN_STATE_BEGIN_PACKAGE: |
353 | pos = strstr(pos, "Package: "); | |
354 | if (!pos) | |
355 | { | |
356 | continue; | |
357 | } | |
358 | pos += 9; | |
359 | package = pos; | |
360 | pos = strchr(pos, '\n'); | |
361 | if (pos) | |
362 | { | |
363 | package = strndup(package, pos - package); | |
364 | pacman_state = PACMAN_STATE_VERSION; | |
365 | } | |
b18b924b | 366 | break; |
45eb318e AS |
367 | case PACMAN_STATE_VERSION: |
368 | pos = strstr(pos, "Version: "); | |
369 | if (!pos) | |
b5c2a270 | 370 | { |
45eb318e | 371 | continue; |
b18b924b | 372 | } |
45eb318e AS |
373 | pos += 9; |
374 | version = pos; | |
375 | pos = strchr(pos, '\n'); | |
376 | if (pos) | |
b18b924b | 377 | { |
45eb318e AS |
378 | version = strndup(version, pos - version); |
379 | pacman_state = PACMAN_STATE_END_PACKAGE; | |
b5c2a270 | 380 | } |
45eb318e AS |
381 | break; |
382 | case PACMAN_STATE_END_PACKAGE: | |
383 | if (*pos != '\n') | |
b18b924b | 384 | { |
45eb318e | 385 | continue; |
b18b924b | 386 | } |
45eb318e AS |
387 | success = update_database(db, package, version, security, &stats); |
388 | free(package); | |
389 | free(version); | |
390 | if (!success) | |
391 | { | |
392 | fclose(file); | |
393 | db->destroy(db); | |
394 | exit(EXIT_FAILURE); | |
395 | } | |
396 | pacman_state = PACMAN_STATE_BEGIN_PACKAGE; | |
b18b924b | 397 | } |
b18b924b | 398 | } |
d79ec8e9 AS |
399 | fclose(file); |
400 | db->destroy(db); | |
b18b924b | 401 | |
45eb318e AS |
402 | printf("processed %d packages, %d new packages, %d new versions, " |
403 | "%d updated versions, %d deleted versions\n", | |
404 | stats.packages, stats.new_packages, stats.new_versions, | |
405 | stats.updated_versions, stats.deleted_versions); | |
d79ec8e9 AS |
406 | } |
407 | ||
408 | static void do_args(int argc, char *argv[]) | |
409 | { | |
410 | char *filename = NULL, *product = NULL; | |
45eb318e | 411 | bool security = FALSE; |
d79ec8e9 AS |
412 | |
413 | /* reinit getopt state */ | |
414 | optind = 0; | |
415 | ||
416 | while (TRUE) | |
417 | { | |
418 | int c; | |
419 | ||
420 | struct option long_opts[] = { | |
421 | { "help", no_argument, NULL, 'h' }, | |
422 | { "file", required_argument, NULL, 'f' }, | |
423 | { "product", required_argument, NULL, 'p' }, | |
45eb318e | 424 | { "security", no_argument, NULL, 's' }, |
d79ec8e9 AS |
425 | { 0,0,0,0 } |
426 | }; | |
427 | ||
428 | c = getopt_long(argc, argv, "", long_opts, NULL); | |
429 | switch (c) | |
430 | { | |
431 | case EOF: | |
432 | break; | |
433 | case 'h': | |
434 | usage(); | |
435 | exit(EXIT_SUCCESS); | |
436 | case 'f': | |
437 | filename = optarg; | |
438 | continue; | |
439 | case 'p': | |
440 | product = optarg; | |
441 | continue; | |
45eb318e AS |
442 | case 's': |
443 | security = TRUE; | |
b5c2a270 | 444 | continue; |
d79ec8e9 AS |
445 | } |
446 | break; | |
447 | } | |
448 | ||
449 | if (filename && product) | |
450 | { | |
45eb318e | 451 | process_packages(filename, product, security); |
d79ec8e9 AS |
452 | } |
453 | else | |
454 | { | |
455 | usage(); | |
456 | exit(EXIT_FAILURE); | |
457 | } | |
458 | } | |
459 | ||
460 | int main(int argc, char *argv[]) | |
461 | { | |
462 | /* enable attest debugging hook */ | |
463 | dbg = pacman_dbg; | |
464 | openlog("pacman", 0, LOG_DEBUG); | |
465 | ||
466 | atexit(cleanup); | |
467 | ||
468 | /* initialize library */ | |
34d3bfcf | 469 | if (!library_init(NULL, "pacman")) |
d79ec8e9 AS |
470 | { |
471 | exit(SS_RC_LIBSTRONGSWAN_INTEGRITY); | |
472 | } | |
b18a5317 | 473 | if (!lib->plugins->load(lib->plugins, |
34d3bfcf | 474 | lib->settings->get_str(lib->settings, "pacman.load", "sqlite"))) |
d79ec8e9 AS |
475 | { |
476 | exit(SS_RC_INITIALIZATION_FAILED); | |
477 | } | |
478 | do_args(argc, argv); | |
479 | ||
480 | exit(EXIT_SUCCESS); | |
481 | } | |
482 |