📄 dpkg.c
字号:
} free(array); }}/* This function lists information on the installed packages. It loops through * the status_hashtable to retrieve the info. This results in smaller code than * scanning the status file. The resulting list, however, is unsorted. */void list_packages(void){ int i; printf(" Name Version\n"); printf("+++-==============-==============\n"); /* go through status hash, dereference package hash and finally strings */ for (i=0; i<STATUS_HASH_PRIME+1; i++) { if (status_hashtable[i]) { const char *stat_str; /* status string */ const char *name_str; /* package name */ const char *vers_str; /* version */ char s1, s2; /* status abbreviations */ int spccnt; /* space count */ int j; stat_str = name_hashtable[status_hashtable[i]->status]; name_str = name_hashtable[package_hashtable[status_hashtable[i]->package]->name]; vers_str = name_hashtable[package_hashtable[status_hashtable[i]->package]->version]; /* get abbreviation for status field 1 */ s1 = stat_str[0] == 'i' ? 'i' : 'r'; /* get abbreviation for status field 2 */ for (j=0, spccnt=0; stat_str[j] && spccnt<2; j++) { if (stat_str[j] == ' ') spccnt++; } s2 = stat_str[j]; /* print out the line formatted like Debian dpkg */ printf("%c%c %-14s %s\n", s1, s2, name_str, vers_str); } }}void remove_package(const unsigned int package_num){ const char *package_name = name_hashtable[package_hashtable[package_num]->name]; const unsigned int status_num = search_status_hashtable(package_name); const int package_name_length = strlen(package_name); char **remove_files; char **exclude_files; char list_name[package_name_length + 25]; char conffile_name[package_name_length + 30]; int return_value; printf("Removing %s ...\n", package_name); /* run prerm script */ return_value = run_package_script(package_name, "prerm"); if (return_value == -1) { error_msg_and_die("script failed, prerm failure"); } /* Create a list of files to remove, and a seperate list of those to keep */ sprintf(list_name, "/var/lib/dpkg/info/%s.list", package_name); remove_files = create_list(list_name); sprintf(conffile_name, "/var/lib/dpkg/info/%s.conffiles", package_name); exclude_files = create_list(conffile_name); /* Some directories cant be removed straight away, so do multiple passes */ while (remove_file_array(remove_files, exclude_files)); free_array(exclude_files); free_array(remove_files); /* Create a list of files in /var/lib/dpkg/info/<package>.* to keep */ exclude_files = xmalloc(sizeof(char*) * 3); exclude_files[0] = xstrdup(conffile_name); exclude_files[1] = xmalloc(package_name_length + 27); sprintf(exclude_files[1], "/var/lib/dpkg/info/%s.postrm", package_name); exclude_files[2] = NULL; /* Create a list of all /var/lib/dpkg/info/<package> files */ remove_files = all_control_list(package_name); remove_file_array(remove_files, exclude_files); free_array(remove_files); free_array(exclude_files); /* rename <package>.conffile to <package>.list */ rename(conffile_name, list_name); /* Change package status */ set_status(status_num, "deinstall", 1); set_status(status_num, "config-files", 3);}void purge_package(const unsigned int package_num){ const char *package_name = name_hashtable[package_hashtable[package_num]->name]; const unsigned int status_num = search_status_hashtable(package_name); char **remove_files; char **exclude_files; char list_name[strlen(package_name) + 25]; /* run prerm script */ if (run_package_script(package_name, "prerm") != 0) { error_msg_and_die("script failed, prerm failure"); } /* Create a list of files to remove */ sprintf(list_name, "/var/lib/dpkg/info/%s.list", package_name); remove_files = create_list(list_name); exclude_files = xmalloc(sizeof(char*)); exclude_files[0] = NULL; /* Some directories cant be removed straight away, so do multiple passes */ while (remove_file_array(remove_files, exclude_files)); free_array(remove_files); /* Create a list of all /var/lib/dpkg/info/<package> files */ remove_files = all_control_list(package_name); remove_file_array(remove_files, exclude_files); free_array(remove_files); free(exclude_files); /* run postrm script */ if (run_package_script(package_name, "postrm") == -1) { error_msg_and_die("postrm fialure.. set status to what?"); } /* Change package status */ set_status(status_num, "purge", 1); set_status(status_num, "not-installed", 3);}void unpack_package(deb_file_t *deb_file){ const char *package_name = name_hashtable[package_hashtable[deb_file->package]->name]; const unsigned int status_num = search_status_hashtable(package_name); const unsigned int status_package_num = status_hashtable[status_num]->package; FILE *out_stream; char *info_prefix; /* If existing version, remove it first */ if (strcmp(name_hashtable[get_status(status_num, 3)], "installed") == 0) { /* Package is already installed, remove old version first */ printf("Preparing to replace %s %s (using %s) ...\n", package_name, name_hashtable[package_hashtable[status_package_num]->version], deb_file->filename); remove_package(status_package_num); } else { printf("Unpacking %s (from %s) ...\n", package_name, deb_file->filename); } /* Extract control.tar.gz to /var/lib/dpkg/info/<package>.filename */ info_prefix = (char *) xmalloc(strlen(package_name) + 20 + 4 + 2); sprintf(info_prefix, "/var/lib/dpkg/info/%s.", package_name); deb_extract(deb_file->filename, stdout, (extract_quiet | extract_control_tar_gz | extract_all_to_fs | extract_unconditional), info_prefix, NULL); /* Run the preinst prior to extracting */ if (run_package_script(package_name, "preinst") != 0) { /* when preinst returns exit code != 0 then quit installation process */ error_msg_and_die("subprocess pre-installation script returned error."); } /* Extract data.tar.gz to the root directory */ deb_extract(deb_file->filename, stdout, (extract_quiet | extract_data_tar_gz | extract_all_to_fs | extract_unconditional), "/", NULL); /* Create the list file */ strcat(info_prefix, "list"); out_stream = xfopen(info_prefix, "w"); deb_extract(deb_file->filename, out_stream, (extract_quiet | extract_data_tar_gz | extract_list), "/", NULL); fclose(out_stream); /* change status */ set_status(status_num, "install", 1); set_status(status_num, "unpacked", 3); free(info_prefix);}void configure_package(deb_file_t *deb_file){ const char *package_name = name_hashtable[package_hashtable[deb_file->package]->name]; const char *package_version = name_hashtable[package_hashtable[deb_file->package]->version]; const int status_num = search_status_hashtable(package_name); printf("Setting up %s (%s)\n", package_name, package_version); /* Run the postinst script */ if (run_package_script(package_name, "postinst") != 0) { /* TODO: handle failure gracefully */ error_msg_and_die("postrm failure.. set status to what?"); } /* Change status to reflect success */ set_status(status_num, "install", 1); set_status(status_num, "installed", 3);}int dpkg_main(int argc, char **argv){ deb_file_t **deb_file = NULL; status_node_t *status_node; int opt; int package_num; int dpkg_opt = 0; int deb_count = 0; int state_status; int status_num; int i; while ((opt = getopt(argc, argv, "CF:ilPru")) != -1) { switch (opt) { case 'C': // equivalent to --configure in official dpkg dpkg_opt |= dpkg_opt_configure; dpkg_opt |= dpkg_opt_package_name; break; case 'F': // equivalent to --force in official dpkg if (strcmp(optarg, "depends") == 0) { dpkg_opt |= dpkg_opt_force_ignore_depends; } case 'i': dpkg_opt |= dpkg_opt_install; dpkg_opt |= dpkg_opt_filename; break; case 'l': dpkg_opt |= dpkg_opt_list_installed; break; case 'P': dpkg_opt |= dpkg_opt_purge; dpkg_opt |= dpkg_opt_package_name; break; case 'r': dpkg_opt |= dpkg_opt_remove; dpkg_opt |= dpkg_opt_package_name; break; case 'u': /* Equivalent to --unpack in official dpkg */ dpkg_opt |= dpkg_opt_unpack; dpkg_opt |= dpkg_opt_filename; break; default: show_usage(); } } /* check for non-otion argument if expected */ if ((dpkg_opt == 0) || ((argc == optind) && !(dpkg_opt && dpkg_opt_list_installed))) { show_usage(); }/* puts("(Reading database ... xxxxx files and directories installed.)"); */ index_status_file("/var/lib/dpkg/status"); /* if the list action was given print the installed packages and exit */ if (dpkg_opt & dpkg_opt_list_installed) { list_packages(); return(EXIT_SUCCESS); } /* Read arguments and store relevant info in structs */ while (optind < argc) { /* deb_count = nb_elem - 1 and we need nb_elem + 1 to allocate terminal node [NULL pointer] */ deb_file = xrealloc(deb_file, sizeof(deb_file_t *) * (deb_count + 2)); deb_file[deb_count] = (deb_file_t *) xmalloc(sizeof(deb_file_t)); if (dpkg_opt & dpkg_opt_filename) { deb_file[deb_count]->filename = xstrdup(argv[optind]); deb_file[deb_count]->control_file = deb_extract(argv[optind], stdout, (extract_control_tar_gz | extract_one_to_buffer), NULL, "./control"); if (deb_file[deb_count]->control_file == NULL) { error_msg_and_die("Couldnt extract control file"); } package_num = fill_package_struct(deb_file[deb_count]->control_file); if (package_num == -1) { error_msg("Invalid control file in %s", argv[optind]); continue; } deb_file[deb_count]->package = (unsigned int) package_num; /* Add the package to the status hashtable */ if ((dpkg_opt & dpkg_opt_unpack) || (dpkg_opt & dpkg_opt_install)) { status_node = (status_node_t *) xmalloc(sizeof(status_node_t)); status_node->package = deb_file[deb_count]->package; /* Try and find a currently installed version of this package */ status_num = search_status_hashtable(name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]); /* If no previous entry was found initialise a new entry */ if ((status_hashtable[status_num] == NULL) || (status_hashtable[status_num]->status == 0)) { /* reinstreq isnt changed to "ok" until the package control info * is written to the status file*/ status_node->status = search_name_hashtable("want-install reinstreq not-installed"); status_hashtable[status_num] = status_node; } else { status_hashtable[status_num]->status = search_name_hashtable("want-install reinstreq not-installed"); } } } else if (dpkg_opt & dpkg_opt_package_name) { deb_file[deb_count]->filename = NULL; deb_file[deb_count]->control_file = NULL; deb_file[deb_count]->package = search_package_hashtable( search_name_hashtable(argv[optind]), search_name_hashtable("ANY"), VER_ANY); if (package_hashtable[deb_file[deb_count]->package] == NULL) { error_msg_and_die("Package %s is uninstalled or unknown\n", argv[optind]); } state_status = get_status(search_status_hashtable(name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]), 3); /* check package status is "installed" */ if (dpkg_opt & dpkg_opt_remove) { if ((strcmp(name_hashtable[state_status], "not-installed") == 0) || (strcmp(name_hashtable[state_status], "config-files") == 0)) { error_msg_and_die("%s is already removed.", name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]); } } else if (dpkg_opt & dpkg_opt_purge) { /* if package status is "conf-files" then its ok */ if (strcmp(name_hashtable[state_status], "not-installed") == 0) { error_msg_and_die("%s is already purged.", name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]); } } } deb_count++; optind++; } deb_file[deb_count] = NULL; /* Check that the deb file arguments are installable */ /* TODO: check dependencies before removing */ if ((dpkg_opt & dpkg_opt_force_ignore_depends) != dpkg_opt_force_ignore_depends) { if (!check_deps(deb_file, 0, deb_count)) { error_msg_and_die("Dependency check failed"); } } for (i = 0; i < deb_count; i++) { /* Remove or purge packages */ if (dpkg_opt & dpkg_opt_remove) { remove_package(deb_file[i]->package); } else if (dpkg_opt & dpkg_opt_purge) { purge_package(deb_file[i]->package); } else if (dpkg_opt & dpkg_opt_unpack) { unpack_package(deb_file[i]); } else if (dpkg_opt & dpkg_opt_install) { unpack_package(deb_file[i]); configure_package(deb_file[i]); } else if (dpkg_opt & dpkg_opt_configure) { configure_package(deb_file[i]); } } write_status_file(deb_file); for (i = 0; i < deb_count; i++) { free(deb_file[i]->control_file); free(deb_file[i]->filename); free(deb_file[i]); } free(deb_file); for (i = 0; i < NAME_HASH_PRIME; i++) { if (name_hashtable[i] != NULL) { free(name_hashtable[i]); } } for (i = 0; i < PACKAGE_HASH_PRIME; i++) { if (package_hashtable[i] != NULL) { free_package(package_hashtable[i]); } } for (i = 0; i < STATUS_HASH_PRIME; i++) { if (status_hashtable[i] != NULL) { free(status_hashtable[i]); } } return(EXIT_SUCCESS);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -