libalpm
Arch Linux Package Manager Library
handle.c
Go to the documentation of this file.
00001 /*
00002  *  handle.c
00003  *
00004  *  Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
00005  *  Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
00006  *  Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
00007  *  Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.org>
00008  *
00009  *  This program is free software; you can redistribute it and/or modify
00010  *  it under the terms of the GNU General Public License as published by
00011  *  the Free Software Foundation; either version 2 of the License, or
00012  *  (at your option) any later version.
00013  *
00014  *  This program is distributed in the hope that it will be useful,
00015  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  *  GNU General Public License for more details.
00018  *
00019  *  You should have received a copy of the GNU General Public License
00020  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00021  */
00022 
00023 #include <errno.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026 #include <limits.h>
00027 #include <sys/types.h>
00028 #include <syslog.h>
00029 #include <sys/stat.h>
00030 #include <fcntl.h>
00031 
00032 /* libalpm */
00033 #include "handle.h"
00034 #include "alpm_list.h"
00035 #include "util.h"
00036 #include "log.h"
00037 #include "delta.h"
00038 #include "trans.h"
00039 #include "alpm.h"
00040 
00041 alpm_handle_t *_alpm_handle_new(void)
00042 {
00043     alpm_handle_t *handle;
00044 
00045     CALLOC(handle, 1, sizeof(alpm_handle_t), return NULL);
00046 
00047     return handle;
00048 }
00049 
00050 void _alpm_handle_free(alpm_handle_t *handle)
00051 {
00052     if(handle == NULL) {
00053         return;
00054     }
00055 
00056     /* close logfile */
00057     if(handle->logstream) {
00058         fclose(handle->logstream);
00059         handle->logstream= NULL;
00060     }
00061     if(handle->usesyslog) {
00062         handle->usesyslog = 0;
00063         closelog();
00064     }
00065 
00066 #ifdef HAVE_LIBCURL
00067     /* release curl handle */
00068     curl_easy_cleanup(handle->curl);
00069 #endif
00070 
00071     regfree(&handle->delta_regex);
00072 
00073     /* free memory */
00074     _alpm_trans_free(handle->trans);
00075     FREE(handle->root);
00076     FREE(handle->dbpath);
00077     FREELIST(handle->cachedirs);
00078     FREE(handle->logfile);
00079     FREE(handle->lockfile);
00080     FREE(handle->arch);
00081     FREE(handle->gpgdir);
00082     FREELIST(handle->dbs_sync);
00083     FREELIST(handle->noupgrade);
00084     FREELIST(handle->noextract);
00085     FREELIST(handle->ignorepkg);
00086     FREELIST(handle->ignoregroup);
00087     FREE(handle);
00088 }
00089 
00090 /** Lock the database */
00091 int _alpm_handle_lock(alpm_handle_t *handle)
00092 {
00093     int fd;
00094     char *dir, *ptr;
00095 
00096     ASSERT(handle->lockfile != NULL, return -1);
00097     ASSERT(handle->lckstream == NULL, return 0);
00098 
00099     /* create the dir of the lockfile first */
00100     dir = strdup(handle->lockfile);
00101     ptr = strrchr(dir, '/');
00102     if(ptr) {
00103         *ptr = '\0';
00104     }
00105     if(_alpm_makepath(dir)) {
00106         FREE(dir);
00107         return -1;
00108     }
00109     FREE(dir);
00110 
00111     do {
00112         fd = open(handle->lockfile, O_WRONLY | O_CREAT | O_EXCL, 0000);
00113     } while(fd == -1 && errno == EINTR);
00114     if(fd >= 0) {
00115         FILE *f = fdopen(fd, "w");
00116         fprintf(f, "%ld\n", (long)getpid());
00117         fflush(f);
00118         fsync(fd);
00119         handle->lckstream = f;
00120         return 0;
00121     }
00122     return -1;
00123 }
00124 
00125 /** Remove a lock file */
00126 int _alpm_handle_unlock(alpm_handle_t *handle)
00127 {
00128     ASSERT(handle->lockfile != NULL, return -1);
00129     ASSERT(handle->lckstream != NULL, return 0);
00130 
00131     fclose(handle->lckstream);
00132     handle->lckstream = NULL;
00133 
00134     if(unlink(handle->lockfile) && errno != ENOENT) {
00135         return -1;
00136     }
00137     return 0;
00138 }
00139 
00140 
00141 alpm_cb_log SYMEXPORT alpm_option_get_logcb(alpm_handle_t *handle)
00142 {
00143     CHECK_HANDLE(handle, return NULL);
00144     return handle->logcb;
00145 }
00146 
00147 alpm_cb_download SYMEXPORT alpm_option_get_dlcb(alpm_handle_t *handle)
00148 {
00149     CHECK_HANDLE(handle, return NULL);
00150     return handle->dlcb;
00151 }
00152 
00153 alpm_cb_fetch SYMEXPORT alpm_option_get_fetchcb(alpm_handle_t *handle)
00154 {
00155     CHECK_HANDLE(handle, return NULL);
00156     return handle->fetchcb;
00157 }
00158 
00159 alpm_cb_totaldl SYMEXPORT alpm_option_get_totaldlcb(alpm_handle_t *handle)
00160 {
00161     CHECK_HANDLE(handle, return NULL);
00162     return handle->totaldlcb;
00163 }
00164 
00165 alpm_cb_event SYMEXPORT alpm_option_get_eventcb(alpm_handle_t *handle)
00166 {
00167     CHECK_HANDLE(handle, return NULL);
00168     return handle->eventcb;
00169 }
00170 
00171 alpm_cb_question SYMEXPORT alpm_option_get_questioncb(alpm_handle_t *handle)
00172 {
00173     CHECK_HANDLE(handle, return NULL);
00174     return handle->questioncb;
00175 }
00176 
00177 alpm_cb_progress SYMEXPORT alpm_option_get_progresscb(alpm_handle_t *handle)
00178 {
00179     CHECK_HANDLE(handle, return NULL);
00180     return handle->progresscb;
00181 }
00182 
00183 const char SYMEXPORT *alpm_option_get_root(alpm_handle_t *handle)
00184 {
00185     CHECK_HANDLE(handle, return NULL);
00186     return handle->root;
00187 }
00188 
00189 const char SYMEXPORT *alpm_option_get_dbpath(alpm_handle_t *handle)
00190 {
00191     CHECK_HANDLE(handle, return NULL);
00192     return handle->dbpath;
00193 }
00194 
00195 alpm_list_t SYMEXPORT *alpm_option_get_cachedirs(alpm_handle_t *handle)
00196 {
00197     CHECK_HANDLE(handle, return NULL);
00198     return handle->cachedirs;
00199 }
00200 
00201 const char SYMEXPORT *alpm_option_get_logfile(alpm_handle_t *handle)
00202 {
00203     CHECK_HANDLE(handle, return NULL);
00204     return handle->logfile;
00205 }
00206 
00207 const char SYMEXPORT *alpm_option_get_lockfile(alpm_handle_t *handle)
00208 {
00209     CHECK_HANDLE(handle, return NULL);
00210     return handle->lockfile;
00211 }
00212 
00213 const char SYMEXPORT *alpm_option_get_gpgdir(alpm_handle_t *handle)
00214 {
00215     CHECK_HANDLE(handle, return NULL);
00216     return handle->gpgdir;
00217 }
00218 
00219 int SYMEXPORT alpm_option_get_usesyslog(alpm_handle_t *handle)
00220 {
00221     CHECK_HANDLE(handle, return -1);
00222     return handle->usesyslog;
00223 }
00224 
00225 alpm_list_t SYMEXPORT *alpm_option_get_noupgrades(alpm_handle_t *handle)
00226 {
00227     CHECK_HANDLE(handle, return NULL);
00228     return handle->noupgrade;
00229 }
00230 
00231 alpm_list_t SYMEXPORT *alpm_option_get_noextracts(alpm_handle_t *handle)
00232 {
00233     CHECK_HANDLE(handle, return NULL);
00234     return handle->noextract;
00235 }
00236 
00237 alpm_list_t SYMEXPORT *alpm_option_get_ignorepkgs(alpm_handle_t *handle)
00238 {
00239     CHECK_HANDLE(handle, return NULL);
00240     return handle->ignorepkg;
00241 }
00242 
00243 alpm_list_t SYMEXPORT *alpm_option_get_ignoregroups(alpm_handle_t *handle)
00244 {
00245     CHECK_HANDLE(handle, return NULL);
00246     return handle->ignoregroup;
00247 }
00248 
00249 const char SYMEXPORT *alpm_option_get_arch(alpm_handle_t *handle)
00250 {
00251     CHECK_HANDLE(handle, return NULL);
00252     return handle->arch;
00253 }
00254 
00255 int SYMEXPORT alpm_option_get_usedelta(alpm_handle_t *handle)
00256 {
00257     CHECK_HANDLE(handle, return -1);
00258     return handle->usedelta;
00259 }
00260 
00261 int SYMEXPORT alpm_option_get_checkspace(alpm_handle_t *handle)
00262 {
00263     CHECK_HANDLE(handle, return -1);
00264     return handle->checkspace;
00265 }
00266 
00267 alpm_db_t SYMEXPORT *alpm_option_get_localdb(alpm_handle_t *handle)
00268 {
00269     CHECK_HANDLE(handle, return NULL);
00270     return handle->db_local;
00271 }
00272 
00273 alpm_list_t SYMEXPORT *alpm_option_get_syncdbs(alpm_handle_t *handle)
00274 {
00275     CHECK_HANDLE(handle, return NULL);
00276     return handle->dbs_sync;
00277 }
00278 
00279 int SYMEXPORT alpm_option_set_logcb(alpm_handle_t *handle, alpm_cb_log cb)
00280 {
00281     CHECK_HANDLE(handle, return -1);
00282     handle->logcb = cb;
00283     return 0;
00284 }
00285 
00286 int SYMEXPORT alpm_option_set_dlcb(alpm_handle_t *handle, alpm_cb_download cb)
00287 {
00288     CHECK_HANDLE(handle, return -1);
00289     handle->dlcb = cb;
00290     return 0;
00291 }
00292 
00293 int SYMEXPORT alpm_option_set_fetchcb(alpm_handle_t *handle, alpm_cb_fetch cb)
00294 {
00295     CHECK_HANDLE(handle, return -1);
00296     handle->fetchcb = cb;
00297     return 0;
00298 }
00299 
00300 int SYMEXPORT alpm_option_set_totaldlcb(alpm_handle_t *handle, alpm_cb_totaldl cb)
00301 {
00302     CHECK_HANDLE(handle, return -1);
00303     handle->totaldlcb = cb;
00304     return 0;
00305 }
00306 
00307 int SYMEXPORT alpm_option_set_eventcb(alpm_handle_t *handle, alpm_cb_event cb)
00308 {
00309     CHECK_HANDLE(handle, return -1);
00310     handle->eventcb = cb;
00311     return 0;
00312 }
00313 
00314 int SYMEXPORT alpm_option_set_questioncb(alpm_handle_t *handle, alpm_cb_question cb)
00315 {
00316     CHECK_HANDLE(handle, return -1);
00317     handle->questioncb = cb;
00318     return 0;
00319 }
00320 
00321 int SYMEXPORT alpm_option_set_progresscb(alpm_handle_t *handle, alpm_cb_progress cb)
00322 {
00323     CHECK_HANDLE(handle, return -1);
00324     handle->progresscb = cb;
00325     return 0;
00326 }
00327 
00328 static char *canonicalize_path(const char *path) {
00329     char *new_path;
00330     size_t len;
00331 
00332     /* verify path ends in a '/' */
00333     len = strlen(path);
00334     if(path[len - 1] != '/') {
00335         len += 1;
00336     }
00337     CALLOC(new_path, len + 1, sizeof(char), return NULL);
00338     strcpy(new_path, path);
00339     new_path[len - 1] = '/';
00340     return new_path;
00341 }
00342 
00343 alpm_errno_t _alpm_set_directory_option(const char *value,
00344         char **storage, int must_exist)
00345  {
00346     struct stat st;
00347     char *real = NULL;
00348     const char *path;
00349 
00350     path = value;
00351     if(!path) {
00352         return ALPM_ERR_WRONG_ARGS;
00353     }
00354     if(must_exist) {
00355         if(stat(path, &st) == -1 || !S_ISDIR(st.st_mode)) {
00356             return ALPM_ERR_NOT_A_DIR;
00357         }
00358         CALLOC(real, PATH_MAX, sizeof(char), return ALPM_ERR_MEMORY);
00359         if(!realpath(path, real)) {
00360             free(real);
00361             return ALPM_ERR_NOT_A_DIR;
00362         }
00363         path = real;
00364     }
00365 
00366     if(*storage) {
00367         FREE(*storage);
00368     }
00369     *storage = canonicalize_path(path);
00370     if(!*storage) {
00371         return ALPM_ERR_MEMORY;
00372     }
00373     free(real);
00374     return 0;
00375 }
00376 
00377 int SYMEXPORT alpm_option_add_cachedir(alpm_handle_t *handle, const char *cachedir)
00378 {
00379     char *newcachedir;
00380 
00381     CHECK_HANDLE(handle, return -1);
00382     ASSERT(cachedir != NULL, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1));
00383     /* don't stat the cachedir yet, as it may not even be needed. we can
00384      * fail later if it is needed and the path is invalid. */
00385 
00386     newcachedir = canonicalize_path(cachedir);
00387     if(!newcachedir) {
00388         RET_ERR(handle, ALPM_ERR_MEMORY, -1);
00389     }
00390     handle->cachedirs = alpm_list_add(handle->cachedirs, newcachedir);
00391     _alpm_log(handle, ALPM_LOG_DEBUG, "option 'cachedir' = %s\n", newcachedir);
00392     return 0;
00393 }
00394 
00395 int SYMEXPORT alpm_option_set_cachedirs(alpm_handle_t *handle, alpm_list_t *cachedirs)
00396 {
00397     alpm_list_t *i;
00398     CHECK_HANDLE(handle, return -1);
00399     if(handle->cachedirs) {
00400         FREELIST(handle->cachedirs);
00401     }
00402     for(i = cachedirs; i; i = i->next) {
00403         int ret = alpm_option_add_cachedir(handle, i->data);
00404         if(ret) {
00405             return ret;
00406         }
00407     }
00408     return 0;
00409 }
00410 
00411 int SYMEXPORT alpm_option_remove_cachedir(alpm_handle_t *handle, const char *cachedir)
00412 {
00413     char *vdata = NULL;
00414     char *newcachedir;
00415     CHECK_HANDLE(handle, return -1);
00416     ASSERT(cachedir != NULL, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1));
00417 
00418     newcachedir = canonicalize_path(cachedir);
00419     if(!newcachedir) {
00420         RET_ERR(handle, ALPM_ERR_MEMORY, -1);
00421     }
00422     handle->cachedirs = alpm_list_remove_str(handle->cachedirs, newcachedir, &vdata);
00423     FREE(newcachedir);
00424     if(vdata != NULL) {
00425         FREE(vdata);
00426         return 1;
00427     }
00428     return 0;
00429 }
00430 
00431 int SYMEXPORT alpm_option_set_logfile(alpm_handle_t *handle, const char *logfile)
00432 {
00433     char *oldlogfile = handle->logfile;
00434 
00435     CHECK_HANDLE(handle, return -1);
00436     if(!logfile) {
00437         handle->pm_errno = ALPM_ERR_WRONG_ARGS;
00438         return -1;
00439     }
00440 
00441     handle->logfile = strdup(logfile);
00442 
00443     /* free the old logfile path string, and close the stream so logaction
00444      * will reopen a new stream on the new logfile */
00445     if(oldlogfile) {
00446         FREE(oldlogfile);
00447     }
00448     if(handle->logstream) {
00449         fclose(handle->logstream);
00450         handle->logstream = NULL;
00451     }
00452     _alpm_log(handle, ALPM_LOG_DEBUG, "option 'logfile' = %s\n", handle->logfile);
00453     return 0;
00454 }
00455 
00456 int SYMEXPORT alpm_option_set_gpgdir(alpm_handle_t *handle, const char *gpgdir)
00457 {
00458     CHECK_HANDLE(handle, return -1);
00459     if(!gpgdir) {
00460         handle->pm_errno = ALPM_ERR_WRONG_ARGS;
00461         return -1;
00462     }
00463 
00464     if(handle->gpgdir) {
00465         FREE(handle->gpgdir);
00466     }
00467     handle->gpgdir = strdup(gpgdir);
00468 
00469     _alpm_log(handle, ALPM_LOG_DEBUG, "option 'gpgdir' = %s\n", handle->gpgdir);
00470     return 0;
00471 }
00472 
00473 int SYMEXPORT alpm_option_set_usesyslog(alpm_handle_t *handle, int usesyslog)
00474 {
00475     CHECK_HANDLE(handle, return -1);
00476     handle->usesyslog = usesyslog;
00477     return 0;
00478 }
00479 
00480 int SYMEXPORT alpm_option_add_noupgrade(alpm_handle_t *handle, const char *pkg)
00481 {
00482     CHECK_HANDLE(handle, return -1);
00483     handle->noupgrade = alpm_list_add(handle->noupgrade, strdup(pkg));
00484     return 0;
00485 }
00486 
00487 int SYMEXPORT alpm_option_set_noupgrades(alpm_handle_t *handle, alpm_list_t *noupgrade)
00488 {
00489     CHECK_HANDLE(handle, return -1);
00490     if(handle->noupgrade) FREELIST(handle->noupgrade);
00491     handle->noupgrade = alpm_list_strdup(noupgrade);
00492     return 0;
00493 }
00494 
00495 int SYMEXPORT alpm_option_remove_noupgrade(alpm_handle_t *handle, const char *pkg)
00496 {
00497     char *vdata = NULL;
00498     CHECK_HANDLE(handle, return -1);
00499     handle->noupgrade = alpm_list_remove_str(handle->noupgrade, pkg, &vdata);
00500     if(vdata != NULL) {
00501         FREE(vdata);
00502         return 1;
00503     }
00504     return 0;
00505 }
00506 
00507 int SYMEXPORT alpm_option_add_noextract(alpm_handle_t *handle, const char *pkg)
00508 {
00509     CHECK_HANDLE(handle, return -1);
00510     handle->noextract = alpm_list_add(handle->noextract, strdup(pkg));
00511     return 0;
00512 }
00513 
00514 int SYMEXPORT alpm_option_set_noextracts(alpm_handle_t *handle, alpm_list_t *noextract)
00515 {
00516     CHECK_HANDLE(handle, return -1);
00517     if(handle->noextract) FREELIST(handle->noextract);
00518     handle->noextract = alpm_list_strdup(noextract);
00519     return 0;
00520 }
00521 
00522 int SYMEXPORT alpm_option_remove_noextract(alpm_handle_t *handle, const char *pkg)
00523 {
00524     char *vdata = NULL;
00525     CHECK_HANDLE(handle, return -1);
00526     handle->noextract = alpm_list_remove_str(handle->noextract, pkg, &vdata);
00527     if(vdata != NULL) {
00528         FREE(vdata);
00529         return 1;
00530     }
00531     return 0;
00532 }
00533 
00534 int SYMEXPORT alpm_option_add_ignorepkg(alpm_handle_t *handle, const char *pkg)
00535 {
00536     CHECK_HANDLE(handle, return -1);
00537     handle->ignorepkg = alpm_list_add(handle->ignorepkg, strdup(pkg));
00538     return 0;
00539 }
00540 
00541 int SYMEXPORT alpm_option_set_ignorepkgs(alpm_handle_t *handle, alpm_list_t *ignorepkgs)
00542 {
00543     CHECK_HANDLE(handle, return -1);
00544     if(handle->ignorepkg) FREELIST(handle->ignorepkg);
00545     handle->ignorepkg = alpm_list_strdup(ignorepkgs);
00546     return 0;
00547 }
00548 
00549 int SYMEXPORT alpm_option_remove_ignorepkg(alpm_handle_t *handle, const char *pkg)
00550 {
00551     char *vdata = NULL;
00552     CHECK_HANDLE(handle, return -1);
00553     handle->ignorepkg = alpm_list_remove_str(handle->ignorepkg, pkg, &vdata);
00554     if(vdata != NULL) {
00555         FREE(vdata);
00556         return 1;
00557     }
00558     return 0;
00559 }
00560 
00561 int SYMEXPORT alpm_option_add_ignoregroup(alpm_handle_t *handle, const char *grp)
00562 {
00563     CHECK_HANDLE(handle, return -1);
00564     handle->ignoregroup = alpm_list_add(handle->ignoregroup, strdup(grp));
00565     return 0;
00566 }
00567 
00568 int SYMEXPORT alpm_option_set_ignoregroups(alpm_handle_t *handle, alpm_list_t *ignoregrps)
00569 {
00570     CHECK_HANDLE(handle, return -1);
00571     if(handle->ignoregroup) FREELIST(handle->ignoregroup);
00572     handle->ignoregroup = alpm_list_strdup(ignoregrps);
00573     return 0;
00574 }
00575 
00576 int SYMEXPORT alpm_option_remove_ignoregroup(alpm_handle_t *handle, const char *grp)
00577 {
00578     char *vdata = NULL;
00579     CHECK_HANDLE(handle, return -1);
00580     handle->ignoregroup = alpm_list_remove_str(handle->ignoregroup, grp, &vdata);
00581     if(vdata != NULL) {
00582         FREE(vdata);
00583         return 1;
00584     }
00585     return 0;
00586 }
00587 
00588 int SYMEXPORT alpm_option_set_arch(alpm_handle_t *handle, const char *arch)
00589 {
00590     CHECK_HANDLE(handle, return -1);
00591     if(handle->arch) FREE(handle->arch);
00592     if(arch) {
00593         handle->arch = strdup(arch);
00594     } else {
00595         handle->arch = NULL;
00596     }
00597     return 0;
00598 }
00599 
00600 int SYMEXPORT alpm_option_set_usedelta(alpm_handle_t *handle, int usedelta)
00601 {
00602     CHECK_HANDLE(handle, return -1);
00603     handle->usedelta = usedelta;
00604     return 0;
00605 }
00606 
00607 int SYMEXPORT alpm_option_set_checkspace(alpm_handle_t *handle, int checkspace)
00608 {
00609     CHECK_HANDLE(handle, return -1);
00610     handle->checkspace = checkspace;
00611     return 0;
00612 }
00613 
00614 int SYMEXPORT alpm_option_set_default_siglevel(alpm_handle_t *handle,
00615         alpm_siglevel_t level)
00616 {
00617     CHECK_HANDLE(handle, return -1);
00618 #ifdef HAVE_LIBGPGME
00619     handle->siglevel = level;
00620 #else
00621     if(level != 0 && level != ALPM_SIG_USE_DEFAULT) {
00622         RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1);
00623     }
00624 #endif
00625     return 0;
00626 }
00627 
00628 alpm_siglevel_t SYMEXPORT alpm_option_get_default_siglevel(alpm_handle_t *handle)
00629 {
00630     CHECK_HANDLE(handle, return -1);
00631     return handle->siglevel;
00632 }
00633 
00634 /* vim: set ts=2 sw=2 noet: */