]> git.ipfire.org Git - people/ms/pakfire.git/blame - src/libpakfire/pakfire.c
libpakfire: db: Use SQLite3
[people/ms/pakfire.git] / src / libpakfire / pakfire.c
CommitLineData
6e46b18e
MT
1/*#############################################################################
2# #
3# Pakfire - The IPFire package management system #
4# Copyright (C) 2017 Pakfire development team #
5# #
6# This program is free software: you can redistribute it and/or modify #
7# it under the terms of the GNU General Public License as published by #
8# the Free Software Foundation, either version 3 of the License, or #
9# (at your option) any later version. #
10# #
11# This program is distributed in the hope that it will be useful, #
12# but WITHOUT ANY WARRANTY; without even the implied warranty of #
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14# GNU General Public License for more details. #
15# #
16# You should have received a copy of the GNU General Public License #
17# along with this program. If not, see <http://www.gnu.org/licenses/>. #
18# #
19#############################################################################*/
20
12656820 21#include <ctype.h>
cb6d631c 22#include <errno.h>
8301098b 23#include <ftw.h>
b36355f7 24#include <stddef.h>
8301098b 25#include <stdio.h>
12656820 26#include <stdlib.h>
3a5d37c5
MT
27#include <sys/stat.h>
28#include <sys/types.h>
12656820 29#include <syslog.h>
3a5d37c5 30#include <unistd.h>
b36355f7 31
f989dacd 32#include <solv/evr.h>
843fcc66 33#include <solv/pool.h>
f989dacd
MT
34#include <solv/poolarch.h>
35#include <solv/queue.h>
843fcc66 36
a5600261 37#include <pakfire/arch.h>
a5376951 38#include <pakfire/constants.h>
33d55ab4 39#include <pakfire/db.h>
5d47c103 40#include <pakfire/logging.h>
f989dacd
MT
41#include <pakfire/package.h>
42#include <pakfire/packagelist.h>
6e46b18e 43#include <pakfire/pakfire.h>
9f953e68 44#include <pakfire/private.h>
843fcc66 45#include <pakfire/repo.h>
6e46b18e
MT
46#include <pakfire/types.h>
47#include <pakfire/util.h>
48
5d47c103
MT
49struct _Pakfire {
50 char* path;
a5376951 51 char* cache_path;
5d47c103 52 char* arch;
f989dacd
MT
53
54 // Pool stuff
f989dacd
MT
55 Pool* pool;
56 int pool_ready;
57 Queue installonly;
5d47c103
MT
58
59 // Logging
60 pakfire_log_function_t log_function;
61 int log_priority;
62
63 int nrefs;
64};
65
12656820
MT
66static int log_priority(const char* priority) {
67 char* end;
68
69 int prio = strtol(priority, &end, 10);
70 if (*end == '\0' || isspace(*end))
71 return prio;
72
73 if (strncmp(priority, "error", strlen("error")) == 0)
74 return LOG_ERR;
75
76 if (strncmp(priority, "info", strlen("info")) == 0)
77 return LOG_INFO;
78
79 if (strncmp(priority, "debug", strlen("debug")) == 0)
80 return LOG_DEBUG;
f06095f1
MT
81
82 return 0;
83}
84
26affd69
MT
85static int pakfire_populate_pool(Pakfire pakfire) {
86 struct pakfire_db* db;
87 int r;
88
89 // Open database in read-only mode and try to load all installed packages
90 r = pakfire_db_open(&db, pakfire, PAKFIRE_DB_READWRITE);
91 if (r)
92 return r;
93
94 // TODO
95
96 // Free database
97 pakfire_db_unref(db);
98
99 return 0;
100}
101
33d55ab4
MT
102// A utility function is already called pakfire_free
103static void _pakfire_free(Pakfire pakfire) {
104 DEBUG(pakfire, "Releasing Pakfire at %p\n", pakfire);
105
106 pakfire_repo_free_all(pakfire);
107
33d55ab4
MT
108 if (pakfire->pool)
109 pool_free(pakfire->pool);
110
111 queue_free(&pakfire->installonly);
112
113 if (pakfire->arch)
114 pakfire_free(pakfire->arch);
115
116 if (pakfire->path)
117 pakfire_free(pakfire->path);
118
119 if (pakfire->cache_path)
120 pakfire_free(pakfire->cache_path);
121
122 pakfire_free(pakfire);
123}
124
6dbda957 125PAKFIRE_EXPORT int pakfire_create(Pakfire* pakfire, const char* path, const char* arch) {
9ad608aa
MT
126 int r;
127
a5600261
MT
128 // Default to the native architecture
129 if (!arch)
130 arch = pakfire_arch_native();
131
132 // Check if the architecture is supported
03b9652a 133 if (!pakfire_arch_supported(arch)) {
6dbda957 134 return -EINVAL;
03b9652a 135 }
a5600261 136
d971fe19 137 // Path must be absolute
5e3ca618 138 if (!pakfire_string_startswith(path, "/")) {
6dbda957 139 return -EINVAL;
d971fe19
MT
140 }
141
1e8366bc
MT
142 // Check if path exists
143 if (!pakfire_path_isdir(path)) {
6dbda957 144 return -ENOENT;
1e8366bc
MT
145 }
146
9db46e1b 147 Pakfire p = pakfire_calloc(1, sizeof(*p));
6dbda957
MT
148 if (!p)
149 return -ENOMEM;
6e46b18e 150
6dbda957 151 p->nrefs = 1;
a5600261 152
6dbda957 153 p->path = pakfire_strdup(path);
af2ad1e0 154
6dbda957
MT
155 // Set architecture
156 p->arch = pakfire_strdup(arch);
12656820 157
6dbda957
MT
158 // Setup logging
159 p->log_function = pakfire_log_syslog;
12656820 160
6dbda957
MT
161 const char* env = secure_getenv("PAKFIRE_LOG");
162 if (env)
163 pakfire_log_set_priority(p, log_priority(env));
1881b8ff 164
6dbda957
MT
165 DEBUG(p, "Pakfire initialized at %p\n", p);
166 DEBUG(p, " arch = %s\n", pakfire_get_arch(p));
167 DEBUG(p, " path = %s\n", pakfire_get_path(p));
f989dacd 168
9ad608aa
MT
169 // Make sure that our private directory exists
170 char* private_dir = pakfire_make_path(p, PAKFIRE_PRIVATE_DIR);
171 r = pakfire_mkdir(p, private_dir, 0);
172 if (r) {
173 ERROR(p, "Could not create private directory %s: %s\n",
174 private_dir, strerror(errno));
175 free(private_dir);
176
177 _pakfire_free(p);
178 return r;
179 }
180
6dbda957
MT
181 // Initialize the pool
182 p->pool = pool_create();
92475554 183 pool_setdisttype(p->pool, DISTTYPE_RPM);
a5376951 184
17247d86
MT
185#ifdef SOLVER_DEBUG
186 pool_setdebuglevel(p->pool, 1);
187#endif
188
6dbda957
MT
189 // Set architecture of the pool
190 pool_setarch(p->pool, p->arch);
af2ad1e0 191
26affd69
MT
192 // Populate pool
193 r = pakfire_populate_pool(p);
194 if (r) {
195 _pakfire_free(p);
196
197 return r;
198 }
199
6dbda957
MT
200 // Initialise cache
201 pakfire_set_cache_path(p, CACHE_PATH);
202
203 *pakfire = p;
204
205 return 0;
6e46b18e
MT
206}
207
9f953e68 208PAKFIRE_EXPORT Pakfire pakfire_ref(Pakfire pakfire) {
af2ad1e0 209 ++pakfire->nrefs;
6e46b18e 210
af2ad1e0 211 return pakfire;
6e46b18e
MT
212}
213
8c916a4d 214PAKFIRE_EXPORT Pakfire pakfire_unref(Pakfire pakfire) {
af2ad1e0 215 if (--pakfire->nrefs > 0)
8c916a4d 216 return pakfire;
af2ad1e0 217
33d55ab4 218 _pakfire_free(pakfire);
8c916a4d 219
8c916a4d 220 return NULL;
6e46b18e
MT
221}
222
9f953e68 223PAKFIRE_EXPORT const char* pakfire_get_path(Pakfire pakfire) {
af2ad1e0 224 return pakfire->path;
6e46b18e
MT
225}
226
9ad608aa
MT
227PAKFIRE_EXPORT char* pakfire_make_path(Pakfire pakfire, const char* path) {
228 // Make sure that path never starts with /
229 if (path && path[0] == '/')
230 path++;
231
232 return pakfire_path_join(pakfire->path, path);
233}
234
9f953e68 235PAKFIRE_EXPORT const char* pakfire_get_arch(Pakfire pakfire) {
af2ad1e0
MT
236 return pakfire->arch;
237}
238
f989dacd
MT
239PAKFIRE_EXPORT int pakfire_version_compare(Pakfire pakfire, const char* evr1, const char* evr2) {
240 return pool_evrcmp_str(pakfire->pool, evr1, evr2, EVRCMP_COMPARE);
6e46b18e 241}
843fcc66 242
19f3d106 243Pool* pakfire_get_solv_pool(Pakfire pakfire) {
f989dacd
MT
244 return pakfire->pool;
245}
246
247void pakfire_pool_has_changed(Pakfire pakfire) {
248 pakfire->pool_ready = 0;
249}
250
b36355f7
MT
251PAKFIRE_EXPORT size_t pakfire_count_packages(Pakfire pakfire) {
252 size_t cnt = 0;
253
254 for (int i = 2; i < pakfire->pool->nsolvables; i++) {
255 Solvable* s = pakfire->pool->solvables + i;
256 if (s->repo)
257 cnt++;
258 }
259
260 return cnt;
261}
262
f989dacd
MT
263void pakfire_pool_apply_changes(Pakfire pakfire) {
264 if (!pakfire->pool_ready) {
265 pool_addfileprovides(pakfire->pool);
266 pool_createwhatprovides(pakfire->pool);
267 pakfire->pool_ready = 1;
268 }
19f3d106
MT
269}
270
0560505f
MT
271PAKFIRE_EXPORT PakfireRepo pakfire_get_repo(Pakfire pakfire, const char* name) {
272 Pool* pool = pakfire_get_solv_pool(pakfire);
273
274 Repo* repo;
275 int i;
276
277 FOR_REPOS(i, repo) {
278 if (strcmp(repo->name, name) == 0)
279 return pakfire_repo_create_from_repo(pakfire, repo);
280 }
281
282 // Nothing found
283 return NULL;
284}
285
843fcc66 286PAKFIRE_EXPORT PakfireRepo pakfire_get_installed_repo(Pakfire pakfire) {
f989dacd 287 if (!pakfire->pool->installed)
843fcc66
MT
288 return NULL;
289
f989dacd 290 return pakfire_repo_create_from_repo(pakfire, pakfire->pool->installed);
843fcc66
MT
291}
292
293PAKFIRE_EXPORT void pakfire_set_installed_repo(Pakfire pakfire, PakfireRepo repo) {
843fcc66 294 if (!repo) {
f989dacd
MT
295 pool_set_installed(pakfire->pool, NULL);
296 return;
297 }
298
299 pool_set_installed(pakfire->pool, pakfire_repo_get_repo(repo));
300}
301
302PAKFIRE_EXPORT const char** pakfire_get_installonly(Pakfire pakfire) {
303 Queue q;
304 queue_init_clone(&q, &pakfire->installonly);
305
306 const char** installonly = pakfire_malloc(sizeof(const char*) * (q.count + 1));
307
308 int i = 0;
309 while (q.count) {
310 installonly[i++] = pool_id2str(pakfire->pool, queue_shift(&q));
311 }
312 installonly[i] = NULL;
313
314 queue_free(&q);
315
316 return installonly;
317}
318
319Queue* pakfire_get_installonly_queue(Pakfire pakfire) {
320 return &pakfire->installonly;
321}
322
323PAKFIRE_EXPORT void pakfire_set_installonly(Pakfire pakfire, const char** installonly) {
324 queue_empty(&pakfire->installonly);
325
326 if (installonly == NULL)
843fcc66 327 return;
f989dacd
MT
328
329 const char* name;
330 while ((name = *installonly++) != NULL)
331 queue_pushunique(&pakfire->installonly, pool_str2id(pakfire->pool, name, 1));
332}
333
334static PakfirePackageList pakfire_pool_dataiterator(Pakfire pakfire, const char* what, int key, int flags) {
12656820 335 PakfirePackageList list = pakfire_packagelist_create(pakfire);
f989dacd
MT
336 pakfire_pool_apply_changes(pakfire);
337
338 int di_flags = 0;
339 if (flags & PAKFIRE_SUBSTRING)
340 di_flags |= SEARCH_SUBSTRING;
341 else
342 di_flags |= SEARCH_STRING;
343
344 if (flags & PAKFIRE_ICASE)
345 di_flags |= SEARCH_NOCASE;
346 if (flags & PAKFIRE_GLOB)
347 di_flags |= SEARCH_GLOB;
348
349 Dataiterator di;
350 dataiterator_init(&di, pakfire->pool, 0, 0, key, what, di_flags);
351 while (dataiterator_step(&di)) {
352 PakfirePackage pkg = pakfire_package_create(pakfire, di.solvid);
353 pakfire_packagelist_push_if_not_exists(list, pkg);
843fcc66 354 }
f989dacd
MT
355 dataiterator_free(&di);
356
357 return list;
358}
359
360static PakfirePackageList pakfire_search_name(Pakfire pakfire, const char* name, int flags) {
361 if (!flags) {
12656820 362 PakfirePackageList list = pakfire_packagelist_create(pakfire);
f989dacd
MT
363 pakfire_pool_apply_changes(pakfire);
364
365 Id id = pool_str2id(pakfire->pool, name, 0);
366 if (id == 0)
367 return list;
368
369 Id p, pp;
370 Pool* pool = pakfire->pool;
371 FOR_PROVIDES(p, pp, id) {
372 Solvable* s = pool_id2solvable(pakfire->pool, p);
373
374 if (s->name == id) {
375 PakfirePackage pkg = pakfire_package_create(pakfire, p);
376 pakfire_packagelist_push_if_not_exists(list, pkg);
377 }
378 }
379
380 return list;
381 }
382
383 return pakfire_pool_dataiterator(pakfire, name, SOLVABLE_NAME, flags);
384}
385
386static PakfirePackageList pakfire_search_provides(Pakfire pakfire, const char* provides, int flags) {
387 if (!flags) {
12656820 388 PakfirePackageList list = pakfire_packagelist_create(pakfire);
f989dacd
MT
389 pakfire_pool_apply_changes(pakfire);
390
391 Id id = pool_str2id(pakfire->pool, provides, 0);
392 if (id == 0)
393 return list;
394
395 Id p, pp;
396 Pool* pool = pakfire->pool;
397 FOR_PROVIDES(p, pp, id) {
398 PakfirePackage pkg = pakfire_package_create(pakfire, p);
399 pakfire_packagelist_push_if_not_exists(list, pkg);
400 }
401
402 return list;
403 }
404
405 return pakfire_pool_dataiterator(pakfire, provides, SOLVABLE_PROVIDES, flags);
406}
407
408PAKFIRE_EXPORT PakfirePackageList pakfire_whatprovides(Pakfire pakfire, const char* what, int flags) {
409 if (flags & PAKFIRE_NAME_ONLY) {
410 flags &= ~PAKFIRE_NAME_ONLY;
411
412 return pakfire_search_name(pakfire, what, flags);
413 } else {
414 return pakfire_search_provides(pakfire, what, flags);
415 }
416}
843fcc66 417
f989dacd
MT
418PAKFIRE_EXPORT PakfirePackageList pakfire_search(Pakfire pakfire, const char* what, int flags) {
419 return pakfire_pool_dataiterator(pakfire, what, 0, PAKFIRE_SUBSTRING);
843fcc66 420}
a5376951
MT
421
422// Cache
423
424PAKFIRE_EXPORT char* pakfire_get_cache_path(Pakfire pakfire, const char* path) {
425 return pakfire_path_join(pakfire->cache_path, path);
426}
427
428PAKFIRE_EXPORT void pakfire_set_cache_path(Pakfire pakfire, const char* path) {
429 // Release old path
430 if (pakfire->cache_path)
431 pakfire_free(pakfire->cache_path);
432
433 pakfire->cache_path = pakfire_strdup(path);
434
12656820 435 DEBUG(pakfire, "Set cache path to %s\n", pakfire->cache_path);
a5376951 436}
3a5d37c5 437
8301098b 438static int _unlink(const char* path, const struct stat* stat, int typeflag, struct FTW* ftwbuf) {
8301098b
MT
439 return remove(path);
440}
441
442PAKFIRE_EXPORT int pakfire_cache_destroy(Pakfire pakfire, const char* path) {
443 char* cache_path = pakfire_get_cache_path(pakfire, path);
444
445 // Completely delete the tree of files
446 int r = nftw(cache_path, _unlink, 64, FTW_DEPTH|FTW_PHYS);
447 pakfire_free(cache_path);
448
cb6d631c
MT
449 // It is okay if the path doesn't exist
450 if (r < 0 && errno == ENOENT)
451 r = 0;
452
8301098b
MT
453 return r;
454}
455
3a5d37c5
MT
456PAKFIRE_EXPORT int pakfire_cache_stat(Pakfire pakfire, const char* path, struct stat* buffer) {
457 char* cache_path = pakfire_get_cache_path(pakfire, path);
458
459 int r = stat(cache_path, buffer);
460 pakfire_free(cache_path);
461
462 return r;
463}
8301098b 464
a239b25d
MT
465PAKFIRE_EXPORT int pakfire_cache_access(Pakfire pakfire, const char* path, int mode) {
466 char* cache_path = pakfire_get_cache_path(pakfire, path);
467
12656820 468 int r = pakfire_access(pakfire, cache_path, NULL, mode);
a239b25d
MT
469 pakfire_free(cache_path);
470
471 return r;
472}
473
8301098b
MT
474PAKFIRE_EXPORT time_t pakfire_cache_age(Pakfire pakfire, const char* path) {
475 struct stat buffer;
476
477 int r = pakfire_cache_stat(pakfire, path, &buffer);
478 if (r == 0) {
479 // Get current timestamp
480 time_t now = time(NULL);
481
482 // Calculate the difference since the file has been created and now.
483 return now - buffer.st_ctime;
484 }
485
486 return -1;
487}
488
489PAKFIRE_EXPORT FILE* pakfire_cache_open(Pakfire pakfire, const char* path, const char* flags) {
490 FILE* f = NULL;
491 char* cache_path = pakfire_get_cache_path(pakfire, path);
492
493 // Ensure that the parent directory exists
b196ec9d 494 char* cache_dirname = pakfire_dirname(cache_path);
8301098b 495
12656820 496 int r = pakfire_mkdir(pakfire, cache_dirname, S_IRUSR|S_IWUSR|S_IXUSR);
8301098b
MT
497 if (r)
498 goto FAIL;
499
500 // Open the file
501 f = fopen(cache_path, flags);
502
503FAIL:
504 pakfire_free(cache_path);
b196ec9d 505 pakfire_free(cache_dirname);
8301098b
MT
506
507 return f;
508}
12656820
MT
509
510PAKFIRE_EXPORT pakfire_log_function_t pakfire_log_get_function(Pakfire pakfire) {
511 return pakfire->log_function;
512}
513
514PAKFIRE_EXPORT void pakfire_log_set_function(Pakfire pakfire, pakfire_log_function_t log_function) {
515 pakfire->log_function = log_function;
516}
517
518PAKFIRE_EXPORT int pakfire_log_get_priority(Pakfire pakfire) {
519 return pakfire->log_priority;
520}
521
522PAKFIRE_EXPORT void pakfire_log_set_priority(Pakfire pakfire, int priority) {
523 pakfire->log_priority = priority;
524}
525
526PAKFIRE_EXPORT void pakfire_log(Pakfire pakfire, int priority, const char* file, int line,
527 const char* fn, const char* format, ...) {
528 va_list args;
529
530 // Save errno
531 int saved_errno = errno;
532
533 va_start(args, format);
534 pakfire->log_function(priority, file, line, fn, format, args);
535 va_end(args);
536
537 // Restore errno
538 errno = saved_errno;
539}