/* -M (--maintainer) search. */ int powaur_maint(alpm_list_t *targets) { if (!targets) { pw_printf(PW_LOG_ERROR, "argument needed for -M\n"); return -1; } else if (alpm_list_count(targets) > 1) { pw_printf(PW_LOG_ERROR, "-M only takes 1 argument\n"); return -1; } int ret; size_t listsz; alpm_list_t *i, *results; struct aurpkg_t *pkg; CURL *curl; curl = curl_easy_new(); if (!curl) { return error(PW_ERR_CURL_INIT); } /* Clear pwerrno */ CLEAR_ERRNO(); results = query_aur(curl, targets->data, AUR_QUERY_MSEARCH); if (pwerrno != PW_ERR_OK) { ret = -1; goto cleanup; } else if (!results) { printf("No packages found.\n"); ret = -1; goto cleanup; } /* Sort by alphabetical order */ listsz = alpm_list_count(results); results = alpm_list_msort(results, listsz, aurpkg_name_cmp); if (config->sort_votes) { results = alpm_list_msort(results, listsz, aurpkg_vote_cmp); } for (i = results; i; i = i->next) { pkg = i->data; printf("%saur/%s%s%s %s%s %s(%d)%s\n", color.bmag, color.nocolor, color.bold, pkg->name, color.bgreen, pkg->version, color.byellow, pkg->votes, color.nocolor); printf("%s%s\n", TAB, pkg->desc); } cleanup: alpm_list_free_inner(results, (alpm_list_fn_free) aurpkg_free); alpm_list_free(results); curl_easy_cleanup(curl); return 0; }
/* Generates the list of packages we are going to install from the AUR, in * topological order. * * @param hashdb hash database * @param graph graph of package strings * @param topost stack containing topological order of packages */ static alpm_list_t *topo_get_targets(struct pw_hashdb *hashdb, struct graph *graph, struct stack *topost) { int curVertex, cnt = 0; const char *pkgname; enum pkgfrom_t *from = NULL; struct pkgpair pkgpair; alpm_list_t *final_targets = NULL; pw_printf(PW_LOG_VDEBUG, "\n%sDependency graph:\n%s", color.bold, color.nocolor); while (!stack_empty(topost)) { stack_pop(topost, &curVertex); pkgname = graph_get_vertex_data(graph, curVertex); from = hashmap_search(hashdb->pkg_from, (void *) pkgname); if (!from) { alpm_list_free(final_targets); return NULL; } if (cnt++) { pw_printf(PW_LOG_VDEBUG, " -> "); } switch (*from) { case PKG_FROM_LOCAL: pw_printf(PW_LOG_VDEBUG, "%s%s (installed)%s", color.bgreen, pkgname, color.nocolor); break; case PKG_FROM_SYNC: pw_printf(PW_LOG_VDEBUG, "%s%s (found in sync)%s", color.bblue, pkgname, color.nocolor); break; case PKG_FROM_AUR: /* Magic happens here */ if (hash_search(hashdb->aur_outdated, (void *) pkgname)) { pw_printf(PW_LOG_VDEBUG, "%s%s (AUR target)%s", color.bred, pkgname, color.nocolor); final_targets = alpm_list_add(final_targets, (void *) pkgname); } else { pkgpair.pkgname = pkgname; if (hash_search(hashdb->aur, &pkgpair)) { pw_printf(PW_LOG_VDEBUG, "%s%s (installed AUR)%s", color.bblue, pkgname, color.nocolor); } else { /* New AUR package */ pw_printf(PW_LOG_VDEBUG, "%s%s (AUR dep)%s", color.bmag, pkgname, color.nocolor); final_targets = alpm_list_add(final_targets, (void *) pkgname); } } break; } } pw_printf(PW_LOG_VDEBUG, "\n"); print_immediate_deps(hashdb); return final_targets; }
/* Prints list of char *, one on each line with proper indentation */ void indent_print(enum pwloglevel_t lvl, alpm_list_t *list, size_t indent) { alpm_list_t *i; int k; size_t prefix_len = 0; switch (lvl) { case PW_LOG_NORM: prefix_len = 0; break; case PW_LOG_INFO: prefix_len = 4; break; case PW_LOG_WARNING: prefix_len = 9; break; case PW_LOG_ERROR: prefix_len = 7; break; case PW_LOG_DEBUG: prefix_len = 7; break; } indent += prefix_len; for (i = list; i; i = i->next) { pw_printf(lvl, "%*s%s\n", indent, "", i->data); } }
static void parse_pmoption_keyval(int *flag, int *flag_com, char *line, const char *key, char **env_conf, int comment) { static const char *keyval_sep = "="; if ((comment && (*flag || *flag_com)) || (!comment && *flag)) { return; } strsep(&line, keyval_sep); line = strtrim(line); if (!strlen(line)) { return; } /* Set global */ if (*env_conf) { free(*env_conf); } *env_conf = strdup(line); pw_printf(PW_LOG_DEBUG, "%s%sDefault %s = %s\n", comstrs.tab, comstrs.tab, key, *env_conf); if (comment) { *flag_com = 1; } else { *flag = 1; } }
/* Obtain deps, optional deps, conflicts, replaces from fp */ void parse_pkgbuild(struct aurpkg_t *pkg, FILE *fp) { char buf[PATH_MAX]; char *line; char *token; char *saveptr; while (line = fgets(buf, PATH_MAX, fp)) { line = strtrim(line); if (line == NULL || strlen(line) == 0) { continue; } if (!strncmp(line, "depends", 7)) { pw_printf(PW_LOG_DEBUG, "Parsing PKGBUILD depends\n"); PARSE_BASH_ARRAY_PREAMBLE(line); parse_bash_array(&(pkg->depends), fp, buf, line, 1); } else if (!strncmp(line, "provides", 8)) { pw_printf(PW_LOG_DEBUG, "Parsing PKGBUILD provides\n"); PARSE_BASH_ARRAY_PREAMBLE(line); parse_bash_array(&(pkg->provides), fp, buf, line, 1); } else if (!strncmp(line, "conflicts", 9)) { pw_printf(PW_LOG_DEBUG, "Parsing PKGBUILD conflicts\n"); PARSE_BASH_ARRAY_PREAMBLE(line); parse_bash_array(&(pkg->conflicts), fp, buf, line, 1); } else if (!strncmp(line, "replaces", 8)) { pw_printf(PW_LOG_DEBUG, "Parsing PKGBUILD replaces\n"); PARSE_BASH_ARRAY_PREAMBLE(line); parse_bash_array(&(pkg->replaces), fp, buf, line, 1); } else if (!strncmp(line, "arch", 4)) { pw_printf(PW_LOG_DEBUG, "Parsing PKGBUILD architectures\n"); PARSE_BASH_ARRAY_PREAMBLE(line); parse_bash_array(&(pkg->arch), fp, buf, line, 1); } else if (!strncmp(line, "build", 5)) { break; } } }
int powaur_crawl(alpm_list_t *targets) { int ret = 0; char cwd[PATH_MAX]; if (!getcwd(cwd, PATH_MAX)) { return error(PW_ERR_GETCWD); } if (chdir(powaur_dir)) { return error(PW_ERR_CHDIR, powaur_dir); } struct pw_hashdb *hashdb = build_hashdb(); if (!hashdb) { pw_fprintf(PW_LOG_ERROR, stderr, "Unable to build hash database!\n"); ret = -1; } alpm_list_t *i, *target_pkgs; struct graph *graph; struct stack *topost = stack_new(sizeof(int)); int have_cycles; for (i = targets; i; i = i->next) { stack_reset(topost); graph = NULL; target_pkgs = alpm_list_add(NULL, i->data); build_dep_graph(&graph, hashdb, target_pkgs, RESOLVE_THOROUGH); if (have_cycles) { printf("Cyclic dependencies for package \"%s\"\n", i->data); } graph_toposort(graph, topost); if (stack_empty(topost)) { printf("Package \"%s\" has no dependencies.\n", i->data); } else { printf("\n"); pw_printf(PW_LOG_INFO, "\"%s\" topological order: ", i->data); print_topo_order(graph, topost); } graph_free(graph); alpm_list_free(target_pkgs); } stack_free(topost); hashdb_free(hashdb); if (chdir(cwd)) { return error(PW_ERR_RESTORECWD); } return ret; }
/* Prints immediate dependencies */ static void print_immediate_deps(struct pw_hashdb *hashdb) { alpm_list_t *i; enum pkgfrom_t *from = NULL; if (!hashdb->immediate_deps) { pw_printf(PW_LOG_NORM, "\nNo dependencies found.\n\n"); return; } printf("\n"); pw_printf(PW_LOG_INFO, "Dependencies:\n"); for (i = hashdb->immediate_deps; i; i = i->next) { from = hashmap_search(hashdb->pkg_from, i->data); switch (*from) { case PKG_FROM_LOCAL: pw_printf(PW_LOG_NORM, "%s%s (installed)%s\n", color.bgreen, i->data, color.nocolor); break; case PKG_FROM_SYNC: pw_printf(PW_LOG_NORM, "%s%s (found in sync)%s\n", color.bblue, i->data, color.nocolor); break; case PKG_FROM_AUR: /* Magic happens here */ if (hash_search(hashdb->aur_outdated, (void *) i->data)) { pw_printf(PW_LOG_NORM, "%s%s (AUR target)%s\n", color.bred, i->data, color.nocolor); } else { struct pkgpair pkgpair; pkgpair.pkgname = i->data; if (hash_search(hashdb->aur, &pkgpair)) { pw_printf(PW_LOG_NORM, "%s%s (installed AUR)%s\n", color.bblue, i->data, color.nocolor); } else { /* New AUR package */ pw_printf(PW_LOG_NORM, "%s%s (AUR dep)%s\n", color.bmag, i->data, color.nocolor); } } break; default: /* Shouldn't happen */ pw_printf(PW_LOG_NORM, "Unknown\n"); break; } } printf("\n"); }
/* Installs packages from the AUR * Assumes we are already in directory with all the relevant PKGBUILDS dled * * @param hashdb hash database * @param targets targets to be installed, in topo order */ static int topo_install(struct pw_hashdb *hashdb, alpm_list_t *targets) { alpm_list_t *i; int ret; pw_printf(PW_LOG_INFO, "Targets (%d):\n", alpm_list_count(targets)); print_list_color(targets, color.bmag); for (i = targets; i; i = i->next) { ret = install_single_package(i->data); if (ret == -2) { return ret; } } return 0; }
/* @param reload set to > 0 if reloading libalpm so that cachedirs can be * reinitialized. */ static int setup_pacman_environment(int reload) { enum _alpm_errno_t err; alpm_list_t *i; if (reload) { pw_printf(PW_LOG_DEBUG, "Reloading pacman configuration\n"); pacman_cachedirs = NULL; } if (parse_pmconfig()) { /* Free cachedirs */ FREELIST(pacman_cachedirs); return error(PW_ERR_PM_CONF_PARSE); } if (!pacman_rootdir) { pacman_rootdir = xstrdup(PACMAN_DEF_ROOTDIR); } if (!pacman_dbpath) { pacman_dbpath = xstrdup(PACMAN_DEF_DBPATH); } if (!pacman_cachedirs) { pacman_cachedirs = alpm_list_add(pacman_cachedirs, xstrdup(PACMAN_DEF_CACHEDIR)); } alpm_option_set_cachedirs(config->handle, pacman_cachedirs); config->handle = alpm_initialize(pacman_rootdir, pacman_dbpath, &err); if (!config->handle) { return error(PW_ERR_INIT_ALPM_HANDLE); } /* Register sync dbs */ for (i = pacman_syncdbs; i; i = i->next) { if (!alpm_db_register_sync(config->handle, (const char *) i->data, ALPM_SIG_USE_DEFAULT)) { return error(PW_ERR_INIT_ALPM_REGISTER_SYNC); } } return 0; }
/* fp is guaranteed to be non-NULL. * returns 0 on success, -1 on failure, 1 if not all options specified */ int parse_powaur_config(FILE *fp) { int ret, parsed; char buf[PATH_MAX]; char *line, *key, *val; size_t len; ret = parsed = 0; while (line = fgets(buf, PATH_MAX, fp)) { line = strtrim(line); len = strlen(line); /* Ignore empty lines and comments */ if (!len || line[0] == '#') { continue; } val = strchr(line, '='); if (!val) { continue; } *val = 0; ++val; key = strtrim(line); val = strtrim(val); if (!strcmp(key, "Editor")) { if (powaur_editor) { pw_fprintf(PW_LOG_ERROR, stderr, "%s%sRepeated Editor option!\n", comstrs.tab, comstrs.tab); ret = -1; goto cleanup; } powaur_editor = strdup(val); if (!powaur_editor) { ret = -1; goto cleanup; } ++parsed; pw_printf(PW_LOG_DEBUG, "%s%sParsed Editor = %s\n", comstrs.tab, comstrs.tab, powaur_editor); } else if (!strcmp(key, "TmpDir")) { if (powaur_dir) { pw_fprintf(PW_LOG_ERROR, stderr, "%s%sRepeated TmpDir option!\n", comstrs.tab, comstrs.tab); ret = -1; goto cleanup; } powaur_dir = strdup(val); if (!powaur_dir) { ret = -1; goto cleanup; } ++parsed; pw_printf(PW_LOG_DEBUG, "%s%sParsed TmpDir = %s\n", comstrs.tab, comstrs.tab, powaur_dir); } } cleanup: if (ret) { if (!parsed) { free(powaur_editor); free(powaur_dir); powaur_editor = powaur_dir = NULL; return -1; } else { return 1; } } return 0; }
/* Parse /etc/pacman.conf * We are hoping that the user does not remove the commented lines * under the [options] section. * * If there is insufficient information, we will fallback to the defaults. */ int parse_pmconfig(void) { int ret = 0; int len; FILE *fp; char buf[PATH_MAX]; char *line; int in_options = 0; int parsed_options = 0; fp = fopen(comstrs.pmconf, "r"); ASSERT(fp != NULL, RET_ERR(PW_ERR_PM_CONF_OPEN, -1)); pw_printf(PW_LOG_DEBUG, "%s : Parsing %s\n", __func__, comstrs.pmconf); while (line = fgets(buf, PATH_MAX, fp)) { line = strtrim(line); len = strlen(line); /* Ignore empty lines / Comments */ if (len == 0 || (!in_options && line[0] == '#')) { continue; } /* Entering a section */ if (line[0] == '[' && line[len-1] == ']') { line[len-1] = 0; ++line; line = strtrim(line); /* Get new length of line */ len = strlen(line); if (!strcmp(line, comstrs.opt)) { if (parsed_options) { pw_printf(PW_LOG_ERROR, "%sRepeated %s section in %s\n", comstrs.tab, comstrs.opt, comstrs.pmconf); ret = -1; goto cleanup; } pw_printf(PW_LOG_DEBUG, "%sParsing [%s] section of %s\n", comstrs.tab, comstrs.opt, comstrs.pmconf); parsed_options = 1; in_options = 1; continue; } else if (len == 0) { pw_printf(PW_LOG_DEBUG, "%sEmpty section in %s\n", comstrs.tab, comstrs.pmconf); ret = -1; goto cleanup; } else { /* Must be a repository * We just add the repository for now */ in_options = 0; pw_printf(PW_LOG_DEBUG, "%sParsing Repo [%s]\n", comstrs.tab, line); if (!alpm_db_register_sync(line)) { pw_printf(PW_LOG_ERROR, "%sFailed to register %s db\n", comstrs.tab, line); goto cleanup; } pw_printf(PW_LOG_DEBUG, "%sRegistering sync database '%s'\n", comstrs.tab, line); } } else if (in_options) { if (ret = _parse_pmoption(line)) { break; } continue; } } cleanup: fclose(fp); return ret; }
/* Line is assumed to have been strtrim'ed */ static int _parse_pmoption(char *line) { static int rootdir_com, rootdir; static int dbpath_com, dbpath; static int cachedir_com, cachedir; int len; if (line[0] == '#') { /* Look for default settings first. */ ++line; line = strtrim(line); len = strlen(line); if (len == 0) { return 0; } if (!strncmp(line, comstrs.rootdir, 7)) { parse_pmoption_keyval(&rootdir, &rootdir_com, line, comstrs.rootdir, &pacman_rootdir, 1); } else if (!strncmp(line, comstrs.dbpath, 6)) { parse_pmoption_keyval(&dbpath, &dbpath_com, line, comstrs.dbpath, &pacman_dbpath, 1); } else if (!strncmp(line, comstrs.cachedir, 8)) { parse_pmoption_repeat(&cachedir, &cachedir_com, line, comstrs.cachedir, setrepeat_cachedir, free_cachedir, (void **) &pacman_cachedirs, 1); pw_printf(PW_LOG_DEBUG, "%s%sCachedir default:\n", comstrs.tab, comstrs.tab); indent_print(PW_LOG_DEBUG, pacman_cachedirs, 12); } } else { /* Non-commented, ie. official stuff */ if (!strncmp(line, comstrs.rootdir, 7)) { if (rootdir) { pw_printf(PW_LOG_ERROR, "%s%sRepeated %s\n", comstrs.tab, comstrs.tab, comstrs.rootdir); return -1; } parse_pmoption_keyval(&rootdir, &rootdir_com, line, comstrs.rootdir, &pacman_rootdir, 0); } else if (!strncmp(line, comstrs.dbpath, 6)) { if (dbpath) { pw_printf(PW_LOG_ERROR, "%s%sRepeated %s\n", comstrs.tab, comstrs.tab, comstrs.dbpath); return -1; } parse_pmoption_keyval(&dbpath, &dbpath_com, line, comstrs.dbpath, &pacman_dbpath, 0); } else if (!strncmp(line, comstrs.cachedir, 8)) { if (cachedir) { pw_printf(PW_LOG_ERROR, "%s%sRepeated %s\n", comstrs.tab, comstrs.tab, comstrs.cachedir); return -1; } parse_pmoption_repeat(&cachedir, &cachedir_com, line, comstrs.cachedir, setrepeat_cachedir, free_cachedir, (void **) &pacman_cachedirs, 0); pw_printf(PW_LOG_DEBUG, "%s%sCachedir final:\n", comstrs.tab, comstrs.tab); indent_print(PW_LOG_DEBUG, pacman_cachedirs, 12); } } return 0; }
/* -Su, checks AUR packages */ static int sync_upgrade(CURL *curl, alpm_list_t *targets) { int ret = 0; int cnt = 0; int upgrade_all; struct pkgpair pkgpair; struct pw_hashdb *hashdb = build_hashdb(); if (!hashdb) { pw_fprintf(PW_LOG_ERROR, stderr, "Failed to build hash database."); return -1; } /* Make sure that packages are from AUR */ alpm_list_t *i, *new_targs = NULL; for (i = targets; i; i = i->next) { pkgpair.pkgname = i->data; if (!hash_search(hashdb->aur, &pkgpair)) { if (cnt++) { printf(", "); } pw_printf(PW_LOG_NORM, "%s", i->data); } else { new_targs = alpm_list_add(new_targs, i->data); } } if (cnt > 1) { printf(" are not AUR packages and will not be checked.\n"); } else if (cnt == 1) { printf(" is not an AUR package and will not be checked.\n"); } alpm_list_t *outdated_pkgs = NULL; if (!targets) { /* Check all AUR packages */ outdated_pkgs = get_outdated_pkgs(curl, hashdb, NULL); } else { if (!new_targs) { goto cleanup; } outdated_pkgs = get_outdated_pkgs(curl, hashdb, new_targs); } if (!outdated_pkgs) { pw_printf(PW_LOG_INFO, "All AUR packages are up to date.\n"); goto cleanup; } printf("\n"); pw_printf(PW_LOG_INFO, "Targets:\n"); print_aurpkg_list(outdated_pkgs); printf("\n"); /* --check, don't upgrade */ if (config->op_s_check) { goto cleanup; } upgrade_all = config->noconfirm || yesno("Do you wish to upgrade the above packages?"); if (upgrade_all) { /* Experimental */ alpm_list_t *final_targets = NULL; struct aurpkg_t *aurpkg; for (i = outdated_pkgs; i; i = i->next) { aurpkg = i->data; final_targets = alpm_list_add(final_targets, aurpkg->name); } ret = upgrade_pkgs(final_targets, hashdb); alpm_list_free(final_targets); } cleanup: alpm_list_free_inner(outdated_pkgs, (alpm_list_fn_free) aurpkg_free); alpm_list_free(outdated_pkgs); alpm_list_free(new_targs); hashdb_free(hashdb); return ret; }
/* Returns a list of outdated AUR packages among targets or all AUR packages. * The list and the packages are to be freed by the caller. * * @param curl curl easy handle * @param targets list of strings (package names) that are _definitely_ AUR packages */ static alpm_list_t *get_outdated_pkgs(CURL *curl, struct pw_hashdb *hashdb, alpm_list_t *targets) { alpm_list_t *i; alpm_list_t *outdated_pkgs = NULL; alpm_list_t *pkglist, *targs; struct pkgpair pkgpair; struct pkgpair *pkgpair_ptr; struct aurpkg_t *aurpkg; const char *pkgname, *pkgver; if (targets) { targs = targets; } else { targs = NULL; alpm_list_t *tmp_targs = hash_to_list(hashdb->aur); for (i = tmp_targs; i; i = i->next) { pkgpair_ptr = i->data; targs = alpm_list_add(targs, (void *) pkgpair_ptr->pkgname); } alpm_list_free(tmp_targs); } for (i = targs; i; i = i->next) { pkglist = query_aur(curl, i->data, AUR_QUERY_INFO); if (!pkglist) { continue; } pkgpair.pkgname = i->data; pkgpair_ptr = hash_search(hashdb->aur, &pkgpair); if (!pkgpair_ptr) { /* Shouldn't happen */ pw_fprintf(PW_LOG_ERROR, stderr, "Unable to find AUR package \"%s\"" "in hashdb!\n", i->data); } aurpkg = pkglist->data; pkgver = alpm_pkg_get_version(pkgpair_ptr->pkg); pkgname = i->data; if (alpm_pkg_vercmp(aurpkg->version, pkgver) > 0) { /* Just show outdated package for now */ pw_printf(PW_LOG_INFO, "%s %s is outdated, %s%s%s%s is available\n", pkgname, pkgver, color.bred, aurpkg->version, color.nocolor, color.bold); /* Add to upgrade list */ outdated_pkgs = alpm_list_add(outdated_pkgs, aurpkg); pkglist->data = NULL; } else if (config->verbose) { pw_printf(PW_LOG_INFO, "%s %s is up to date.\n", pkgname, pkgver); } alpm_list_free_inner(pkglist, (alpm_list_fn_free) aurpkg_free); alpm_list_free(pkglist); } if (!targets) { alpm_list_free(targs); } return outdated_pkgs; }
int powaur_backup(alpm_list_t *targets) { int ret = 0; char localdb[PATH_MAX]; struct archive *a; struct archive_entry *entry; struct stat st; char cwd[PATH_MAX]; char backup_dest[PATH_MAX]; char backup[MINI_BUFSZ]; time_t time_now; struct tm tm_st; if (targets != NULL && alpm_list_count(targets) != 1) { pw_fprintf(PW_LOG_ERROR, stderr, "-B only takes 1 argument.\n"); return -1; } a = archive_write_new(); if (!a) { return error(PW_ERR_ARCHIVE_CREATE); } archive_write_set_compression_bzip2(a); archive_write_set_format_pax_restricted(a); /* Filename = pacman-YYYY-MM-DD_HHhMM.tar.bz2 */ time(&time_now); localtime_r(&time_now, &tm_st); strftime(backup, MINI_BUFSZ, "pacman-%Y-%m-%d_%Hh%M.tar.bz2", &tm_st); if (!getcwd(cwd, PATH_MAX)) { error(PW_ERR_GETCWD); ret = -1; goto cleanup; } /* Get full path */ if (targets) { snprintf(backup_dest, PATH_MAX, "%s/%s", targets->data, backup); } else { snprintf(backup_dest, PATH_MAX, "%s/%s", cwd, backup); } if (archive_write_open_filename(a, backup_dest) != ARCHIVE_OK) { PW_SETERRNO(PW_ERR_ARCHIVE_OPEN); ret = -1; goto cleanup; } if (ret = chdir(pacman_dbpath)) { error(PW_ERR_CHDIR, pacman_dbpath); goto restore_cwd; } /* Create entry for the current directory. */ entry = archive_entry_new(); if (!entry) { error(PW_ERR_ARCHIVE_ENTRY); goto restore_cwd; } snprintf(localdb, PATH_MAX, "%s", "local"); if (ret = stat(localdb, &st)) { error(PW_ERR_STAT, localdb); goto free_entry; } archive_entry_set_pathname(entry, localdb); archive_entry_copy_stat(entry, &st); archive_write_header(a, entry); pw_printf(PW_LOG_INFO, "Saving pacman database in %s\n", backup_dest); ret = write_dir_archive(localdb, a); if (!ret) { pw_printf(PW_LOG_INFO, "Pacman database successfully saved in %s\n", backup_dest); } else { pw_fprintf(PW_LOG_ERROR, stderr, "Pacman database not saved.\n"); } free_entry: archive_entry_free(entry); restore_cwd: if (chdir(cwd)) { PW_SETERRNO(PW_ERR_RESTORECWD); ret = -1; } cleanup: archive_write_finish(a); return ret; }
/* Lists detailed information about targets */ static int sync_info(CURL *curl, alpm_list_t *targets) { int found, ret, pkgcount; alpm_list_t *i, *j, *results; alpm_list_t *free_list = NULL; alpm_list_t *syncdbs = alpm_option_get_syncdbs(config->handle); alpm_pkg_t *spkg; char cwd[PATH_MAX]; char filename[PATH_MAX]; char url[PATH_MAX]; FILE *fp = NULL; int fd; struct aurpkg_t *pkg; if (!getcwd(cwd, PATH_MAX)) { return error(PW_ERR_GETCWD); } if (chdir(powaur_dir)) { return error(PW_ERR_CHDIR, powaur_dir); } found = ret = pkgcount = 0; for (i = targets; i; i = i->next, ++pkgcount) { /* Search sync dbs first */ spkg = search_syncdbs(syncdbs, i->data); if (spkg) { if (found++){ printf("\n"); } pacman_pkgdump(spkg, PKG_FROM_SYNC); spkg = NULL; continue; } results = query_aur(curl, i->data, AUR_QUERY_INFO); if (alpm_list_count(results) != 1) { if (pkgcount > 0) { printf("\n"); } pw_printf(PW_LOG_ERROR, "package %s not found\n", i->data); goto garbage_collect; } snprintf(filename, PATH_MAX, "%s.PKGBUILDXXXXXX", i->data); fd = mkstemp(filename); if (fd < 0) { error(PW_ERR_FOPEN, filename); goto garbage_collect; } fp = fdopen(fd, "w+"); if (!fp) { printf("NO\n"); error(PW_ERR_FOPEN, filename); goto garbage_collect; } snprintf(url, PATH_MAX, AUR_PKGBUILD_URL, i->data); /* Download the PKGBUILD and parse it */ ret = download_single_file(curl, url, fp); if (ret) { goto destroy_remnants; } /* Parse PKGBUILD and get detailed info */ fseek(fp, 0L, SEEK_SET); pkg = results->data; parse_pkgbuild(pkg, fp); if (found++) { printf("\n"); } printf("%s%s %saur%s\n", color.bold, REPO, color.bmag, color.nocolor); printf("%s%s %s%s\n", color.bold, NAME, pkg->name, color.nocolor); printf("%s%s %s%s%s\n", color.bold, VERSION, color.bgreen, pkg->version, color.nocolor); printf("%s%s %s%s%s\n", color.bold, URL, color.bcyan, pkg->url, color.nocolor); printf("%s%s%s ", color.bold, A_URL, color.bcyan); printf(AUR_PKG_URL, pkg->id); printf("%s\n", color.nocolor); printf("%s%s %s%s\n", color.bold, LICENSES, color.nocolor, pkg->license); printf("%s%s %s%d\n", color.bold, A_VOTES, color.nocolor, pkg->votes); printf("%s%s ", color.bold, A_OUTOFDATE); if (pkg->outofdate) { printf("%s%s", color.bred, "Yes"); } else { printf("%s%s", color.nocolor, "No"); } printf("%s\n", color.nocolor); print_list_prefix(pkg->provides, PROVIDES); print_list_prefix(pkg->depends, DEPS); print_list_prefix(pkg->optdepends, OPTDEPS); print_list_prefix(pkg->conflicts, CONFLICTS); print_list_prefix(pkg->replaces, REPLACES); print_list_prefix(pkg->arch, ARCH); printf("%s%s%s %s\n", color.bold, DESC, color.nocolor, pkg->desc); destroy_remnants: fclose(fp); fp = NULL; unlink(filename); garbage_collect: free_list = alpm_list_add(free_list, results); } cleanup: for (i = free_list; i; i = i->next) { alpm_list_free_inner(i->data, (alpm_list_fn_free) aurpkg_free); alpm_list_free(i->data); } alpm_list_free(free_list); if (chdir(cwd)) { return error(PW_ERR_RESTORECWD); } return found ? 0 : -1; }
static int setup_powaur_config(void) { /* Check the following places for logfile: * $XDG_CONFIG_HOME * $HOME * * Then fallback to default settings */ int ret = -1; FILE *fp = NULL; char *dir; char buf[PATH_MAX]; struct stat st; pw_printf(PW_LOG_DEBUG, "%s: Setting up powaur configuration\n", __func__); dir = getenv("XDG_CONFIG_HOME"); if (dir) { snprintf(buf, PATH_MAX, "%s/%s", dir, PW_CONF); if (!stat(buf, &st)) { fp = fopen(buf, "r"); if (!fp) { goto check_home; } pw_printf(PW_LOG_DEBUG, "%sParsing %s\n", TAB, buf); parse_powaur_config(fp); fclose(fp); goto cleanup; } } check_home: /* Check $HOME */ dir = getenv("HOME"); if (dir) { snprintf(buf, PATH_MAX, "%s/.config/%s", dir, PW_CONF); if (!stat(buf, &st)) { fp = fopen(buf, "r"); if (!fp) { goto cleanup; } pw_printf(PW_LOG_DEBUG, "%sParsing %s\n", TAB, buf); parse_powaur_config(fp); fclose(fp); } } cleanup: /* Use default settings for unspecified options */ if (!powaur_dir) { uid_t myuid = geteuid(); struct passwd *passwd_struct = getpwuid(myuid); if (!passwd_struct) { powaur_dir = xstrdup(PW_DEF_DIR); } else { snprintf(buf, PATH_MAX, "%s-%s", PW_DEF_DIR, passwd_struct->pw_name); powaur_dir = xstrdup(buf); } pw_printf(PW_LOG_DEBUG, "%sFalling back to default directory %s\n", TAB, powaur_dir); } if (!powaur_editor) { powaur_editor = xstrdup(PW_DEF_EDITOR); pw_printf(PW_LOG_DEBUG, "%sFalling back to default editor %s\n", TAB, powaur_editor); } if (powaur_maxthreads <= 0 || powaur_maxthreads > PW_DEF_MAXTHREADS) { powaur_maxthreads = PW_DEF_MAXTHREADS; } config->maxthreads = powaur_maxthreads; pw_printf(PW_LOG_DEBUG, "%sMaximum no. of threads = %d\n", TAB, config->maxthreads); return 0; }
/* TODO: Return version string for >=, >, <, =. * TODO: provides, etc, ":" for optdepends * Refer to https://wiki.archlinux.org/index.php/Pkgbuild for details. */ static void parse_bash_array(alpm_list_t **list, FILE *fp, char *buf, char *line, int preserve_ver) { static const char *delim = " "; int len; int can_break = 0; char *token, *saveptr; char *tmpstr; /* Parse multi-line bash array */ for (; !feof(fp) && !can_break; line = fgets(buf, PATH_MAX, fp)) { line = strtrim(line); len = strlen(line); if (len == 0) { continue; } else if (line[len - 1] == ')') { can_break = 1; } for (token = strtok_r(line, delim, &saveptr), line = NULL; token; token = strtok_r(line, delim, &saveptr)) { token = strtrim(token); /* Remove quotes */ if (token[0] == '\'' || token[0] == '"') { ++token; } len = strlen(token); if (token[len-1] == '\'' || token[len-1] == '"') { token[len-1] = 0; --len; } if (len == 0) { continue; } else if (token[0] == ')') { can_break = 1; break; } else if (token[len-1] == ')') { can_break = 1; token[len-1] = 0; token = strtrim(token); if (token[len-2] == '\'' || token[len-2] == '"') { token[len-2] = 0; } } if (preserve_ver) { *list = alpm_list_add(*list, strdup(token)); } else { token = strtrim_ver(token); *list = alpm_list_add(*list, strdup(token)); } pw_printf(PW_LOG_DEBUG, "%sParsed \"%s\"\n", TAB, token); } } }