ipkg_cmd.c
来自「this is the pkg installer for linux」· C语言 代码 · 共 1,433 行 · 第 1/3 页
C
1,433 行
/* ipkg_cmd.c - the itsy package management system Carl D. Worth Copyright (C) 2001 University of Southern California This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.*/#include <string.h>#include "ipkg.h"#include <libgen.h>#include <glob.h>#include <errno.h>#include <stdlib.h>#include <unistd.h>#include <signal.h>#include <stdio.h>#include <dirent.h>#include "ipkg_conf.h"#include "ipkg_cmd.h"#include "ipkg_message.h"#include "pkg.h"#include "pkg_dest.h"#include "pkg_parse.h"#include "sprintf_alloc.h"#include "pkg.h"#include "file_util.h"#include "str_util.h"#include "libbb/libbb.h"#include <fnmatch.h>#include "ipkg_download.h"#include "ipkg_install.h"#include "ipkg_upgrade.h"#include "ipkg_remove.h"#include "ipkg_configure.h"#include "ipkg_message.h"#ifdef IPKG_LIB#include "libipkg.h"static void *p_userdata = NULL;#endifstatic int ipkg_update_cmd(ipkg_conf_t *conf, int argc, char **argv);static int ipkg_upgrade_cmd(ipkg_conf_t *conf, int argc, char **argv);static int ipkg_list_cmd(ipkg_conf_t *conf, int argc, char **argv);static int ipkg_info_cmd(ipkg_conf_t *conf, int argc, char **argv);static int ipkg_status_cmd(ipkg_conf_t *conf, int argc, char **argv);static int ipkg_install_pending_cmd(ipkg_conf_t *conf, int argc, char **argv);static int ipkg_install_cmd(ipkg_conf_t *conf, int argc, char **argv);static int ipkg_list_installed_cmd(ipkg_conf_t *conf, int argc, char **argv);static int ipkg_remove_cmd(ipkg_conf_t *conf, int argc, char **argv);static int ipkg_purge_cmd(ipkg_conf_t *conf, int argc, char **argv);static int ipkg_flag_cmd(ipkg_conf_t *conf, int argc, char **argv);static int ipkg_files_cmd(ipkg_conf_t *conf, int argc, char **argv);static int ipkg_search_cmd(ipkg_conf_t *conf, int argc, char **argv);static int ipkg_download_cmd(ipkg_conf_t *conf, int argc, char **argv);static int ipkg_depends_cmd(ipkg_conf_t *conf, int argc, char **argv);static int ipkg_whatdepends_cmd(ipkg_conf_t *conf, int argc, char **argv);static int ipkg_whatdepends_recursively_cmd(ipkg_conf_t *conf, int argc, char **argv);static int ipkg_whatsuggests_cmd(ipkg_conf_t *conf, int argc, char **argv);static int ipkg_whatrecommends_cmd(ipkg_conf_t *conf, int argc, char **argv);static int ipkg_whatprovides_cmd(ipkg_conf_t *conf, int argc, char **argv);static int ipkg_whatconflicts_cmd(ipkg_conf_t *conf, int argc, char **argv);static int ipkg_whatreplaces_cmd(ipkg_conf_t *conf, int argc, char **argv);static int ipkg_compare_versions_cmd(ipkg_conf_t *conf, int argc, char **argv);static int ipkg_print_architecture_cmd(ipkg_conf_t *conf, int argc, char **argv);static int ipkg_configure_cmd(ipkg_conf_t *conf, int argc, char **argv);/* XXX: CLEANUP: The usage strings should be incorporated into this array for easier maintenance */static ipkg_cmd_t cmds[] = { {"update", 0, (ipkg_cmd_fun_t)ipkg_update_cmd}, {"upgrade", 0, (ipkg_cmd_fun_t)ipkg_upgrade_cmd}, {"list", 0, (ipkg_cmd_fun_t)ipkg_list_cmd}, {"list_installed", 0, (ipkg_cmd_fun_t)ipkg_list_installed_cmd}, {"info", 0, (ipkg_cmd_fun_t)ipkg_info_cmd}, {"flag", 1, (ipkg_cmd_fun_t)ipkg_flag_cmd}, {"status", 0, (ipkg_cmd_fun_t)ipkg_status_cmd}, {"install_pending", 0, (ipkg_cmd_fun_t)ipkg_install_pending_cmd}, {"install", 1, (ipkg_cmd_fun_t)ipkg_install_cmd}, {"remove", 1, (ipkg_cmd_fun_t)ipkg_remove_cmd}, {"purge", 1, (ipkg_cmd_fun_t)ipkg_purge_cmd}, {"configure", 0, (ipkg_cmd_fun_t)ipkg_configure_cmd}, {"files", 1, (ipkg_cmd_fun_t)ipkg_files_cmd}, {"search", 1, (ipkg_cmd_fun_t)ipkg_search_cmd}, {"download", 1, (ipkg_cmd_fun_t)ipkg_download_cmd}, {"compare_versions", 1, (ipkg_cmd_fun_t)ipkg_compare_versions_cmd}, {"compare-versions", 1, (ipkg_cmd_fun_t)ipkg_compare_versions_cmd}, {"print-architecture", 0, (ipkg_cmd_fun_t)ipkg_print_architecture_cmd}, {"print_architecture", 0, (ipkg_cmd_fun_t)ipkg_print_architecture_cmd}, {"print-installation-architecture", 0, (ipkg_cmd_fun_t)ipkg_print_architecture_cmd}, {"print_installation_architecture", 0, (ipkg_cmd_fun_t)ipkg_print_architecture_cmd}, {"depends", 1, (ipkg_cmd_fun_t)ipkg_depends_cmd}, {"whatdepends", 1, (ipkg_cmd_fun_t)ipkg_whatdepends_cmd}, {"whatdependsrec", 1, (ipkg_cmd_fun_t)ipkg_whatdepends_recursively_cmd}, {"whatrecommends", 1, (ipkg_cmd_fun_t)ipkg_whatrecommends_cmd}, {"whatsuggests", 1, (ipkg_cmd_fun_t)ipkg_whatsuggests_cmd}, {"whatprovides", 1, (ipkg_cmd_fun_t)ipkg_whatprovides_cmd}, {"whatreplaces", 1, (ipkg_cmd_fun_t)ipkg_whatreplaces_cmd}, {"whatconflicts", 1, (ipkg_cmd_fun_t)ipkg_whatconflicts_cmd},};int ipkg_state_changed;static void write_status_files_if_changed(ipkg_conf_t *conf){ if (ipkg_state_changed && !conf->noaction) { ipkg_message(conf, IPKG_INFO, " writing status file\n"); ipkg_conf_write_status_files(conf); pkg_write_changed_filelists(conf); } else { ipkg_message(conf, IPKG_NOTICE, "Nothing to be done\n"); }}static int num_cmds = sizeof(cmds) / sizeof(ipkg_cmd_t);ipkg_cmd_t *ipkg_cmd_find(const char *name){ int i; ipkg_cmd_t *cmd; for (i=0; i < num_cmds; i++) { cmd = &cmds[i]; if (strcmp(name, cmd->name) == 0) { return cmd; } } return NULL;}#ifdef IPKG_LIBint ipkg_cmd_exec(ipkg_cmd_t *cmd, ipkg_conf_t *conf, int argc, const char **argv, void *userdata){ int result; p_userdata = userdata; result = (cmd->fun)(conf, argc, argv); if ( result == 0 ) { ipkg_message(conf, IPKG_NOTICE, "Successfully terminated.\n"); } else { ipkg_message(conf, IPKG_NOTICE, "An error ocurred, return value: %d.\n", result); } if ( error_list ) { reverse_error_list(&error_list); ipkg_message(conf, IPKG_NOTICE, "Collected errors:\n"); /* Here we print the errors collected and free the list */ while (error_list != NULL) { ipkg_message(conf, IPKG_NOTICE, "%s",error_list->errmsg); error_list = error_list->next; } free_error_list(&error_list); } p_userdata = NULL; return result;}#elseint ipkg_cmd_exec(ipkg_cmd_t *cmd, ipkg_conf_t *conf, int argc, const char **argv){ return (cmd->fun)(conf, argc, argv);}#endifstatic int ipkg_update_cmd(ipkg_conf_t *conf, int argc, char **argv){ int err; int failures; char *lists_dir; pkg_src_list_elt_t *iter; pkg_src_t *src; sprintf_alloc(&lists_dir, "%s", conf->restrict_to_default_dest ? conf->default_dest->lists_dir : conf->lists_dir); if (! file_is_dir(lists_dir)) { if (file_exists(lists_dir)) { ipkg_message(conf, IPKG_ERROR, "%s: ERROR: %s exists, but is not a directory\n", __FUNCTION__, lists_dir); free(lists_dir); return EINVAL; } err = file_mkdir_hier(lists_dir, 0755); if (err) { ipkg_message(conf, IPKG_ERROR, "%s: ERROR: failed to make directory %s: %s\n", __FUNCTION__, lists_dir, strerror(errno)); free(lists_dir); return EINVAL; } } failures = 0; for (iter = conf->pkg_src_list.head; iter; iter = iter->next) { char *url, *list_file_name; src = iter->data; if (src->extra_data) /* debian style? */ sprintf_alloc(&url, "%s/%s/%s", src->value, src->extra_data, src->gzip ? "Packages.gz" : "Packages"); else sprintf_alloc(&url, "%s/%s", src->value, src->gzip ? "Packages.gz" : "Packages"); sprintf_alloc(&list_file_name, "%s/%s", lists_dir, src->name); if (src->gzip) { char *tmp; char *tmp_file_name; FILE *in, *out; tmp = strdup ("/tmp/ipkg.XXXXXX"); if (mkdtemp (tmp) == NULL) { perror ("mkdtemp"); failures++; continue; } sprintf_alloc (&tmp_file_name, "%s/%s.gz", tmp, src->name); err = ipkg_download(conf, url, tmp_file_name); if (err == 0) { ipkg_message (conf, IPKG_NOTICE, "Inflating %s\n", url); in = fopen (tmp_file_name, "r"); out = fopen (list_file_name, "w"); if (in && out) unzip (in, out); else err = 1; if (in) fclose (in); if (out) fclose (out); unlink (tmp_file_name); rmdir (tmp); free (tmp); } } else err = ipkg_download(conf, url, list_file_name); if (err) { failures++; } else { ipkg_message(conf, IPKG_NOTICE, "Updated list of available packages in %s\n", list_file_name); } free(url); free(list_file_name); } free(lists_dir);#ifdef CONFIG_CLEAR_SW_INSTALL_FLAG#warning here /* clear SW_INSTALL on any package where state is SS_NOT_INSTALLED. * this is a hack to work around poor bookkeeping in old ipkg upgrade code * -Jamey 3/1/03 */ { int i; int changed = 0; pkg_vec_t *available = pkg_vec_alloc(); pkg_hash_fetch_available(&conf->pkg_hash, available); ipkg_message(conf, IPKG_DEBUG, "Clearing SW_INSTALL for SS_NOT_INSTALLED packages.\n"); for (i = 0; i < available->len; i++) { pkg_t *pkg = available->pkgs[i]; if (pkg->state_want == SW_INSTALL && pkg->state_status == SS_NOT_INSTALLED) { ipkg_message(conf, IPKG_DEBUG, "Clearing SW_INSTALL on package %s.\n", pkg->name); pkg->state_want = SW_UNKNOWN; changed = 1; } } pkg_vec_free(available); if (changed) { write_status_files_if_changed(conf); } }#endif return failures;}/* scan the args passed and cache the local filenames of the packages */int ipkg_multiple_files_scan(ipkg_conf_t *conf, int argc, char **argv){ int i; int err; /* * First scan through package names/urls * For any urls, download the packages and install in database. * For any files, install package info in database. */ for (i = 0; i < argc; i ++) { char *filename = argv [i]; //char *tmp = basename (tmp); //int tmplen = strlen (tmp); //if (strcmp (tmp + (tmplen - strlen (IPKG_PKG_EXTENSION)), IPKG_PKG_EXTENSION) != 0) // continue; //if (strcmp (tmp + (tmplen - strlen (DPKG_PKG_EXTENSION)), DPKG_PKG_EXTENSION) != 0) // continue; ipkg_message(conf, IPKG_DEBUG2, "Debug mfs: %s \n",filename ); err = ipkg_prepare_url_for_install(conf, filename, &argv[i]); if (err) return err; } return 0;}struct ipkg_intercept{ char *oldpath; char *statedir;};typedef struct ipkg_intercept *ipkg_intercept_t;ipkg_intercept_t ipkg_prep_intercepts(ipkg_conf_t *conf){ ipkg_intercept_t ctx; char *newpath; int gen; ctx = malloc (sizeof (*ctx)); ctx->oldpath = strdup (getenv ("PATH")); sprintf_alloc (&newpath, "%s/ipkg/intercept:%s", DATADIR, ctx->oldpath); setenv ("PATH", newpath, 1); free (newpath); gen = 0; retry: sprintf_alloc (&ctx->statedir, "/tmp/ipkg-intercept-%d-%d", getpid (), gen); if (mkdir (ctx->statedir, 0770) < 0) { if (errno == EEXIST) { free (ctx->statedir); gen++; goto retry; } perror (ctx->statedir); return NULL; } setenv ("IPKG_INTERCEPT_DIR", ctx->statedir, 1); return ctx;}int ipkg_finalize_intercepts(ipkg_intercept_t ctx){ char *cmd; DIR *dir; int err = 0; setenv ("PATH", ctx->oldpath, 1); free (ctx->oldpath); dir = opendir (ctx->statedir); if (dir) { struct dirent *de; while (de = readdir (dir), de != NULL) { char *path; if (de->d_name[0] == '.') continue; sprintf_alloc (&path, "%s/%s", ctx->statedir, de->d_name); if (access (path, X_OK) == 0) { if (system (path)) { err = errno; perror (de->d_name); } } free (path); } } else perror (ctx->statedir); sprintf_alloc (&cmd, "rm -rf %s", ctx->statedir); system (cmd); free (cmd); free (ctx->statedir); free (ctx); return err;}int ipkg_configure_packages(ipkg_conf_t *conf, char *pkg_name){ pkg_vec_t *all; int i; pkg_t *pkg; ipkg_intercept_t ic; int r, err = 0; ipkg_message(conf, IPKG_INFO, "Configuring unpacked packages\n"); fflush( stdout ); all = pkg_vec_alloc(); pkg_hash_fetch_available(&conf->pkg_hash, all); ic = ipkg_prep_intercepts (conf); for(i = 0; i < all->len; i++) { pkg = all->pkgs[i]; if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) continue; if (pkg->state_status == SS_UNPACKED) { ipkg_message(conf, IPKG_NOTICE, "Configuring %s\n", pkg->name); fflush( stdout ); r = ipkg_configure(conf, pkg); if (r == 0) { pkg->state_status = SS_INSTALLED; pkg->parent->state_status = SS_INSTALLED; pkg->state_flag &= ~SF_PREFER; } else { if (!err) err = r; } } } r = ipkg_finalize_intercepts (ic); if (r && !err) err = r; pkg_vec_free(all); return err;}static ipkg_conf_t *global_conf;static void sigint_handler(int sig){ signal(sig, SIG_DFL); ipkg_message(NULL, IPKG_NOTICE, "ipkg: interrupted. writing out status database\n"); write_status_files_if_changed(global_conf); exit(128 + sig);}static int ipkg_install_cmd(ipkg_conf_t *conf, int argc, char **argv){ int i; char *arg; int err=0; global_conf = conf; signal(SIGINT, sigint_handler); /*
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?