📄 dpkg.c
字号:
continue; } /* There is a conflict against the package name * check if version conflict as well */ if (test_version(package_hashtable[deb_file[i]->package]->version, package_edge->version, package_edge->operator)) { error_msg_and_die("Package %s conflict with %s", name_hashtable[package_hashtable[deb_file[i]->package]->name], name_hashtable[package_hashtable[status_package_num]->name]); } } } } /* Check dependendcies */ i = 0; while (deb_file[i] != NULL) { const common_node_t *package_node = package_hashtable[deb_file[i]->package]; int status_num = 0; for (j = 0; j < package_hashtable[deb_file[i]->package]->num_of_edges; j++) { const edge_t *package_edge = package_node->edge[j]; const unsigned int package_num = search_package_hashtable(package_edge->name, package_edge->version, package_edge->operator); status_num = search_status_hashtable(name_hashtable[package_hashtable[package_num]->name]); state_status = get_status(status_num, 3); state_want = get_status(status_num, 1); switch (package_edge->type) { case(EDGE_PRE_DEPENDS): case(EDGE_OR_PRE_DEPENDS): /* It must be already installed */ /* NOTE: This is untested, nothing apropriate in my status file */ if ((package_hashtable[package_num] == NULL) || (state_status != search_name_hashtable("installed"))) { error_msg_and_die("Package %s pre-depends on %s, but it is not installed", name_hashtable[package_node->name], name_hashtable[package_edge->name]); } break; case(EDGE_DEPENDS): case(EDGE_OR_DEPENDS): /* It must be already installed, or to be installed */ if ((package_hashtable[package_num] == NULL) || ((state_status != search_name_hashtable("installed")) && (state_want != search_name_hashtable("want_install")))) { error_msg_and_die("Package %s depends on %s, but it is not installed, or flaged to be installed", name_hashtable[package_node->name], name_hashtable[package_edge->name]); } break; } } i++; } free(conflicts); return(TRUE);}char **create_list(const char *filename){ FILE *list_stream; char **file_list = xmalloc(sizeof(char *)); char *line = NULL; char *last_char; int length = 0; int count = 0; /* dont use [xw]fopen here, handle error ourself */ list_stream = fopen(filename, "r"); if (list_stream == NULL) { *file_list = NULL; return(file_list); } while (getline(&line, &length, list_stream) != -1) { file_list = xrealloc(file_list, sizeof(char *) * (length + 1)); last_char = last_char_is(line, '\n'); if (last_char) { *last_char = '\0'; } file_list[count] = xstrdup(line); free(line); count++; length = 0; } fclose(list_stream); if (count == 0) { return(NULL); } else { file_list[count] = NULL; return(file_list); }}/* maybe i should try and hook this into remove_file.c somehow */int remove_file_array(char **remove_names, char **exclude_names){ struct stat path_stat; int match_flag; int remove_flag = FALSE; int i,j; if (remove_names == NULL) { return(FALSE); } for (i = 0; remove_names[i] != NULL; i++) { match_flag = FALSE; if (exclude_names != NULL) { for (j = 0; exclude_names[j] != 0; j++) { if (strcmp(remove_names[i], exclude_names[j]) == 0) { match_flag = TRUE; break; } } } if (!match_flag) { if (lstat(remove_names[i], &path_stat) < 0) { continue; } if (S_ISDIR(path_stat.st_mode)) { if (rmdir(remove_names[i]) != -1) { remove_flag = TRUE; } } else { if (unlink(remove_names[i]) != -1) { remove_flag = TRUE; } } } } return(remove_flag);}int run_package_script(const char *package_name, const char *script_type){ struct stat path_stat; char *script_path; script_path = xmalloc(strlen(package_name) + strlen(script_type) + 21); sprintf(script_path, "/var/lib/dpkg/info/%s.%s", package_name, script_type); /* If the file doesnt exist is isnt a fatal */ if (lstat(script_path, &path_stat) < 0) { free(script_path); return(EXIT_SUCCESS); } else { free(script_path); return(system(script_path)); }}void all_control_list(char **remove_files, const char *package_name){ const char *all_extensions[11] = {"preinst", "postinst", "prerm", "postrm", "list", "md5sums", "shlibs", "conffiles", "config", "templates", NULL }; int i; /* Create a list of all /var/lib/dpkg/info/<package> files */ for(i = 0; i < 10; i++) { remove_files[i] = xmalloc(strlen(package_name) + strlen(all_extensions[i]) + 21); sprintf(remove_files[i], "/var/lib/dpkg/info/%s.%s", package_name, all_extensions[i]); } remove_files[10] = NULL;}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) == TRUE); /* Create a list of all /var/lib/dpkg/info/<package> files */ remove_files = xmalloc(11); all_control_list(remove_files, package_name); /* 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; remove_file_array(remove_files, 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") == -1) { 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(1); exclude_files[0] = NULL; /* Some directories cant be removed straight away, so do multiple passes */ while (remove_file_array(remove_files, exclude_files) == TRUE); /* Create a list of all /var/lib/dpkg/info/<package> files */ remove_files = xmalloc(11); all_control_list(remove_files, package_name); remove_file_array(remove_files, 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]->status; 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(sizeof(package_name) + 20 + 4 + 1); 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), info_prefix, NULL); /* Extract data.tar.gz to the root directory */ deb_extract(deb_file->filename, stdout, (extract_quiet | extract_data_tar_gz | extract_all_to_fs), "/", 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, 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); int return_value; printf("Setting up %s (%s)\n", package_name, package_version); /* Run the preinst prior to extracting */ return_value = run_package_script(package_name, "postinst"); if (return_value == -1) { /* 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);}extern int dpkg_main(int argc, char **argv){ deb_file_t **deb_file = NULL; status_node_t *status_node; int opt = 0; 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; 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(); } } if ((argc == optind) || (dpkg_opt == 0)) { show_usage(); } puts("(Reading database ... xxxxx files and directories installed.)"); index_status_file("/var/lib/dpkg/status"); /* Read arguments and store relevant info in structs */ deb_file = xmalloc(sizeof(deb_file_t)); while (optind < argc) { 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; /* use reinstreq isnt changed to "ok" until the package control info * is written to the status file*/ status_node->status = search_name_hashtable("install reinstreq not-installed"); status_num = search_status_hashtable(name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]); status_hashtable[status_num] = status_node; } } 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++) { free_package(package_hashtable[i]); } for (i = 0; i < STATUS_HASH_PRIME; i++) { if (status_hashtable[i] != NULL) { free(status_hashtable[i]); } } return(EXIT_FAILURE);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -