]> git.ipfire.org Git - pakfire.git/blame - src/libpakfire/pakfire.c
libpakfire: Drop pakfire_malloc
[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
f0d6233d 102static void pakfire_free(Pakfire pakfire) {
33d55ab4
MT
103 DEBUG(pakfire, "Releasing Pakfire at %p\n", pakfire);
104
105 pakfire_repo_free_all(pakfire);
106
33d55ab4
MT
107 if (pakfire->pool)
108 pool_free(pakfire->pool);
109
110 queue_free(&pakfire->installonly);
111
112 if (pakfire->arch)
f0d6233d 113 free(pakfire->arch);
33d55ab4
MT
114
115 if (pakfire->path)
f0d6233d 116 free(pakfire->path);
33d55ab4
MT
117
118 if (pakfire->cache_path)
f0d6233d 119 free(pakfire->cache_path);
33d55ab4 120
f0d6233d 121 free(pakfire);
33d55ab4
MT
122}
123
6dbda957 124PAKFIRE_EXPORT int pakfire_create(Pakfire* pakfire, const char* path, const char* arch) {
9ad608aa
MT
125 int r;
126
a5600261
MT
127 // Default to the native architecture
128 if (!arch)
129 arch = pakfire_arch_native();
130
131 // Check if the architecture is supported
03b9652a 132 if (!pakfire_arch_supported(arch)) {
6dbda957 133 return -EINVAL;
03b9652a 134 }
a5600261 135
d971fe19 136 // Path must be absolute
5e3ca618 137 if (!pakfire_string_startswith(path, "/")) {
6dbda957 138 return -EINVAL;
d971fe19
MT
139 }
140
1e8366bc
MT
141 // Check if path exists
142 if (!pakfire_path_isdir(path)) {
6dbda957 143 return -ENOENT;
1e8366bc
MT
144 }
145
90312f5c 146 Pakfire p = calloc(1, sizeof(*p));
6dbda957
MT
147 if (!p)
148 return -ENOMEM;
6e46b18e 149
6dbda957 150 p->nrefs = 1;
a5600261 151
6dbda957 152 p->path = pakfire_strdup(path);
af2ad1e0 153
6dbda957
MT
154 // Set architecture
155 p->arch = pakfire_strdup(arch);
12656820 156
6dbda957
MT
157 // Setup logging
158 p->log_function = pakfire_log_syslog;
12656820 159
6dbda957
MT
160 const char* env = secure_getenv("PAKFIRE_LOG");
161 if (env)
162 pakfire_log_set_priority(p, log_priority(env));
1881b8ff 163
6dbda957
MT
164 DEBUG(p, "Pakfire initialized at %p\n", p);
165 DEBUG(p, " arch = %s\n", pakfire_get_arch(p));
166 DEBUG(p, " path = %s\n", pakfire_get_path(p));
f989dacd 167
9ad608aa
MT
168 // Make sure that our private directory exists
169 char* private_dir = pakfire_make_path(p, PAKFIRE_PRIVATE_DIR);
170 r = pakfire_mkdir(p, private_dir, 0);
171 if (r) {
172 ERROR(p, "Could not create private directory %s: %s\n",
173 private_dir, strerror(errno));
174 free(private_dir);
175
f0d6233d 176 pakfire_free(p);
9ad608aa
MT
177 return r;
178 }
179
6dbda957
MT
180 // Initialize the pool
181 p->pool = pool_create();
92475554 182 pool_setdisttype(p->pool, DISTTYPE_RPM);
a5376951 183
17247d86
MT
184#ifdef SOLVER_DEBUG
185 pool_setdebuglevel(p->pool, 1);
186#endif
187
6dbda957
MT
188 // Set architecture of the pool
189 pool_setarch(p->pool, p->arch);
af2ad1e0 190
26affd69
MT
191 // Populate pool
192 r = pakfire_populate_pool(p);
193 if (r) {
f0d6233d 194 pakfire_free(p);
26affd69
MT
195
196 return r;
197 }
198
6dbda957
MT
199 // Initialise cache
200 pakfire_set_cache_path(p, CACHE_PATH);
201
202 *pakfire = p;
203
204 return 0;
6e46b18e
MT
205}
206
9f953e68 207PAKFIRE_EXPORT Pakfire pakfire_ref(Pakfire pakfire) {
af2ad1e0 208 ++pakfire->nrefs;
6e46b18e 209
af2ad1e0 210 return pakfire;
6e46b18e
MT
211}
212
8c916a4d 213PAKFIRE_EXPORT Pakfire pakfire_unref(Pakfire pakfire) {
af2ad1e0 214 if (--pakfire->nrefs > 0)
8c916a4d 215 return pakfire;
af2ad1e0 216
f0d6233d 217 pakfire_free(pakfire);
8c916a4d 218
8c916a4d 219 return NULL;
6e46b18e
MT
220}
221
9f953e68 222PAKFIRE_EXPORT const char* pakfire_get_path(Pakfire pakfire) {
af2ad1e0 223 return pakfire->path;
6e46b18e
MT
224}
225
9ad608aa
MT
226PAKFIRE_EXPORT char* pakfire_make_path(Pakfire pakfire, const char* path) {
227 // Make sure that path never starts with /
228 if (path && path[0] == '/')
229 path++;
230
231 return pakfire_path_join(pakfire->path, path);
232}
233
9f953e68 234PAKFIRE_EXPORT const char* pakfire_get_arch(Pakfire pakfire) {
af2ad1e0
MT
235 return pakfire->arch;
236}
237
f989dacd
MT
238PAKFIRE_EXPORT int pakfire_version_compare(Pakfire pakfire, const char* evr1, const char* evr2) {
239 return pool_evrcmp_str(pakfire->pool, evr1, evr2, EVRCMP_COMPARE);
6e46b18e 240}
843fcc66 241
19f3d106 242Pool* pakfire_get_solv_pool(Pakfire pakfire) {
f989dacd
MT
243 return pakfire->pool;
244}
245
246void pakfire_pool_has_changed(Pakfire pakfire) {
247 pakfire->pool_ready = 0;
248}
249
b36355f7
MT
250PAKFIRE_EXPORT size_t pakfire_count_packages(Pakfire pakfire) {
251 size_t cnt = 0;
252
253 for (int i = 2; i < pakfire->pool->nsolvables; i++) {
254 Solvable* s = pakfire->pool->solvables + i;
255 if (s->repo)
256 cnt++;
257 }
258
259 return cnt;
260}
261
f989dacd
MT
262void pakfire_pool_apply_changes(Pakfire pakfire) {
263 if (!pakfire->pool_ready) {
264 pool_addfileprovides(pakfire->pool);
265 pool_createwhatprovides(pakfire->pool);
266 pakfire->pool_ready = 1;
267 }
19f3d106
MT
268}
269
0560505f
MT
270PAKFIRE_EXPORT PakfireRepo pakfire_get_repo(Pakfire pakfire, const char* name) {
271 Pool* pool = pakfire_get_solv_pool(pakfire);
272
273 Repo* repo;
274 int i;
275
276 FOR_REPOS(i, repo) {
277 if (strcmp(repo->name, name) == 0)
278 return pakfire_repo_create_from_repo(pakfire, repo);
279 }
280
281 // Nothing found
282 return NULL;
283}
284
843fcc66 285PAKFIRE_EXPORT PakfireRepo pakfire_get_installed_repo(Pakfire pakfire) {
f989dacd 286 if (!pakfire->pool->installed)
843fcc66
MT
287 return NULL;
288
f989dacd 289 return pakfire_repo_create_from_repo(pakfire, pakfire->pool->installed);
843fcc66
MT
290}
291
292PAKFIRE_EXPORT void pakfire_set_installed_repo(Pakfire pakfire, PakfireRepo repo) {
843fcc66 293 if (!repo) {
f989dacd
MT
294 pool_set_installed(pakfire->pool, NULL);
295 return;
296 }
297
298 pool_set_installed(pakfire->pool, pakfire_repo_get_repo(repo));
299}
300
301PAKFIRE_EXPORT const char** pakfire_get_installonly(Pakfire pakfire) {
302 Queue q;
303 queue_init_clone(&q, &pakfire->installonly);
304
547759ae 305 const char** installonly = malloc(sizeof(const char*) * (q.count + 1));
f989dacd
MT
306
307 int i = 0;
308 while (q.count) {
309 installonly[i++] = pool_id2str(pakfire->pool, queue_shift(&q));
310 }
311 installonly[i] = NULL;
312
313 queue_free(&q);
314
315 return installonly;
316}
317
318Queue* pakfire_get_installonly_queue(Pakfire pakfire) {
319 return &pakfire->installonly;
320}
321
322PAKFIRE_EXPORT void pakfire_set_installonly(Pakfire pakfire, const char** installonly) {
323 queue_empty(&pakfire->installonly);
324
325 if (installonly == NULL)
843fcc66 326 return;
f989dacd
MT
327
328 const char* name;
329 while ((name = *installonly++) != NULL)
330 queue_pushunique(&pakfire->installonly, pool_str2id(pakfire->pool, name, 1));
331}
332
333static PakfirePackageList pakfire_pool_dataiterator(Pakfire pakfire, const char* what, int key, int flags) {
12656820 334 PakfirePackageList list = pakfire_packagelist_create(pakfire);
f989dacd
MT
335 pakfire_pool_apply_changes(pakfire);
336
337 int di_flags = 0;
338 if (flags & PAKFIRE_SUBSTRING)
339 di_flags |= SEARCH_SUBSTRING;
340 else
341 di_flags |= SEARCH_STRING;
342
343 if (flags & PAKFIRE_ICASE)
344 di_flags |= SEARCH_NOCASE;
345 if (flags & PAKFIRE_GLOB)
346 di_flags |= SEARCH_GLOB;
347
348 Dataiterator di;
349 dataiterator_init(&di, pakfire->pool, 0, 0, key, what, di_flags);
350 while (dataiterator_step(&di)) {
351 PakfirePackage pkg = pakfire_package_create(pakfire, di.solvid);
352 pakfire_packagelist_push_if_not_exists(list, pkg);
843fcc66 353 }
f989dacd
MT
354 dataiterator_free(&di);
355
356 return list;
357}
358
359static PakfirePackageList pakfire_search_name(Pakfire pakfire, const char* name, int flags) {
360 if (!flags) {
12656820 361 PakfirePackageList list = pakfire_packagelist_create(pakfire);
f989dacd
MT
362 pakfire_pool_apply_changes(pakfire);
363
364 Id id = pool_str2id(pakfire->pool, name, 0);
365 if (id == 0)
366 return list;
367
368 Id p, pp;
369 Pool* pool = pakfire->pool;
370 FOR_PROVIDES(p, pp, id) {
371 Solvable* s = pool_id2solvable(pakfire->pool, p);
372
373 if (s->name == id) {
374 PakfirePackage pkg = pakfire_package_create(pakfire, p);
375 pakfire_packagelist_push_if_not_exists(list, pkg);
376 }
377 }
378
379 return list;
380 }
381
382 return pakfire_pool_dataiterator(pakfire, name, SOLVABLE_NAME, flags);
383}
384
385static PakfirePackageList pakfire_search_provides(Pakfire pakfire, const char* provides, int flags) {
386 if (!flags) {
12656820 387 PakfirePackageList list = pakfire_packagelist_create(pakfire);
f989dacd
MT
388 pakfire_pool_apply_changes(pakfire);
389
390 Id id = pool_str2id(pakfire->pool, provides, 0);
391 if (id == 0)
392 return list;
393
394 Id p, pp;
395 Pool* pool = pakfire->pool;
396 FOR_PROVIDES(p, pp, id) {
397 PakfirePackage pkg = pakfire_package_create(pakfire, p);
398 pakfire_packagelist_push_if_not_exists(list, pkg);
399 }
400
401 return list;
402 }
403
404 return pakfire_pool_dataiterator(pakfire, provides, SOLVABLE_PROVIDES, flags);
405}
406
407PAKFIRE_EXPORT PakfirePackageList pakfire_whatprovides(Pakfire pakfire, const char* what, int flags) {
408 if (flags & PAKFIRE_NAME_ONLY) {
409 flags &= ~PAKFIRE_NAME_ONLY;
410
411 return pakfire_search_name(pakfire, what, flags);
412 } else {
413 return pakfire_search_provides(pakfire, what, flags);
414 }
415}
843fcc66 416
f989dacd
MT
417PAKFIRE_EXPORT PakfirePackageList pakfire_search(Pakfire pakfire, const char* what, int flags) {
418 return pakfire_pool_dataiterator(pakfire, what, 0, PAKFIRE_SUBSTRING);
843fcc66 419}
a5376951
MT
420
421// Cache
422
423PAKFIRE_EXPORT char* pakfire_get_cache_path(Pakfire pakfire, const char* path) {
424 return pakfire_path_join(pakfire->cache_path, path);
425}
426
427PAKFIRE_EXPORT void pakfire_set_cache_path(Pakfire pakfire, const char* path) {
428 // Release old path
429 if (pakfire->cache_path)
f0d6233d 430 free(pakfire->cache_path);
a5376951
MT
431
432 pakfire->cache_path = pakfire_strdup(path);
433
12656820 434 DEBUG(pakfire, "Set cache path to %s\n", pakfire->cache_path);
a5376951 435}
3a5d37c5 436
8301098b 437static int _unlink(const char* path, const struct stat* stat, int typeflag, struct FTW* ftwbuf) {
8301098b
MT
438 return remove(path);
439}
440
441PAKFIRE_EXPORT int pakfire_cache_destroy(Pakfire pakfire, const char* path) {
442 char* cache_path = pakfire_get_cache_path(pakfire, path);
443
444 // Completely delete the tree of files
445 int r = nftw(cache_path, _unlink, 64, FTW_DEPTH|FTW_PHYS);
f0d6233d 446 free(cache_path);
8301098b 447
cb6d631c
MT
448 // It is okay if the path doesn't exist
449 if (r < 0 && errno == ENOENT)
450 r = 0;
451
8301098b
MT
452 return r;
453}
454
3a5d37c5
MT
455PAKFIRE_EXPORT int pakfire_cache_stat(Pakfire pakfire, const char* path, struct stat* buffer) {
456 char* cache_path = pakfire_get_cache_path(pakfire, path);
457
458 int r = stat(cache_path, buffer);
f0d6233d 459 free(cache_path);
3a5d37c5
MT
460
461 return r;
462}
8301098b 463
a239b25d
MT
464PAKFIRE_EXPORT int pakfire_cache_access(Pakfire pakfire, const char* path, int mode) {
465 char* cache_path = pakfire_get_cache_path(pakfire, path);
466
12656820 467 int r = pakfire_access(pakfire, cache_path, NULL, mode);
f0d6233d 468 free(cache_path);
a239b25d
MT
469
470 return r;
471}
472
8301098b
MT
473PAKFIRE_EXPORT time_t pakfire_cache_age(Pakfire pakfire, const char* path) {
474 struct stat buffer;
475
476 int r = pakfire_cache_stat(pakfire, path, &buffer);
477 if (r == 0) {
478 // Get current timestamp
479 time_t now = time(NULL);
480
481 // Calculate the difference since the file has been created and now.
482 return now - buffer.st_ctime;
483 }
484
485 return -1;
486}
487
488PAKFIRE_EXPORT FILE* pakfire_cache_open(Pakfire pakfire, const char* path, const char* flags) {
489 FILE* f = NULL;
490 char* cache_path = pakfire_get_cache_path(pakfire, path);
491
492 // Ensure that the parent directory exists
b196ec9d 493 char* cache_dirname = pakfire_dirname(cache_path);
8301098b 494
12656820 495 int r = pakfire_mkdir(pakfire, cache_dirname, S_IRUSR|S_IWUSR|S_IXUSR);
8301098b
MT
496 if (r)
497 goto FAIL;
498
499 // Open the file
500 f = fopen(cache_path, flags);
501
502FAIL:
f0d6233d
MT
503 free(cache_path);
504 free(cache_dirname);
8301098b
MT
505
506 return f;
507}
12656820
MT
508
509PAKFIRE_EXPORT pakfire_log_function_t pakfire_log_get_function(Pakfire pakfire) {
510 return pakfire->log_function;
511}
512
513PAKFIRE_EXPORT void pakfire_log_set_function(Pakfire pakfire, pakfire_log_function_t log_function) {
514 pakfire->log_function = log_function;
515}
516
517PAKFIRE_EXPORT int pakfire_log_get_priority(Pakfire pakfire) {
518 return pakfire->log_priority;
519}
520
521PAKFIRE_EXPORT void pakfire_log_set_priority(Pakfire pakfire, int priority) {
522 pakfire->log_priority = priority;
523}
524
525PAKFIRE_EXPORT void pakfire_log(Pakfire pakfire, int priority, const char* file, int line,
526 const char* fn, const char* format, ...) {
527 va_list args;
528
529 // Save errno
530 int saved_errno = errno;
531
532 va_start(args, format);
533 pakfire->log_function(priority, file, line, fn, format, args);
534 va_end(args);
535
536 // Restore errno
537 errno = saved_errno;
538}