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 + -
显示快捷键?