]> git.ipfire.org Git - people/ms/strongswan.git/blame - src/libimcv/plugins/imv_os/pacman.c
lib: Add global config namespace
[people/ms/strongswan.git] / src / libimcv / plugins / imv_os / pacman.c
CommitLineData
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
31typedef enum pacman_state_t pacman_state_t;
32
33enum pacman_state_t {
34 PACMAN_STATE_BEGIN_PACKAGE,
35 PACMAN_STATE_VERSION,
36 PACMAN_STATE_END_PACKAGE
37};
38
39typedef struct stats_t stats_t;
40
41struct 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 */
54static int debug_level = 1;
55static bool stderr_quiet = TRUE;
56
57/**
58 * pacman dbg function
59 */
60static 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 */
99static void cleanup(void)
100{
101 closelog();
102 library_deinit();
103}
104
105static 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
114static 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 276static 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
408static 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
460int 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