1 /*
2  *  handle.c
3  *
4  *  Copyright (c) 2006-2018 Pacman Development Team <pacman-dev@archlinux.org>
5  *  Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
6  *  Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
7  *  Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.org>
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #include <errno.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <limits.h>
27 #include <sys/types.h>
28 #include <syslog.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 
32 /* libalpm */
33 #include "handle.h"
34 #include "alpm_list.h"
35 #include "util.h"
36 #include "log.h"
37 #include "delta.h"
38 #include "trans.h"
39 #include "alpm.h"
40 #include "deps.h"
41 
_alpm_handle_new(void)42 alpm_handle_t *_alpm_handle_new(void)
43 {
44 	alpm_handle_t *handle;
45 
46 	CALLOC(handle, 1, sizeof(alpm_handle_t), return NULL);
47 	handle->deltaratio = 0.0;
48 	handle->lockfd = -1;
49 
50 	return handle;
51 }
52 
_alpm_handle_free(alpm_handle_t * handle)53 void _alpm_handle_free(alpm_handle_t *handle)
54 {
55 	if(handle == NULL) {
56 		return;
57 	}
58 
59 	/* close logfile */
60 	if(handle->logstream) {
61 		fclose(handle->logstream);
62 		handle->logstream = NULL;
63 	}
64 	if(handle->usesyslog) {
65 		handle->usesyslog = 0;
66 		closelog();
67 	}
68 
69 #ifdef HAVE_LIBCURL
70 	/* release curl handle */
71 	curl_easy_cleanup(handle->curl);
72 #endif
73 
74 #ifdef HAVE_LIBGPGME
75 	FREELIST(handle->known_keys);
76 #endif
77 
78 	regfree(&handle->delta_regex);
79 
80 	/* free memory */
81 	_alpm_trans_free(handle->trans);
82 	FREE(handle->root);
83 	FREE(handle->dbpath);
84 	FREE(handle->dbext);
85 	FREELIST(handle->cachedirs);
86 	FREELIST(handle->hookdirs);
87 	FREE(handle->logfile);
88 	FREE(handle->lockfile);
89 	FREE(handle->arch);
90 	FREE(handle->gpgdir);
91 	FREELIST(handle->noupgrade);
92 	FREELIST(handle->noextract);
93 	FREELIST(handle->ignorepkg);
94 	FREELIST(handle->ignoregroup);
95 	FREELIST(handle->overwrite_files);
96 
97 	alpm_list_free_inner(handle->assumeinstalled, (alpm_list_fn_free)alpm_dep_free);
98 	alpm_list_free(handle->assumeinstalled);
99 
100 	FREE(handle);
101 }
102 
103 /** Lock the database */
_alpm_handle_lock(alpm_handle_t * handle)104 int _alpm_handle_lock(alpm_handle_t *handle)
105 {
106 	char *dir, *ptr;
107 
108 	ASSERT(handle->lockfile != NULL, return -1);
109 	ASSERT(handle->lockfd < 0, return 0);
110 
111 	/* create the dir of the lockfile first */
112 	dir = strdup(handle->lockfile);
113 	ptr = strrchr(dir, '/');
114 	if(ptr) {
115 		*ptr = '\0';
116 	}
117 	if(_alpm_makepath(dir)) {
118 		FREE(dir);
119 		return -1;
120 	}
121 	FREE(dir);
122 
123 	do {
124 		handle->lockfd = open(handle->lockfile, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
125 	} while(handle->lockfd == -1 && errno == EINTR);
126 
127 	return (handle->lockfd >= 0 ? 0 : -1);
128 }
129 
130 /** Remove the database lock file
131  * @param handle the context handle
132  * @return 0 on success, -1 on error
133  *
134  * @note Safe to call from inside signal handlers.
135  */
alpm_unlock(alpm_handle_t * handle)136 int SYMEXPORT alpm_unlock(alpm_handle_t *handle)
137 {
138 	ASSERT(handle != NULL, return -1);
139 	ASSERT(handle->lockfile != NULL, return 0);
140 	ASSERT(handle->lockfd >= 0, return 0);
141 
142 	close(handle->lockfd);
143 	handle->lockfd = -1;
144 
145 	if(unlink(handle->lockfile) != 0) {
146 		RET_ERR_ASYNC_SAFE(handle, ALPM_ERR_SYSTEM, -1);
147 	} else {
148 		return 0;
149 	}
150 }
151 
_alpm_handle_unlock(alpm_handle_t * handle)152 int _alpm_handle_unlock(alpm_handle_t *handle)
153 {
154 	if(alpm_unlock(handle) != 0) {
155 		if(errno == ENOENT) {
156 			_alpm_log(handle, ALPM_LOG_WARNING,
157 					_("lock file missing %s\n"), handle->lockfile);
158 			alpm_logaction(handle, ALPM_CALLER_PREFIX,
159 					"warning: lock file missing %s\n", handle->lockfile);
160 			return 0;
161 		} else {
162 			_alpm_log(handle, ALPM_LOG_WARNING,
163 					_("could not remove lock file %s\n"), handle->lockfile);
164 			alpm_logaction(handle, ALPM_CALLER_PREFIX,
165 					"warning: could not remove lock file %s\n", handle->lockfile);
166 			return -1;
167 		}
168 	}
169 
170 	return 0;
171 }
172 
173 
alpm_option_get_logcb(alpm_handle_t * handle)174 alpm_cb_log SYMEXPORT alpm_option_get_logcb(alpm_handle_t *handle)
175 {
176 	CHECK_HANDLE(handle, return NULL);
177 	return handle->logcb;
178 }
179 
alpm_option_get_dlcb(alpm_handle_t * handle)180 alpm_cb_download SYMEXPORT alpm_option_get_dlcb(alpm_handle_t *handle)
181 {
182 	CHECK_HANDLE(handle, return NULL);
183 	return handle->dlcb;
184 }
185 
alpm_option_get_fetchcb(alpm_handle_t * handle)186 alpm_cb_fetch SYMEXPORT alpm_option_get_fetchcb(alpm_handle_t *handle)
187 {
188 	CHECK_HANDLE(handle, return NULL);
189 	return handle->fetchcb;
190 }
191 
alpm_option_get_totaldlcb(alpm_handle_t * handle)192 alpm_cb_totaldl SYMEXPORT alpm_option_get_totaldlcb(alpm_handle_t *handle)
193 {
194 	CHECK_HANDLE(handle, return NULL);
195 	return handle->totaldlcb;
196 }
197 
alpm_option_get_eventcb(alpm_handle_t * handle)198 alpm_cb_event SYMEXPORT alpm_option_get_eventcb(alpm_handle_t *handle)
199 {
200 	CHECK_HANDLE(handle, return NULL);
201 	return handle->eventcb;
202 }
203 
alpm_option_get_questioncb(alpm_handle_t * handle)204 alpm_cb_question SYMEXPORT alpm_option_get_questioncb(alpm_handle_t *handle)
205 {
206 	CHECK_HANDLE(handle, return NULL);
207 	return handle->questioncb;
208 }
209 
alpm_option_get_progresscb(alpm_handle_t * handle)210 alpm_cb_progress SYMEXPORT alpm_option_get_progresscb(alpm_handle_t *handle)
211 {
212 	CHECK_HANDLE(handle, return NULL);
213 	return handle->progresscb;
214 }
215 
alpm_option_get_root(alpm_handle_t * handle)216 const char SYMEXPORT *alpm_option_get_root(alpm_handle_t *handle)
217 {
218 	CHECK_HANDLE(handle, return NULL);
219 	return handle->root;
220 }
221 
alpm_option_get_dbpath(alpm_handle_t * handle)222 const char SYMEXPORT *alpm_option_get_dbpath(alpm_handle_t *handle)
223 {
224 	CHECK_HANDLE(handle, return NULL);
225 	return handle->dbpath;
226 }
227 
alpm_option_get_hookdirs(alpm_handle_t * handle)228 alpm_list_t SYMEXPORT *alpm_option_get_hookdirs(alpm_handle_t *handle)
229 {
230 	CHECK_HANDLE(handle, return NULL);
231 	return handle->hookdirs;
232 }
233 
alpm_option_get_cachedirs(alpm_handle_t * handle)234 alpm_list_t SYMEXPORT *alpm_option_get_cachedirs(alpm_handle_t *handle)
235 {
236 	CHECK_HANDLE(handle, return NULL);
237 	return handle->cachedirs;
238 }
239 
alpm_option_get_logfile(alpm_handle_t * handle)240 const char SYMEXPORT *alpm_option_get_logfile(alpm_handle_t *handle)
241 {
242 	CHECK_HANDLE(handle, return NULL);
243 	return handle->logfile;
244 }
245 
alpm_option_get_lockfile(alpm_handle_t * handle)246 const char SYMEXPORT *alpm_option_get_lockfile(alpm_handle_t *handle)
247 {
248 	CHECK_HANDLE(handle, return NULL);
249 	return handle->lockfile;
250 }
251 
alpm_option_get_gpgdir(alpm_handle_t * handle)252 const char SYMEXPORT *alpm_option_get_gpgdir(alpm_handle_t *handle)
253 {
254 	CHECK_HANDLE(handle, return NULL);
255 	return handle->gpgdir;
256 }
257 
alpm_option_get_usesyslog(alpm_handle_t * handle)258 int SYMEXPORT alpm_option_get_usesyslog(alpm_handle_t *handle)
259 {
260 	CHECK_HANDLE(handle, return -1);
261 	return handle->usesyslog;
262 }
263 
alpm_option_get_noupgrades(alpm_handle_t * handle)264 alpm_list_t SYMEXPORT *alpm_option_get_noupgrades(alpm_handle_t *handle)
265 {
266 	CHECK_HANDLE(handle, return NULL);
267 	return handle->noupgrade;
268 }
269 
alpm_option_get_noextracts(alpm_handle_t * handle)270 alpm_list_t SYMEXPORT *alpm_option_get_noextracts(alpm_handle_t *handle)
271 {
272 	CHECK_HANDLE(handle, return NULL);
273 	return handle->noextract;
274 }
275 
alpm_option_get_ignorepkgs(alpm_handle_t * handle)276 alpm_list_t SYMEXPORT *alpm_option_get_ignorepkgs(alpm_handle_t *handle)
277 {
278 	CHECK_HANDLE(handle, return NULL);
279 	return handle->ignorepkg;
280 }
281 
alpm_option_get_ignoregroups(alpm_handle_t * handle)282 alpm_list_t SYMEXPORT *alpm_option_get_ignoregroups(alpm_handle_t *handle)
283 {
284 	CHECK_HANDLE(handle, return NULL);
285 	return handle->ignoregroup;
286 }
287 
alpm_option_get_overwrite_files(alpm_handle_t * handle)288 alpm_list_t SYMEXPORT *alpm_option_get_overwrite_files(alpm_handle_t *handle)
289 {
290 	CHECK_HANDLE(handle, return NULL);
291 	return handle->overwrite_files;
292 }
293 
alpm_option_get_assumeinstalled(alpm_handle_t * handle)294 alpm_list_t SYMEXPORT *alpm_option_get_assumeinstalled(alpm_handle_t *handle)
295 {
296 	CHECK_HANDLE(handle, return NULL);
297 	return handle->assumeinstalled;
298 }
299 
alpm_option_get_arch(alpm_handle_t * handle)300 const char SYMEXPORT *alpm_option_get_arch(alpm_handle_t *handle)
301 {
302 	CHECK_HANDLE(handle, return NULL);
303 	return handle->arch;
304 }
305 
alpm_option_get_deltaratio(alpm_handle_t * handle)306 double SYMEXPORT alpm_option_get_deltaratio(alpm_handle_t *handle)
307 {
308 	CHECK_HANDLE(handle, return -1);
309 	return handle->deltaratio;
310 }
311 
alpm_option_get_checkspace(alpm_handle_t * handle)312 int SYMEXPORT alpm_option_get_checkspace(alpm_handle_t *handle)
313 {
314 	CHECK_HANDLE(handle, return -1);
315 	return handle->checkspace;
316 }
317 
alpm_option_get_dbext(alpm_handle_t * handle)318 const char SYMEXPORT *alpm_option_get_dbext(alpm_handle_t *handle)
319 {
320 	CHECK_HANDLE(handle, return NULL);
321 	return handle->dbext;
322 }
323 
alpm_option_set_logcb(alpm_handle_t * handle,alpm_cb_log cb)324 int SYMEXPORT alpm_option_set_logcb(alpm_handle_t *handle, alpm_cb_log cb)
325 {
326 	CHECK_HANDLE(handle, return -1);
327 	handle->logcb = cb;
328 	return 0;
329 }
330 
alpm_option_set_dlcb(alpm_handle_t * handle,alpm_cb_download cb)331 int SYMEXPORT alpm_option_set_dlcb(alpm_handle_t *handle, alpm_cb_download cb)
332 {
333 	CHECK_HANDLE(handle, return -1);
334 	handle->dlcb = cb;
335 	return 0;
336 }
337 
alpm_option_set_fetchcb(alpm_handle_t * handle,alpm_cb_fetch cb)338 int SYMEXPORT alpm_option_set_fetchcb(alpm_handle_t *handle, alpm_cb_fetch cb)
339 {
340 	CHECK_HANDLE(handle, return -1);
341 	handle->fetchcb = cb;
342 	return 0;
343 }
344 
alpm_option_set_totaldlcb(alpm_handle_t * handle,alpm_cb_totaldl cb)345 int SYMEXPORT alpm_option_set_totaldlcb(alpm_handle_t *handle, alpm_cb_totaldl cb)
346 {
347 	CHECK_HANDLE(handle, return -1);
348 	handle->totaldlcb = cb;
349 	return 0;
350 }
351 
alpm_option_set_eventcb(alpm_handle_t * handle,alpm_cb_event cb)352 int SYMEXPORT alpm_option_set_eventcb(alpm_handle_t *handle, alpm_cb_event cb)
353 {
354 	CHECK_HANDLE(handle, return -1);
355 	handle->eventcb = cb;
356 	return 0;
357 }
358 
alpm_option_set_questioncb(alpm_handle_t * handle,alpm_cb_question cb)359 int SYMEXPORT alpm_option_set_questioncb(alpm_handle_t *handle, alpm_cb_question cb)
360 {
361 	CHECK_HANDLE(handle, return -1);
362 	handle->questioncb = cb;
363 	return 0;
364 }
365 
alpm_option_set_progresscb(alpm_handle_t * handle,alpm_cb_progress cb)366 int SYMEXPORT alpm_option_set_progresscb(alpm_handle_t *handle, alpm_cb_progress cb)
367 {
368 	CHECK_HANDLE(handle, return -1);
369 	handle->progresscb = cb;
370 	return 0;
371 }
372 
canonicalize_path(const char * path)373 static char *canonicalize_path(const char *path)
374 {
375 	char *new_path;
376 	size_t len;
377 
378 	/* verify path ends in a '/' */
379 	len = strlen(path);
380 	if(path[len - 1] != '/') {
381 		len += 1;
382 	}
383 	CALLOC(new_path, len + 1, sizeof(char), return NULL);
384 	strcpy(new_path, path);
385 	new_path[len - 1] = '/';
386 	return new_path;
387 }
388 
_alpm_set_directory_option(const char * value,char ** storage,int must_exist)389 alpm_errno_t _alpm_set_directory_option(const char *value,
390 		char **storage, int must_exist)
391 {
392 	struct stat st;
393 	char real[PATH_MAX];
394 	const char *path;
395 
396 	path = value;
397 	if(!path) {
398 		return ALPM_ERR_WRONG_ARGS;
399 	}
400 	if(must_exist) {
401 		if(stat(path, &st) == -1 || !S_ISDIR(st.st_mode)) {
402 			return ALPM_ERR_NOT_A_DIR;
403 		}
404 		if(!realpath(path, real)) {
405 			return ALPM_ERR_NOT_A_DIR;
406 		}
407 		path = real;
408 	}
409 
410 	if(*storage) {
411 		FREE(*storage);
412 	}
413 	*storage = canonicalize_path(path);
414 	if(!*storage) {
415 		return ALPM_ERR_MEMORY;
416 	}
417 	return 0;
418 }
419 
alpm_option_add_hookdir(alpm_handle_t * handle,const char * hookdir)420 int SYMEXPORT alpm_option_add_hookdir(alpm_handle_t *handle, const char *hookdir)
421 {
422 	char *newhookdir;
423 
424 	CHECK_HANDLE(handle, return -1);
425 	ASSERT(hookdir != NULL, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1));
426 
427 	newhookdir = canonicalize_path(hookdir);
428 	if(!newhookdir) {
429 		RET_ERR(handle, ALPM_ERR_MEMORY, -1);
430 	}
431 	handle->hookdirs = alpm_list_add(handle->hookdirs, newhookdir);
432 	_alpm_log(handle, ALPM_LOG_DEBUG, "option 'hookdir' = %s\n", newhookdir);
433 	return 0;
434 }
435 
alpm_option_set_hookdirs(alpm_handle_t * handle,alpm_list_t * hookdirs)436 int SYMEXPORT alpm_option_set_hookdirs(alpm_handle_t *handle, alpm_list_t *hookdirs)
437 {
438 	alpm_list_t *i;
439 	CHECK_HANDLE(handle, return -1);
440 	if(handle->hookdirs) {
441 		FREELIST(handle->hookdirs);
442 	}
443 	for(i = hookdirs; i; i = i->next) {
444 		int ret = alpm_option_add_hookdir(handle, i->data);
445 		if(ret) {
446 			return ret;
447 		}
448 	}
449 	return 0;
450 }
451 
alpm_option_remove_hookdir(alpm_handle_t * handle,const char * hookdir)452 int SYMEXPORT alpm_option_remove_hookdir(alpm_handle_t *handle, const char *hookdir)
453 {
454 	char *vdata = NULL;
455 	char *newhookdir;
456 	CHECK_HANDLE(handle, return -1);
457 	ASSERT(hookdir != NULL, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1));
458 
459 	newhookdir = canonicalize_path(hookdir);
460 	if(!newhookdir) {
461 		RET_ERR(handle, ALPM_ERR_MEMORY, -1);
462 	}
463 	handle->hookdirs = alpm_list_remove_str(handle->hookdirs, newhookdir, &vdata);
464 	FREE(newhookdir);
465 	if(vdata != NULL) {
466 		FREE(vdata);
467 		return 1;
468 	}
469 	return 0;
470 }
471 
alpm_option_add_cachedir(alpm_handle_t * handle,const char * cachedir)472 int SYMEXPORT alpm_option_add_cachedir(alpm_handle_t *handle, const char *cachedir)
473 {
474 	char *newcachedir;
475 
476 	CHECK_HANDLE(handle, return -1);
477 	ASSERT(cachedir != NULL, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1));
478 	/* don't stat the cachedir yet, as it may not even be needed. we can
479 	 * fail later if it is needed and the path is invalid. */
480 
481 	newcachedir = canonicalize_path(cachedir);
482 	if(!newcachedir) {
483 		RET_ERR(handle, ALPM_ERR_MEMORY, -1);
484 	}
485 	handle->cachedirs = alpm_list_add(handle->cachedirs, newcachedir);
486 	_alpm_log(handle, ALPM_LOG_DEBUG, "option 'cachedir' = %s\n", newcachedir);
487 	return 0;
488 }
489 
alpm_option_set_cachedirs(alpm_handle_t * handle,alpm_list_t * cachedirs)490 int SYMEXPORT alpm_option_set_cachedirs(alpm_handle_t *handle, alpm_list_t *cachedirs)
491 {
492 	alpm_list_t *i;
493 	CHECK_HANDLE(handle, return -1);
494 	if(handle->cachedirs) {
495 		FREELIST(handle->cachedirs);
496 	}
497 	for(i = cachedirs; i; i = i->next) {
498 		int ret = alpm_option_add_cachedir(handle, i->data);
499 		if(ret) {
500 			return ret;
501 		}
502 	}
503 	return 0;
504 }
505 
alpm_option_remove_cachedir(alpm_handle_t * handle,const char * cachedir)506 int SYMEXPORT alpm_option_remove_cachedir(alpm_handle_t *handle, const char *cachedir)
507 {
508 	char *vdata = NULL;
509 	char *newcachedir;
510 	CHECK_HANDLE(handle, return -1);
511 	ASSERT(cachedir != NULL, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1));
512 
513 	newcachedir = canonicalize_path(cachedir);
514 	if(!newcachedir) {
515 		RET_ERR(handle, ALPM_ERR_MEMORY, -1);
516 	}
517 	handle->cachedirs = alpm_list_remove_str(handle->cachedirs, newcachedir, &vdata);
518 	FREE(newcachedir);
519 	if(vdata != NULL) {
520 		FREE(vdata);
521 		return 1;
522 	}
523 	return 0;
524 }
525 
alpm_option_set_logfile(alpm_handle_t * handle,const char * logfile)526 int SYMEXPORT alpm_option_set_logfile(alpm_handle_t *handle, const char *logfile)
527 {
528 	char *oldlogfile = handle->logfile;
529 
530 	CHECK_HANDLE(handle, return -1);
531 	if(!logfile) {
532 		handle->pm_errno = ALPM_ERR_WRONG_ARGS;
533 		return -1;
534 	}
535 
536 	STRDUP(handle->logfile, logfile, RET_ERR(handle, ALPM_ERR_MEMORY, -1));
537 
538 	/* free the old logfile path string, and close the stream so logaction
539 	 * will reopen a new stream on the new logfile */
540 	if(oldlogfile) {
541 		FREE(oldlogfile);
542 	}
543 	if(handle->logstream) {
544 		fclose(handle->logstream);
545 		handle->logstream = NULL;
546 	}
547 	_alpm_log(handle, ALPM_LOG_DEBUG, "option 'logfile' = %s\n", handle->logfile);
548 	return 0;
549 }
550 
alpm_option_set_gpgdir(alpm_handle_t * handle,const char * gpgdir)551 int SYMEXPORT alpm_option_set_gpgdir(alpm_handle_t *handle, const char *gpgdir)
552 {
553 	int err;
554 	CHECK_HANDLE(handle, return -1);
555 	if((err = _alpm_set_directory_option(gpgdir, &(handle->gpgdir), 0))) {
556 		RET_ERR(handle, err, -1);
557 	}
558 	_alpm_log(handle, ALPM_LOG_DEBUG, "option 'gpgdir' = %s\n", handle->gpgdir);
559 	return 0;
560 }
561 
alpm_option_set_usesyslog(alpm_handle_t * handle,int usesyslog)562 int SYMEXPORT alpm_option_set_usesyslog(alpm_handle_t *handle, int usesyslog)
563 {
564 	CHECK_HANDLE(handle, return -1);
565 	handle->usesyslog = usesyslog;
566 	return 0;
567 }
568 
_alpm_option_strlist_add(alpm_handle_t * handle,alpm_list_t ** list,const char * str)569 static int _alpm_option_strlist_add(alpm_handle_t *handle, alpm_list_t **list, const char *str)
570 {
571 	char *dup;
572 	CHECK_HANDLE(handle, return -1);
573 	STRDUP(dup, str, RET_ERR(handle, ALPM_ERR_MEMORY, -1));
574 	*list = alpm_list_add(*list, dup);
575 	return 0;
576 }
577 
_alpm_option_strlist_set(alpm_handle_t * handle,alpm_list_t ** list,alpm_list_t * newlist)578 static int _alpm_option_strlist_set(alpm_handle_t *handle, alpm_list_t **list, alpm_list_t *newlist)
579 {
580 	CHECK_HANDLE(handle, return -1);
581 	FREELIST(*list);
582 	*list = alpm_list_strdup(newlist);
583 	return 0;
584 }
585 
_alpm_option_strlist_rem(alpm_handle_t * handle,alpm_list_t ** list,const char * str)586 static int _alpm_option_strlist_rem(alpm_handle_t *handle, alpm_list_t **list, const char *str)
587 {
588 	char *vdata = NULL;
589 	CHECK_HANDLE(handle, return -1);
590 	*list = alpm_list_remove_str(*list, str, &vdata);
591 	if(vdata != NULL) {
592 		FREE(vdata);
593 		return 1;
594 	}
595 	return 0;
596 }
597 
alpm_option_add_noupgrade(alpm_handle_t * handle,const char * pkg)598 int SYMEXPORT alpm_option_add_noupgrade(alpm_handle_t *handle, const char *pkg)
599 {
600 	return _alpm_option_strlist_add(handle, &(handle->noupgrade), pkg);
601 }
602 
alpm_option_set_noupgrades(alpm_handle_t * handle,alpm_list_t * noupgrade)603 int SYMEXPORT alpm_option_set_noupgrades(alpm_handle_t *handle, alpm_list_t *noupgrade)
604 {
605 	return _alpm_option_strlist_set(handle, &(handle->noupgrade), noupgrade);
606 }
607 
alpm_option_remove_noupgrade(alpm_handle_t * handle,const char * pkg)608 int SYMEXPORT alpm_option_remove_noupgrade(alpm_handle_t *handle, const char *pkg)
609 {
610 	return _alpm_option_strlist_rem(handle, &(handle->noupgrade), pkg);
611 }
612 
alpm_option_match_noupgrade(alpm_handle_t * handle,const char * path)613 int SYMEXPORT alpm_option_match_noupgrade(alpm_handle_t *handle, const char *path)
614 {
615 	return _alpm_fnmatch_patterns(handle->noupgrade, path);
616 }
617 
alpm_option_add_noextract(alpm_handle_t * handle,const char * path)618 int SYMEXPORT alpm_option_add_noextract(alpm_handle_t *handle, const char *path)
619 {
620 	return _alpm_option_strlist_add(handle, &(handle->noextract), path);
621 }
622 
alpm_option_set_noextracts(alpm_handle_t * handle,alpm_list_t * noextract)623 int SYMEXPORT alpm_option_set_noextracts(alpm_handle_t *handle, alpm_list_t *noextract)
624 {
625 	return _alpm_option_strlist_set(handle, &(handle->noextract), noextract);
626 }
627 
alpm_option_remove_noextract(alpm_handle_t * handle,const char * path)628 int SYMEXPORT alpm_option_remove_noextract(alpm_handle_t *handle, const char *path)
629 {
630 	return _alpm_option_strlist_rem(handle, &(handle->noextract), path);
631 }
632 
alpm_option_match_noextract(alpm_handle_t * handle,const char * path)633 int SYMEXPORT alpm_option_match_noextract(alpm_handle_t *handle, const char *path)
634 {
635 	return _alpm_fnmatch_patterns(handle->noextract, path);
636 }
637 
alpm_option_add_ignorepkg(alpm_handle_t * handle,const char * pkg)638 int SYMEXPORT alpm_option_add_ignorepkg(alpm_handle_t *handle, const char *pkg)
639 {
640 	return _alpm_option_strlist_add(handle, &(handle->ignorepkg), pkg);
641 }
642 
alpm_option_set_ignorepkgs(alpm_handle_t * handle,alpm_list_t * ignorepkgs)643 int SYMEXPORT alpm_option_set_ignorepkgs(alpm_handle_t *handle, alpm_list_t *ignorepkgs)
644 {
645 	return _alpm_option_strlist_set(handle, &(handle->ignorepkg), ignorepkgs);
646 }
647 
alpm_option_remove_ignorepkg(alpm_handle_t * handle,const char * pkg)648 int SYMEXPORT alpm_option_remove_ignorepkg(alpm_handle_t *handle, const char *pkg)
649 {
650 	return _alpm_option_strlist_rem(handle, &(handle->ignorepkg), pkg);
651 }
652 
alpm_option_add_ignoregroup(alpm_handle_t * handle,const char * grp)653 int SYMEXPORT alpm_option_add_ignoregroup(alpm_handle_t *handle, const char *grp)
654 {
655 	return _alpm_option_strlist_add(handle, &(handle->ignoregroup), grp);
656 }
657 
alpm_option_set_ignoregroups(alpm_handle_t * handle,alpm_list_t * ignoregrps)658 int SYMEXPORT alpm_option_set_ignoregroups(alpm_handle_t *handle, alpm_list_t *ignoregrps)
659 {
660 	return _alpm_option_strlist_set(handle, &(handle->ignoregroup), ignoregrps);
661 }
662 
alpm_option_remove_ignoregroup(alpm_handle_t * handle,const char * grp)663 int SYMEXPORT alpm_option_remove_ignoregroup(alpm_handle_t *handle, const char *grp)
664 {
665 	return _alpm_option_strlist_rem(handle, &(handle->ignoregroup), grp);
666 }
667 
alpm_option_add_overwrite_file(alpm_handle_t * handle,const char * glob)668 int SYMEXPORT alpm_option_add_overwrite_file(alpm_handle_t *handle, const char *glob)
669 {
670 	return _alpm_option_strlist_add(handle, &(handle->overwrite_files), glob);
671 }
672 
alpm_option_set_overwrite_files(alpm_handle_t * handle,alpm_list_t * globs)673 int SYMEXPORT alpm_option_set_overwrite_files(alpm_handle_t *handle, alpm_list_t *globs)
674 {
675 	return _alpm_option_strlist_set(handle, &(handle->overwrite_files), globs);
676 }
677 
alpm_option_remove_overwrite_file(alpm_handle_t * handle,const char * glob)678 int SYMEXPORT alpm_option_remove_overwrite_file(alpm_handle_t *handle, const char *glob)
679 {
680 	return _alpm_option_strlist_rem(handle, &(handle->overwrite_files), glob);
681 }
682 
alpm_option_add_assumeinstalled(alpm_handle_t * handle,const alpm_depend_t * dep)683 int SYMEXPORT alpm_option_add_assumeinstalled(alpm_handle_t *handle, const alpm_depend_t *dep)
684 {
685 	alpm_depend_t *depcpy;
686 	CHECK_HANDLE(handle, return -1);
687 	ASSERT(dep->mod == ALPM_DEP_MOD_EQ || dep->mod == ALPM_DEP_MOD_ANY,
688 			RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1));
689 	ASSERT((depcpy = _alpm_dep_dup(dep)), RET_ERR(handle, ALPM_ERR_MEMORY, -1));
690 
691 	/* fill in name_hash in case dep was built by hand */
692 	depcpy->name_hash = _alpm_hash_sdbm(dep->name);
693 	handle->assumeinstalled = alpm_list_add(handle->assumeinstalled, depcpy);
694 	return 0;
695 }
696 
alpm_option_set_assumeinstalled(alpm_handle_t * handle,alpm_list_t * deps)697 int SYMEXPORT alpm_option_set_assumeinstalled(alpm_handle_t *handle, alpm_list_t *deps)
698 {
699 	CHECK_HANDLE(handle, return -1);
700 	if(handle->assumeinstalled) {
701 		alpm_list_free_inner(handle->assumeinstalled, (alpm_list_fn_free)alpm_dep_free);
702 		alpm_list_free(handle->assumeinstalled);
703 	}
704 	while(deps) {
705 		if(alpm_option_add_assumeinstalled(handle, deps->data) != 0) {
706 			return -1;
707 		}
708 		deps = deps->next;
709 	}
710 	return 0;
711 }
712 
assumeinstalled_cmp(const void * d1,const void * d2)713 static int assumeinstalled_cmp(const void *d1, const void *d2)
714 {
715 	const alpm_depend_t *dep1 = d1;
716 	const alpm_depend_t *dep2 = d2;
717 
718 	if(dep1->name_hash != dep2->name_hash
719 			|| strcmp(dep1->name, dep2->name) != 0) {
720 		return -1;
721 	}
722 
723 	if(dep1->version && dep2->version
724 			&& strcmp(dep1->version, dep2->version) == 0) {
725 		return 0;
726 	}
727 
728 	if(dep1->version == NULL && dep2->version == NULL) {
729 		return 0;
730 	}
731 
732 
733 	return -1;
734 }
735 
alpm_option_remove_assumeinstalled(alpm_handle_t * handle,const alpm_depend_t * dep)736 int SYMEXPORT alpm_option_remove_assumeinstalled(alpm_handle_t *handle, const alpm_depend_t *dep)
737 {
738 	alpm_depend_t *vdata = NULL;
739 	CHECK_HANDLE(handle, return -1);
740 
741 	handle->assumeinstalled = alpm_list_remove(handle->assumeinstalled, dep, &assumeinstalled_cmp, (void **)&vdata);
742 	if(vdata != NULL) {
743 		alpm_dep_free(vdata);
744 		return 1;
745 	}
746 
747 	return 0;
748 }
749 
alpm_option_set_arch(alpm_handle_t * handle,const char * arch)750 int SYMEXPORT alpm_option_set_arch(alpm_handle_t *handle, const char *arch)
751 {
752 	CHECK_HANDLE(handle, return -1);
753 	if(handle->arch) FREE(handle->arch);
754 	STRDUP(handle->arch, arch, RET_ERR(handle, ALPM_ERR_MEMORY, -1));
755 	return 0;
756 }
757 
alpm_option_set_deltaratio(alpm_handle_t * handle,double ratio)758 int SYMEXPORT alpm_option_set_deltaratio(alpm_handle_t *handle, double ratio)
759 {
760 	CHECK_HANDLE(handle, return -1);
761 	if(ratio < 0.0 || ratio > 2.0) {
762 		RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1);
763 	}
764 	handle->deltaratio = ratio;
765 	return 0;
766 }
767 
alpm_get_localdb(alpm_handle_t * handle)768 alpm_db_t SYMEXPORT *alpm_get_localdb(alpm_handle_t *handle)
769 {
770 	CHECK_HANDLE(handle, return NULL);
771 	return handle->db_local;
772 }
773 
alpm_get_syncdbs(alpm_handle_t * handle)774 alpm_list_t SYMEXPORT *alpm_get_syncdbs(alpm_handle_t *handle)
775 {
776 	CHECK_HANDLE(handle, return NULL);
777 	return handle->dbs_sync;
778 }
779 
alpm_option_set_checkspace(alpm_handle_t * handle,int checkspace)780 int SYMEXPORT alpm_option_set_checkspace(alpm_handle_t *handle, int checkspace)
781 {
782 	CHECK_HANDLE(handle, return -1);
783 	handle->checkspace = checkspace;
784 	return 0;
785 }
786 
alpm_option_set_dbext(alpm_handle_t * handle,const char * dbext)787 int SYMEXPORT alpm_option_set_dbext(alpm_handle_t *handle, const char *dbext)
788 {
789 	CHECK_HANDLE(handle, return -1);
790 	ASSERT(dbext, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1));
791 
792 	if(handle->dbext) {
793 		FREE(handle->dbext);
794 	}
795 
796 	STRDUP(handle->dbext, dbext, RET_ERR(handle, ALPM_ERR_MEMORY, -1));
797 
798 	_alpm_log(handle, ALPM_LOG_DEBUG, "option 'dbext' = %s\n", handle->dbext);
799 	return 0;
800 }
801 
alpm_option_set_default_siglevel(alpm_handle_t * handle,int level)802 int SYMEXPORT alpm_option_set_default_siglevel(alpm_handle_t *handle,
803 		int level)
804 {
805 	CHECK_HANDLE(handle, return -1);
806 #ifdef HAVE_LIBGPGME
807 	handle->siglevel = level;
808 #else
809 	if(level != 0 && level != ALPM_SIG_USE_DEFAULT) {
810 		RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1);
811 	}
812 #endif
813 	return 0;
814 }
815 
alpm_option_get_default_siglevel(alpm_handle_t * handle)816 int SYMEXPORT alpm_option_get_default_siglevel(alpm_handle_t *handle)
817 {
818 	CHECK_HANDLE(handle, return -1);
819 	return handle->siglevel;
820 }
821 
alpm_option_set_local_file_siglevel(alpm_handle_t * handle,int level)822 int SYMEXPORT alpm_option_set_local_file_siglevel(alpm_handle_t *handle,
823 		int level)
824 {
825 	CHECK_HANDLE(handle, return -1);
826 #ifdef HAVE_LIBGPGME
827 	handle->localfilesiglevel = level;
828 #else
829 	if(level != 0 && level != ALPM_SIG_USE_DEFAULT) {
830 		RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1);
831 	}
832 #endif
833 	return 0;
834 }
835 
alpm_option_get_local_file_siglevel(alpm_handle_t * handle)836 int SYMEXPORT alpm_option_get_local_file_siglevel(alpm_handle_t *handle)
837 {
838 	CHECK_HANDLE(handle, return -1);
839 	if(handle->localfilesiglevel & ALPM_SIG_USE_DEFAULT) {
840 		return handle->siglevel;
841 	} else {
842 		return handle->localfilesiglevel;
843 	}
844 }
845 
alpm_option_set_remote_file_siglevel(alpm_handle_t * handle,int level)846 int SYMEXPORT alpm_option_set_remote_file_siglevel(alpm_handle_t *handle,
847 		int level)
848 {
849 	CHECK_HANDLE(handle, return -1);
850 #ifdef HAVE_LIBGPGME
851 	handle->remotefilesiglevel = level;
852 #else
853 	if(level != 0 && level != ALPM_SIG_USE_DEFAULT) {
854 		RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1);
855 	}
856 #endif
857 	return 0;
858 }
859 
alpm_option_get_remote_file_siglevel(alpm_handle_t * handle)860 int SYMEXPORT alpm_option_get_remote_file_siglevel(alpm_handle_t *handle)
861 {
862 	CHECK_HANDLE(handle, return -1);
863 	if(handle->remotefilesiglevel & ALPM_SIG_USE_DEFAULT) {
864 		return handle->siglevel;
865 	} else {
866 		return handle->remotefilesiglevel;
867 	}
868 }
869 
alpm_option_set_disable_dl_timeout(alpm_handle_t * handle,unsigned short disable_dl_timeout)870 int SYMEXPORT alpm_option_set_disable_dl_timeout(alpm_handle_t *handle,
871 		unsigned short disable_dl_timeout)
872 {
873 	CHECK_HANDLE(handle, return -1);
874 #ifdef HAVE_LIBCURL
875 	handle->disable_dl_timeout = disable_dl_timeout;
876 #endif
877 	return 0;
878 }
879