aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'conf-update.c')
-rw-r--r--conf-update.c438
1 files changed, 438 insertions, 0 deletions
diff --git a/conf-update.c b/conf-update.c
new file mode 100644
index 0000000..f987501
--- /dev/null
+++ b/conf-update.c
@@ -0,0 +1,438 @@
+#include "conf-update.h"
+
+int main(int argc, char **argv) {
+ bool cont, menu_changed, firstrun, doit;
+ bool *tmp_index;
+ char *config_protect, *config_protect_mask,*cmd, *myfile, *highest;
+ char *esc_highest, *esc_myfile;
+ char **result, **envvars, **protected, **masked, **md5_cache;
+ char **md5sum_cache, **myupdate, **merged_updates_report = NULL;
+ char **removed_updates_report = NULL;
+ const char *name, *myname;
+ int indent, myindent, i, j, file_count, c, item_ct, cur;
+ int merged_updates_ct = 0, removed_updates_ct = 0, arglen;
+ ITEM **items_list;
+ MENU *mymenu;
+ WINDOW *inner, *menu_win;
+
+ read_config();
+ sanity_checks();
+
+ if (argc == 1) {
+ fprintf(stderr, ">>> Getting CONFIG_PROTECT* variables from portage...\n");
+ #ifdef DEBUG
+ // sandboxing is useful for debugging, believe me
+ envvars = get_listing("portageq envvar CONFIG_PROTECT CONFIG_PROTECT_MASK | sed -e \"s:^/:${SANDBOX}/:\" -e \"s: /: ${SANDBOX}/:g\"", "\n");
+ #else
+ envvars = get_listing("portageq envvar CONFIG_PROTECT CONFIG_PROTECT_MASK", "\n");
+ #endif
+
+ if (is_valid_entry(envvars[0]) && is_valid_entry(envvars[1])) {
+ config_protect = strdup(envvars[0]);
+ config_protect_mask = strdup(envvars[1]);
+ free(envvars[0]);
+ free(envvars[1]);
+ free(envvars);
+ } else {
+ fprintf(stderr, "!!! failed. Aborting.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ fprintf(stderr, ">>> Automerging updates in CONFIG_PROTECT_MASK...\n");
+ masked = find_updates(config_protect_mask);
+ free(config_protect_mask);
+ for (i=0;!is_last_entry(masked[i]);i++) {
+ if (is_valid_entry(masked[i])) {
+ merged_updates_ct++;
+ merged_updates_report = (char **)realloc(merged_updates_report, merged_updates_ct * sizeof(char *));
+ merged_updates_report[merged_updates_ct-1] = get_real_filename(masked[i]);
+ merge(get_highest_update(masked, masked[i]), masked);
+ }
+ }
+ free(masked);
+ fprintf(stderr, ">>> Searching for updates in CONFIG_PROTECT...\n");
+ } else {
+ if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
+ display_help();
+ } else {
+ arglen = 0;
+ for (i=1;i<argc;i++) {
+ arglen += strlen(argv[i]) + 1;
+ }
+ config_protect = (char *)calloc(sizeof(char), arglen);
+ for (i=1;i<argc;i++) {
+ if (argv[i][0] != '/') {
+ // relative paths screw our indentation. maybe this should be a TODO?
+ fprintf(stderr, "!!! ERROR: Non-absolute path given as argument\n");
+ exit(EXIT_FAILURE);
+ }
+ strcat(config_protect, argv[i]);
+ if (i < argc-1) {
+ strcat(config_protect, " ");
+ }
+ }
+ fprintf(stderr, ">>> Searching for updates in specified directories...\n");
+ }
+ }
+
+ protected = find_updates(config_protect);
+
+ // it's important that we do this first
+ if (config.automerge_unmodified) {
+ fprintf(stderr, ">>> Automerging unmodified files...\n");
+ file_count = 1;
+ md5_cache = (char **) malloc(sizeof(char *) * file_count);
+ md5sum_cache = (char **) malloc(sizeof(char *) * file_count);
+ md5_cache[0] = LAST_ENTRY;
+ md5sum_cache[0] = LAST_ENTRY;
+ for (i=0;!is_last_entry(protected[i]);i++) {
+ if (is_valid_entry(protected[i])) {
+ highest = get_highest_update(protected, protected[i]);
+ if (!strcmp(protected[i], highest)) {
+ md5_cache = (char **) realloc(md5_cache, sizeof(char *) * (file_count + 1));
+ md5sum_cache = (char **) realloc(md5sum_cache, sizeof(char *) * (file_count + 1));
+ md5_cache[file_count-1] = strdup(highest);
+ md5sum_cache[file_count-1] = (char *)malloc(sizeof(char) * 32);
+ calc_md5(md5_cache[file_count-1], md5sum_cache[file_count-1]);
+ md5_cache[file_count] = LAST_ENTRY;
+ md5sum_cache[file_count] = LAST_ENTRY;
+ file_count++;
+ }
+ }
+ }
+ for (i=0;!is_last_entry(protected[i]);i++) {
+ if (is_valid_entry(protected[i])) {
+ myfile = get_real_filename(protected[i]);
+
+ if (!user_modified(myfile)) {
+ merged_updates_ct++;
+ merged_updates_report = (char **)realloc(merged_updates_report, merged_updates_ct * sizeof(char *));
+ merged_updates_report[merged_updates_ct-1] = get_real_filename(protected[i]);
+ merge(get_highest_update(protected, protected[i]), protected);
+ }
+
+ free(myfile);
+ }
+ }
+ for (i=0;!is_last_entry(md5_cache[i]);i++) {
+ myfile = get_real_filename(md5_cache[i]);
+ md5sum_update(myfile, md5sum_cache[i]);
+ free(myfile);
+ free(md5_cache[i]);
+ free(md5sum_cache[i]);
+ }
+ free(md5_cache);
+ free(md5sum_cache);
+ }
+
+ if (config.automerge_trivial) {
+ fprintf(stderr, ">>> Automerging trivial changes...\n");
+ for (i=0;!is_last_entry(protected[i]);i++) {
+ if (is_valid_entry(protected[i])) {
+ myfile = get_real_filename(protected[i]);
+ esc_myfile = g_shell_quote(myfile);
+ highest = get_highest_update(protected, protected[i]);
+ esc_highest = g_shell_quote(highest);
+ cmd = (char *)calloc(strlen("diff -Nu % % | grep \"^[+-][^+-]\" | grep -v \"^[-+]#\" | grep -v \"^[-+][:space:]*$\" " ) + strlen(esc_highest) + strlen(esc_myfile), sizeof(char));
+ strcpy(cmd, "diff -Nu ");
+ strcat(cmd, esc_myfile);
+ strcat(cmd, " ");
+ strcat(cmd, esc_highest);
+ strcat(cmd, " | grep \"^[+-][^+-]\" | grep -v \"^[-+]#\" | grep -v \"^[-+][:space:]*$\"");
+
+ free(myfile);
+ free(esc_myfile);
+ free(esc_highest);
+
+ result = get_listing(cmd, "\n");
+ free(cmd);
+ if (is_last_entry(result[0])) {
+ merged_updates_ct++;
+ merged_updates_report = (char **)realloc(merged_updates_report, merged_updates_ct * sizeof(char *));
+ merged_updates_report[merged_updates_ct-1] = get_real_filename(highest);
+ merge(highest, protected);
+ }
+ for (j=0;!is_last_entry(result[j]);j++) {
+ free(result[j]);
+ }
+ free(result);
+ }
+ }
+ }
+ /***/
+ // ncurses n'stuff
+ initscr();
+ cbreak();
+ noecho();
+ keypad(stdscr, TRUE);
+ start_color();
+ init_pair(1, COLOR_CYAN, COLOR_BLUE);
+ init_pair(2, COLOR_WHITE, COLOR_WHITE);
+ init_pair(3, COLOR_BLACK, COLOR_WHITE);
+ init_pair(4, COLOR_RED, COLOR_WHITE);
+ init_pair(5, COLOR_WHITE, COLOR_BLACK);
+
+ draw_background();
+
+ inner = newwin(LINES - 4, COLS - 4, 2, 2);
+ keypad(inner, TRUE);
+
+ draw_legend(inner);
+
+ menu_win = subwin(inner, LINES - 7 - 6, COLS - 4 - 3, 8, 3);
+
+ mymenu = create_menu(protected);
+ items_list = menu_items(mymenu);
+ set_menu_win(mymenu, inner);
+ set_menu_sub(mymenu, menu_win);
+
+ post_menu(mymenu);
+ touchwin(inner);
+ wrefresh(inner);
+ menu_changed = FALSE;
+ while ((item_count(mymenu) > 1) && (c = wgetch(inner)) != 'q' && c != 'Q') {
+ switch(c) {
+ // navigation 1up/down
+ case KEY_DOWN:
+ menu_driver(mymenu, REQ_DOWN_ITEM);
+ break;
+ case KEY_UP:
+ menu_driver(mymenu, REQ_UP_ITEM);
+ break;
+ //navigation 1 page up/down
+ case KEY_PPAGE:
+ menu_driver(mymenu, REQ_SCR_UPAGE);
+ break;
+ case KEY_NPAGE:
+ menu_driver(mymenu, REQ_SCR_DPAGE);
+ break;
+ // navigation top/bottom
+ case KEY_HOME:
+ menu_driver(mymenu, REQ_FIRST_ITEM);
+ break;
+ case KEY_END:
+ menu_driver(mymenu, REQ_LAST_ITEM);
+ break;
+
+ // select single
+ case ' ':
+ if ((strrchr(item_name(current_item(mymenu)), '/'))) {
+ // it's a dir, select all subdirs + files
+ name = item_name(current_item(mymenu));
+ indent = 0;
+ while (name[indent] == INDENT_CHAR) {
+ indent++;
+ }
+ cont = TRUE;
+ while (cont) {
+ menu_driver(mymenu, REQ_DOWN_ITEM);
+ myname = item_name(current_item(mymenu));
+ myindent = 0;
+ while (myname[myindent] == INDENT_CHAR) {
+ myindent++;
+ }
+ if (myindent > indent) {
+ if ((!strrchr(myname, '/'))) {
+ set_item_value(current_item(mymenu), TRUE);
+ }
+ } else {
+ menu_driver(mymenu, REQ_UP_ITEM);
+ cont = FALSE;
+ }
+ }
+ } else {
+ menu_driver(mymenu, REQ_TOGGLE_ITEM);
+ }
+ break;
+ // select all
+ case 'a':
+ case 'A':
+ menu_driver(mymenu, REQ_LAST_ITEM);
+ for (i=0;i<item_count(mymenu);i++) {
+ if ((!strrchr(item_name(current_item(mymenu)), '/'))) {
+ set_item_value(current_item(mymenu), TRUE);
+ }
+ menu_driver(mymenu, REQ_UP_ITEM);
+ }
+ menu_driver(mymenu, REQ_FIRST_ITEM);
+ break;
+ // deselect all
+ case 'u':
+ case 'U':
+ menu_driver(mymenu, REQ_LAST_ITEM);
+ for (i=0;i<item_count(mymenu);i++) {
+ menu_driver(mymenu, REQ_UP_ITEM);
+ set_item_value(current_item(mymenu), FALSE);
+ }
+ menu_driver(mymenu, REQ_FIRST_ITEM);
+ break;
+ // disp diff
+ case '\n':
+ case KEY_ENTER:
+ if (item_userptr(current_item(mymenu))) {
+ endwin();
+ show_diff(*((char **)item_userptr(current_item(mymenu))));
+ reset_prog_mode();
+ }
+ break;
+ // edit update
+ case 'e':
+ case 'E':
+ if (item_userptr(current_item(mymenu))) {
+ endwin();
+ edit_update(*((char **)item_userptr(current_item(mymenu))));
+ reset_prog_mode();
+ }
+ break;
+ // merge interactively
+ case 'm':
+ case 'M':
+ if (item_userptr(current_item(mymenu))) {
+ endwin();
+ protected = merge_interactively(*((char **)item_userptr(current_item(mymenu))), protected);
+ reset_prog_mode();
+ menu_changed = TRUE;
+ }
+ break;
+
+ // merge/replace update
+ case 'r':
+ case 'R':
+ /* it is important that we go from last to first:
+ * if e.g. both 0000 and 0001 are selected for merging, this
+ * assures (given a sorted list), that 0001 gets merged before
+ * 0000 and therefore 0000 gets removed
+ */
+ firstrun = config.check_actions;
+ doit = TRUE;
+ for (i=item_count(mymenu)-1;i>=0;i--) {
+ if (item_value(items_list[i]) == TRUE || (current_item(mymenu) == items_list[i] && item_userptr(items_list[i]))) {
+ if (firstrun) {
+ doit = get_confirmation(inner, "replace");
+ firstrun = false;
+ }
+ if (doit) {
+ myupdate = (char **)item_userptr(items_list[i]);
+ if (is_valid_entry(*myupdate)) {
+ merged_updates_ct++;
+ merged_updates_report = (char **)realloc(merged_updates_report, merged_updates_ct * sizeof(char *));
+ merged_updates_report[merged_updates_ct-1] = get_real_filename(*myupdate);
+ menu_changed = TRUE;
+ merge(*myupdate, protected);
+ }
+ }
+ }
+ }
+ break;
+ // delete update
+ case 'd':
+ case 'D':
+ firstrun = config.check_actions;
+ doit = TRUE;
+ for (i=0;i<item_count(mymenu);i++) {
+ if (item_value(items_list[i]) == TRUE || (current_item(mymenu) == items_list[i] && item_userptr(items_list[i]))) {
+ if (firstrun) {
+ doit = get_confirmation(inner, "delete");
+ firstrun = false;
+ }
+ if (doit) {
+ myupdate = (char **)item_userptr(items_list[i]);
+ exit_error(!unlink(*(myupdate)), *(myupdate));
+ removed_updates_ct++;
+ removed_updates_report = (char**)realloc(removed_updates_report, removed_updates_ct * sizeof(char *));
+ removed_updates_report[removed_updates_ct-1] = get_real_filename(*myupdate);
+ free(*myupdate);
+ *myupdate = SKIP_ENTRY;
+ menu_changed = TRUE;
+ }
+ }
+ }
+ break;
+ case KEY_RESIZE:
+ if (LINES > 13 && COLS > 55) {
+ // we don't want to loose the selection just because of a window resize
+ item_ct = item_count(mymenu);
+ cur = item_index(current_item(mymenu));
+ tmp_index = malloc(sizeof(bool) * item_ct);
+ for (i=0;i<item_ct;i++) {
+ if (item_value(items_list[i]) == TRUE || (cur == i && item_userptr(items_list[i]))) {
+ tmp_index[i] = TRUE;
+ } else {
+ tmp_index[i] = FALSE;
+ }
+ }
+ remove_menu(mymenu);
+ delwin(menu_win);
+ delwin(inner);
+ draw_background();
+ inner = newwin(LINES - 4, COLS - 4, 2, 2);
+ keypad(inner, TRUE);
+ draw_legend(inner);
+ menu_win = subwin(inner, LINES - 7 - 6, COLS - 4 - 5, 8, 5);
+ mymenu = create_menu(protected);
+ items_list = menu_items(mymenu);
+ set_menu_win(mymenu, inner);
+ set_menu_sub(mymenu, menu_win);
+ post_menu(mymenu);
+
+ for (i=0;i<item_ct;i++) {
+ set_item_value(items_list[i], tmp_index[i]);
+ }
+ set_current_item(mymenu, items_list[cur]);
+ free(tmp_index);
+ }
+ break;
+ }
+ if (menu_changed) {
+ remove_menu(mymenu);
+ draw_legend(inner);
+ mymenu = create_menu(protected);
+ items_list = menu_items(mymenu);
+ set_menu_win(mymenu, inner);
+ set_menu_sub(mymenu, menu_win);
+ post_menu(mymenu);
+ menu_changed = FALSE;
+ }
+ touchwin(inner);
+ wrefresh(inner);
+ }
+ endwin();
+ remove_menu(mymenu);
+
+ if (merged_updates_ct > 0) {
+ fprintf(stdout, ">>> Merged updates for the following files:\n");
+ for (i=0;i<merged_updates_ct;i++) {
+ fprintf(stdout, "\t%s\n", merged_updates_report[i]);
+ free(merged_updates_report[i]);
+ }
+ free(merged_updates_report);
+ }
+ if (removed_updates_ct > 0) {
+ fprintf(stdout, ">>> Deleted updates for the following files:\n");
+ for (i=0;i<removed_updates_ct;i++) {
+ fprintf(stdout, "\t%s\n", removed_updates_report[i]);
+ free(removed_updates_report[i]);
+ }
+ free(removed_updates_report);
+ }
+
+ for (i=0;!is_last_entry(protected[i]);i++) {
+ if (is_valid_entry(protected[i])) {
+ free(protected[i]);
+ }
+ }
+ free(protected);
+ if (config.pager) {
+ free(config.pager);
+ }
+ if (config.diff_tool) {
+ free(config.diff_tool);
+ }
+ if (config.merge_tool) {
+ free(config.merge_tool);
+ }
+ free(config.edit_tool);
+ free(config_protect);
+ fprintf(stderr, ">>> Nothing left to do... Bye!\n");
+ exit(EXIT_SUCCESS);
+}