// Return -1 for error, 0 for entry not changed, 1 for entry changed (or new). static int entry_changed(struct sbuf *sb, struct manios *manios, struct asfd *chfd, struct sbuf **csb) { static int finished=0; static struct blk *blk=NULL; if(finished) return 1; if((*csb)->path.buf) { // Already have an entry. } else { // Need to read another. if(!blk && !(blk=blk_alloc())) return -1; switch(manio_read_with_blk(manios->current, *csb, blk, NULL)) { case 1: // Reached the end. sbuf_free(csb); blk_free(&blk); finished=1; return 1; case -1: return -1; } if(!(*csb)->path.buf) { logp("Should have a path at this point, but do not, in %s\n", __func__); return -1; } // Got an entry. } while(1) { switch(sbuf_pathcmp(*csb, sb)) { case 0: return found_in_current_manifest(*csb, sb, manios, &blk, chfd); case 1: return 1; case -1: // Behind - need to read more data from the old // manifest. switch(manio_read_with_blk(manios->current, *csb, blk, NULL)) { case 1: // Reached the end. sbuf_free(csb); blk_free(&blk); return 1; case -1: return -1; } // Got something, go back around the loop. } } return 0; }
int pkg_delete(struct pkg *pkg, struct pkgdb *db, int force) { struct pkg **rdeps; int i, ret; struct sbuf *rdep_msg; if (pkg == NULL) return (ERROR_BAD_ARG("pkg")); if (db == NULL) return (ERROR_BAD_ARG("db")); /* * Ensure that we have all the informations we need */ if ((ret = pkgdb_loadrdeps(db, pkg)) != EPKG_OK) return (ret); if ((ret = pkgdb_loadfiles(db, pkg)) != EPKG_OK) return (ret); if ((ret = pkgdb_loadscripts(db, pkg)) != EPKG_OK) return (ret); if ((ret = pkgdb_loadmtree(db, pkg)) != EPKG_OK) return (ret); rdeps = pkg_rdeps(pkg); if (rdeps[0] != NULL) { rdep_msg = sbuf_new_auto(); sbuf_printf(rdep_msg, "%s-%s is required by other packages:", pkg_get(pkg, PKG_NAME), pkg_get(pkg, PKG_VERSION)); for (i = 0;rdeps[i] != NULL; i++) { sbuf_cat(rdep_msg, " "); sbuf_printf(rdep_msg, "%s-%s", pkg_get(rdeps[i], PKG_NAME), pkg_get(rdeps[i], PKG_VERSION)); } if (!force) { sbuf_finish(rdep_msg); ret = pkg_error_set(EPKG_REQUIRED, "%s", sbuf_get(rdep_msg)); sbuf_free(rdep_msg); return ret; } sbuf_cat(rdep_msg, ", deleting anyway"); sbuf_finish(rdep_msg); fprintf(stderr, "%s\n", sbuf_get(rdep_msg)); sbuf_free(rdep_msg); } if ((ret = pkg_script_pre_deinstall(pkg)) != EPKG_OK) return (ret); if ((ret = pkg_delete_files(pkg, force)) != EPKG_OK) return (ret); if ((ret = pkg_script_post_deinstall(pkg)) != EPKG_OK) return (ret); return (pkgdb_unregister_pkg(db, pkg_get(pkg, PKG_ORIGIN))); }
static #endif int forward_past_entry(struct manio *manio, struct iobuf *target, enum protocol protocol, man_off_t **pos) { struct sbuf *sb=NULL; if(!(sb=sbuf_alloc(protocol))) goto error; man_off_t_free(pos); if(!(*pos=manio_tell(manio))) { logp("Could not manio_tell first pos in %s(): %s\n", __func__, strerror(errno)); goto error; } while(1) { sbuf_free_content(sb); switch(manio_read(manio, sb)) { case 0: break; case 1: logp("End of file in %s()\n", __func__); goto error; default: logp("Error in %s()\n", __func__); // Treat error in unchanged manio as not OK. goto error; } if(target->cmd==sb->path.cmd && !pathcmp(target->buf, sb->path.buf)) { man_off_t_free(pos); if(!(*pos=manio_tell(manio))) { logp("Could not get pos in %s(): %s\n", __func__, strerror(errno)); goto error; } sbuf_free(&sb); return 0; } } error: sbuf_free(&sb); man_off_t_free(pos); return -1; }
END_TEST static void do_test_check_browsedir_windows_blank(enum protocol protocol) { struct sbuf *mb; const char *browsedir; char *last_bd_match=NULL; fail_unless((mb=sbuf_alloc(protocol))!=NULL); browsedir=""; run_check_browsedir(browsedir, mb, CMD_FILE, "A:/aaa", &last_bd_match, "A:", 1, 1); run_check_browsedir(browsedir, mb, CMD_DIRECTORY, "C:/aaa", &last_bd_match, "C:", 1, 1); run_check_browsedir(browsedir, mb, CMD_FILE, "C:/aaa/file", &last_bd_match, "C:", 0, 1); run_check_browsedir(browsedir, mb, CMD_FILE, "C:/aaa/filx", &last_bd_match, "C:", 0, 1); run_check_browsedir(browsedir, mb, CMD_FILE, "D:/adf", &last_bd_match, "D:", 1, 1); sbuf_free(&mb); free_w(&last_bd_match); alloc_check(); }
// Used on resume, this just reads the phase1 file and sets up cntr. static int read_phase1(struct manio *p1manio, struct conf **cconfs) { int ret=-1; struct sbuf *p1b; enum protocol protocol=get_protocol(cconfs); struct cntr *cntr=get_cntr(cconfs); if(!(p1b=sbuf_alloc(protocol))) return -1; while(1) { sbuf_free_content(p1b); switch(manio_read(p1manio, p1b)) { case 0: break; case 1: ret=0; default: goto end; } cntr_add_phase1(cntr, p1b->path.cmd, 0); if(sbuf_is_estimatable(p1b)) cntr_add_val(cntr, CMD_BYTES_ESTIMATED, (uint64_t)p1b->statp.st_size); } end: sbuf_free(&p1b); return ret; }
static int do_backup_phase2_client(struct asfd *asfd, struct conf *conf, int resume) { int ret=-1; // For efficiency, open Windows files for the VSS data, and do not // close them until another time around the loop, when the actual // data is read. BFILE bfd; // Windows VSS headers tell us how much file // data to expect. size_t datalen=0; #ifdef HAVE_WIN32 binit(&bfd, 0, conf); #endif struct sbuf *sb=NULL; struct iobuf *rbuf=asfd->rbuf; if(!(sb=sbuf_alloc(conf))) goto end; if(!resume) { // Only do this bit if the server did not tell us to resume. if(asfd->write_str(asfd, CMD_GEN, "backupphase2") || asfd->read_expect(asfd, CMD_GEN, "ok")) goto end; } else if(conf->send_client_cntr) { // On resume, the server might update the client with cntr. if(cntr_recv(asfd, conf)) goto end; } while(1) { iobuf_free_content(rbuf); if(asfd->read(asfd)) goto end; else if(!rbuf->buf) continue; if(rbuf->cmd==CMD_GEN && !strcmp(rbuf->buf, "backupphase2end")) { if(asfd->write_str(asfd, CMD_GEN, "okbackupphase2end")) goto end; ret=0; break; } if(parse_rbuf(asfd, sb, &bfd, &datalen, conf)) goto end; } end: #ifdef HAVE_WIN32 // It is possible for a bfd to still be open. close_file_for_sendl(&bfd, NULL, asfd); #endif iobuf_free_content(rbuf); sbuf_free(sb); return ret; }
END_TEST START_TEST(test_check_browsedir_alloc_error) { char *path; size_t bdlen; struct sbuf *mb; const char *browsedir; char *last_bd_match=NULL; fail_unless((mb=sbuf_alloc(PROTO_1))!=NULL); browsedir=""; bdlen=0; fail_unless((path=strdup_w("aaa", __func__))!=NULL); iobuf_from_str(&mb->path, CMD_FILE, path); alloc_errors=1; fail_unless(check_browsedir( browsedir, mb, bdlen, &last_bd_match) ==-1); sbuf_free(&mb); free_w(&last_bd_match); alloc_check(); }
void pkg_free(struct pkg *pkg) { if (pkg == NULL) return; ucl_object_unref(pkg->fields); for (int i = 0; i < PKG_NUM_SCRIPTS; i++) sbuf_free(pkg->scripts[i]); pkg_list_free(pkg, PKG_DEPS); pkg_list_free(pkg, PKG_RDEPS); pkg_list_free(pkg, PKG_FILES); pkg_list_free(pkg, PKG_DIRS); pkg_list_free(pkg, PKG_OPTIONS); pkg_list_free(pkg, PKG_USERS); pkg_list_free(pkg, PKG_GROUPS); pkg_list_free(pkg, PKG_SHLIBS_REQUIRED); pkg_list_free(pkg, PKG_SHLIBS_PROVIDED); if (pkg->rootfd != -1) close(pkg->rootfd); free(pkg); }
static void get_wbuf_from_scan(struct iobuf *wbuf, struct slist *flist) { struct sbuf *sb=flist->head; if(!sb) return; if(!(sb->flags & SBUF_SENT_STAT)) { iobuf_copy(wbuf, &sb->attr); sb->flags |= SBUF_SENT_STAT; } else if(!(sb->flags & SBUF_SENT_PATH)) { iobuf_copy(wbuf, &sb->path); sb->flags |= SBUF_SENT_PATH; } else if(sb->link.buf && !(sb->flags & SBUF_SENT_LINK)) { iobuf_copy(wbuf, &sb->link); sb->flags |= SBUF_SENT_LINK; } else { flist->head=flist->head->next; sbuf_free(&sb); if(flist->head) { // Go ahead and get the next one from the list. get_wbuf_from_scan(wbuf, flist); } else { flist->tail=NULL; iobuf_from_str(wbuf, CMD_GEN, (char *)"scan_end"); } } }
END_TEST static void do_test_check_browsedir_null_or_blank(enum protocol protocol, const char *browsedir) { struct sbuf *mb; char *last_bd_match=NULL; fail_unless((mb=sbuf_alloc(protocol))!=NULL); run_check_browsedir(browsedir, mb, CMD_FILE, "aaa", &last_bd_match, "aaa", 1, 0); run_check_browsedir(browsedir, mb, CMD_DIRECTORY, "/", &last_bd_match, "/", 1, 1); run_check_browsedir(browsedir, mb, CMD_DIRECTORY, "/asdf", &last_bd_match, "/", 0, 1); run_check_browsedir(browsedir, mb, CMD_DIRECTORY, "/asdf/blah", &last_bd_match, "/", 0, 1); run_check_browsedir(browsedir, mb, CMD_FILE, "zzz", &last_bd_match, "zzz", 1, 0); run_check_browsedir(browsedir, mb, CMD_FILE, "zzzz//", &last_bd_match, "zzzz", 1, 1); sbuf_free(&mb); free_w(&last_bd_match); alloc_check(); }
/* Note that we use marked_message_internal to avoid resetting the alarm. */ void update_window_names (rp_screen *s, char *fmt) { struct sbuf *bar_buffer; int mark_start = 0; int mark_end = 0; if (s->bar_is_raised != BAR_IS_WINDOW_LIST) return; bar_buffer = sbuf_new (0); if(defaults.window_list_style == STYLE_ROW) { get_window_list (fmt, NULL, bar_buffer, &mark_start, &mark_end); marked_message_internal (sbuf_get (bar_buffer), mark_start, mark_end); } else { get_window_list (fmt, "\n", bar_buffer, &mark_start, &mark_end); marked_message_internal (sbuf_get (bar_buffer), mark_start, mark_end); } /* marked_message (sbuf_get (bar_buffer), mark_start, mark_end); */ sbuf_free (bar_buffer); }
static int browse_manifest_start(struct asfd *srfd, struct cstat *cstat, struct bu *bu, const char *browse, struct conf **confs) { int ret=-1; char *manifest=NULL; struct sbuf *sb=NULL; struct manio *manio=NULL; if(!(manifest=prepend_s(bu->path, cstat->protocol==PROTO_1?"manifest.gz":"manifest")) || !(manio=manio_alloc()) || manio_init_read(manio, manifest) || !(sb=sbuf_alloc_protocol(cstat->protocol))) goto end; manio_set_protocol(manio, cstat->protocol); if(get_int(confs[OPT_MONITOR_BROWSE_CACHE])) ret=cache_load(srfd, manio, sb, cstat, bu); else ret=do_browse_manifest(srfd, manio, sb, browse); end: free_w(&manifest); manio_free(&manio); sbuf_free(&sb); return ret; }
/* Lifted the code from rxvt. */ static char * get_primary_selection(void) { long nread; unsigned long bytes_after; XTextProperty ct; struct sbuf *s = sbuf_new(0); for (nread = 0, bytes_after = 1; bytes_after > 0; nread += ct.nitems) { if ((XGetWindowProperty(dpy, current_screen()->input_window, rp_selection, (nread / 4), 4096, True, AnyPropertyType, &ct.encoding, &ct.format, &ct.nitems, &bytes_after, &ct.value) != Success)) { XFree(ct.value); sbuf_free(s); return NULL; } if (ct.value == NULL) continue; /* Accumulate the data. FIXME: ct.value may not be NULL terminated. */ sbuf_nconcat (s, ct.value, ct.nitems); XFree(ct.value); } return sbuf_free_struct (s); }
static int write_to_changed_file(struct asfd *asfd, struct asfd *chfd, struct manios *manios, struct slist *slist, int end_flags) { struct sbuf *sb; if(!slist) return 0; while((sb=slist->head)) { if(sb->flags & SBUF_NEED_DATA) { switch(sbuf_needs_data(sb, asfd, chfd, manios, slist, end_flags)) { case 0: return 0; case 1: continue; default: return -1; } } else { // No change, can go straight in. if(manio_write_sbuf(manios->changed, sb)) return -1; if(write_endfile(sb, manios)) return -1; // Move along. slist->head=sb->next; sanity_before_sbuf_free(slist, sb); sbuf_free(&sb); } } return 0; }
static int restore_remaining_dirs(struct asfd *asfd, struct bu *bu, struct slist *slist, enum action act, struct sdirs *sdirs, enum cntr_status cntr_status, struct conf **cconfs) { int ret=-1; struct sbuf *sb; struct sbuf *need_data=NULL; if(!(need_data=sbuf_alloc(get_protocol(cconfs)))) goto end; // Restore any directories that are left in the list. for(sb=slist->head; sb; sb=sb->next) { if(get_protocol(cconfs)==PROTO_1) { if(restore_sbuf_protocol1(asfd, sb, bu, act, sdirs, cntr_status, cconfs)) goto end; } else { if(restore_sbuf_protocol2(asfd, sb, act, cntr_status, get_cntr(cconfs), need_data)) goto end; } } ret=0; end: sbuf_free(&need_data); return ret; }
/* * Print a number of variable values for NcML */ static void pr_any_valsx( const ncvar_t *vp, /* variable */ size_t len, /* number of values to print */ bool_t more, /* true if more data for this row will * follow, so add trailing comma */ bool_t lastrow, /* true if this is the last row for this * variable, so terminate with ";" instead * of "," */ const void *vals /* pointer to block of values */ ) { long iel; safebuf_t *sb = sbuf_new(); const char *valp = (const char *)vals; for (iel = 0; iel < len-1; iel++) { print_any_val(sb, vp, (void *)valp); valp += vp->tinfo->size; /* next value according to type */ sbuf_cat(sb, " "); lput(sbuf_str(sb)); } print_any_val(sb, vp, (void *)valp); lput(sbuf_str(sb)); lastdelim2x (more, lastrow); sbuf_free(sb); }
void free_sbufls(struct sbuf **sb, int count) { int s=0; if(!sb) return; for(s=0; s<count; s++) sbuf_free(&(sb[s])); free_v((void **)&sb); }
void term_commit(void) { if (term_sbuf) { write(1, sbuf_buf(term_sbuf), sbuf_len(term_sbuf)); sbuf_free(term_sbuf); term_sbuf = NULL; } }
void pkg_conflict_free(struct pkg_conflict *c) { if (c == NULL) return; sbuf_free(c->glob); free(c); }
static int maybe_add_from_scan(struct manios *manios, struct slist *slist, struct asfd *chfd, struct sbuf **csb) { int ret=-1; struct sbuf *snew=NULL; while(1) { sbuf_free(&snew); if(!manios->phase1) return 0; // Limit the amount loaded into memory at any one time. if(slist && slist->head) { if(slist->head->protocol2->index - slist->tail->protocol2->index>4096) return 0; } if(!(snew=sbuf_alloc(PROTO_2))) goto end; switch(manio_read(manios->phase1, snew)) { case 0: break; case 1: manio_close(&manios->phase1); ret=0; // Finished. default: goto end; } switch(entry_changed(snew, manios, chfd, csb)) { case 0: continue; // No change. case 1: break; default: goto end; // Error. } if(data_needed(snew)) snew->flags|=SBUF_NEED_DATA; slist_add_sbuf(slist, snew); snew=NULL; } return 0; end: sbuf_free(&snew); return ret; }
static void tear_down(struct sbuf **sb, struct cntr **cntr, struct conf ***confs, struct asfd **asfd) { clean(); sbuf_free(sb); cntr_free(cntr); confs_free(confs); asfd_free(asfd); asfd_mock_teardown(&areads, &awrites); alloc_check(); }
// When a backup is ongoing, use this to add newly complete candidates. int candidate_add_fresh(const char *path, struct conf *conf) { int ars; int ret=-1; gzFile zp=NULL; const char *cp=NULL; struct sbuf *sb=NULL; struct candidate *candidate=NULL; struct blk *blk=NULL; if(!(candidate=candidates_add_new())) goto end; cp=path+strlen(conf->directory); while(cp && *cp=='/') cp++; if(!(candidate->path=strdup(cp))) { log_out_of_memory(__func__); goto end; } if(!(sb=sbuf_alloc(conf)) || !(blk=blk_alloc()) || !(zp=gzopen_file(path, "rb"))) goto end; while(zp) { if((ars=sbuf_fill_from_gzfile(sb, NULL /* struct async */, zp, blk, NULL, conf))<0) goto end; else if(ars>0) { // Reached the end. break; } if(!*(blk->weak)) continue; if(is_hook(blk->weak)) { if(sparse_add_candidate(blk->weak, candidate)) goto end; } *blk->weak='\0'; } if(scores_grow(scores, candidates_len)) goto end; candidates_set_score_pointers(candidates, candidates_len, scores); scores_reset(scores); //printf("HERE: %d candidates\n", (int)candidates_len); ret=0; end: gzclose_fp(&zp); sbuf_free(sb); blk_free(blk); return ret; }
static void _ctx_free(struct type_5_parser_context *ctx) { if (!ctx) return; if (ctx->channels) list_free(ctx->channels); if (ctx->buffer) sbuf_free(ctx->buffer); if (ctx->current_channel) _channel_order_free(ctx->current_channel); free(ctx); }
int format_exec_cmd(char **dest, const char *in, const char *prefix, const char *plist_file) { struct sbuf *buf = sbuf_new_auto(); char path[MAXPATHLEN + 1]; char *cp; while (in[0] != '\0') { if (in[0] == '%') { in++; switch(in[0]) { case 'D': sbuf_cat(buf, prefix); break; case 'F': sbuf_cat(buf, plist_file); break; case 'f': if (prefix[strlen(prefix) - 1] == '/') snprintf(path, sizeof(path), "%s%s", prefix, plist_file); else snprintf(path, sizeof(path), "%s/%s", prefix, plist_file); cp = strrchr(path, '/'); cp ++; sbuf_cat(buf, cp); break; case 'B': if (prefix[strlen(prefix) - 1] == '/') snprintf(path, sizeof(path), "%s%s", prefix, plist_file); else snprintf(path, sizeof(path), "%s/%s", prefix, plist_file); cp = strrchr(path, '/'); cp[0] = '\0'; sbuf_cat(buf, path); break; default: sbuf_putc(buf, in[0]); break; } } else { sbuf_putc(buf, in[0]); } in++; } sbuf_finish(buf); *dest = strdup(sbuf_data(buf)); sbuf_free(buf); return (0); }
static void download_pipe_close(download_t *dn) { if (dn->pipe_fd >= 0) { close(dn->pipe_fd); if (dn->pipe_pid) kill(-(dn->pipe_pid), SIGKILL); /* kill whole process group */ dn->pipe_fd = -1; dn->pipe_pid = 0; } sbuf_free(&dn->pipe_sbuf); }
int packing_append_tree(struct packing *pack, const char *treepath, const char *newroot) { FTS *fts = NULL; FTSENT *fts_e = NULL; size_t treelen; struct sbuf *sb; char *paths[2] = { __DECONST(char *, treepath), NULL }; treelen = strlen(treepath); fts = fts_open(paths, FTS_PHYSICAL | FTS_XDEV, NULL); if (fts == NULL) goto cleanup; sb = sbuf_new_auto(); while ((fts_e = fts_read(fts)) != NULL) { switch(fts_e->fts_info) { case FTS_D: case FTS_DEFAULT: case FTS_F: case FTS_SL: case FTS_SLNONE: /* Entries not within this tree are irrelevant. */ if (fts_e->fts_pathlen <= treelen) break; sbuf_clear(sb); /* Strip the prefix to obtain the target path */ if (newroot) /* Prepend a root if one is specified */ sbuf_cat(sb, newroot); /* +1 = skip trailing slash */ sbuf_cat(sb, fts_e->fts_path + treelen + 1); sbuf_finish(sb); packing_append_file(pack, fts_e->fts_name, sbuf_get(sb)); break; case FTS_DC: case FTS_DNR: case FTS_ERR: case FTS_NS: /* XXX error cases, check fts_e->fts_errno and * bubble up the call chain */ break; default: break; } } sbuf_free(sb); cleanup: fts_close(fts); return EPKG_OK; }
int del_from_sbufl_arr(struct sbuf ***sblist, int *count) { struct sbuf **sbtmp=NULL; (*count)--; if((*sblist)[*count]) sbuf_free(&((*sblist)[*count])); if(*count && !(sbtmp=(struct sbuf **)realloc_w(*sblist, (*count)*sizeof(struct sbuf *), __func__))) return -1; *sblist=sbtmp; return 0; }
int64_t pkg_repo_binary_stat(struct pkg_repo *repo, pkg_stats_t type) { sqlite3 *sqlite = PRIV_GET(repo); sqlite3_stmt *stmt = NULL; int64_t stats = 0; struct sbuf *sql = NULL; int ret; sql = sbuf_new_auto(); switch(type) { case PKG_STATS_LOCAL_COUNT: goto out; break; case PKG_STATS_LOCAL_SIZE: goto out; break; case PKG_STATS_REMOTE_UNIQUE: sbuf_printf(sql, "SELECT COUNT(id) FROM main.packages;"); break; case PKG_STATS_REMOTE_COUNT: sbuf_printf(sql, "SELECT COUNT(id) FROM main.packages;"); break; case PKG_STATS_REMOTE_SIZE: sbuf_printf(sql, "SELECT SUM(pkgsize) FROM main.packages;"); break; case PKG_STATS_REMOTE_REPOS: goto out; break; } sbuf_finish(sql); pkg_debug(4, "binary_repo: running '%s'", sbuf_data(sql)); ret = sqlite3_prepare_v2(sqlite, sbuf_data(sql), -1, &stmt, NULL); if (ret != SQLITE_OK) { ERROR_SQLITE(sqlite, sbuf_data(sql)); goto out; } while (sqlite3_step(stmt) != SQLITE_DONE) { stats = sqlite3_column_int64(stmt, 0); } out: sbuf_free(sql); if (stmt != NULL) sqlite3_finalize(stmt); return (stats); }
void slist_free(struct slist *slist) { struct sbuf *sb; struct sbuf *shead; if(!slist) return; shead=slist->head; while(shead) { sb=shead; shead=shead->next; sbuf_free(&sb); } free(slist); }
void pkg_free(struct pkg *pkg) { if (pkg == NULL) return; free(pkg->name); free(pkg->origin); free(pkg->old_version); free(pkg->maintainer); free(pkg->www); free(pkg->arch); free(pkg->abi); free(pkg->uid); free(pkg->digest); free(pkg->old_digest); free(pkg->message); free(pkg->prefix); free(pkg->comment); free(pkg->desc); free(pkg->sum); free(pkg->repopath); free(pkg->repourl); free(pkg->reason); free(pkg->dep_formula); for (int i = 0; i < PKG_NUM_SCRIPTS; i++) sbuf_free(pkg->scripts[i]); pkg_list_free(pkg, PKG_DEPS); pkg_list_free(pkg, PKG_RDEPS); pkg_list_free(pkg, PKG_FILES); pkg_list_free(pkg, PKG_DIRS); pkg_list_free(pkg, PKG_OPTIONS); pkg_list_free(pkg, PKG_USERS); pkg_list_free(pkg, PKG_GROUPS); pkg_list_free(pkg, PKG_SHLIBS_REQUIRED); pkg_list_free(pkg, PKG_SHLIBS_PROVIDED); pkg_list_free(pkg, PKG_PROVIDES); pkg_list_free(pkg, PKG_REQUIRES); LL_FREE(pkg->categories, pkg_strel_free); LL_FREE(pkg->licenses, pkg_strel_free); LL_FREE(pkg->annotations, pkg_kv_free); if (pkg->rootfd != -1) close(pkg->rootfd); free(pkg); }