Esempio n. 1
0
File: bloom.c Progetto: hagemt/bloom
int
main(int argc, char *argv[])
{
	size_t path_len, total_files;
	off_t bytes_wasted, total_wasted;
	char path_buffer[PATH_MAX_LEN], *hash_value;
	struct file_entry_t *file_entry, *trie_entry;

	SListIterator slist_iterator;
	SetIterator set_iterator;

	/* Step 0: Session data */
	struct file_info_t file_info;
	clear_info(&file_info);

	/* Step 1: Parse arguments */
	while (--argc) {
		/* Being unable to record implies insufficient resources */
		if (!record(argv[argc], &file_info)){
			fprintf(stderr, "[FATAL] out of memory\n");
			destroy_info(&file_info);
			return (EXIT_FAILURE);
		}
	}

	/* Step 2: Fully explore any directories specified */
	#ifndef NDEBUG
	printf("[DEBUG] Creating file list...\n");
	#endif
	while (slist_length(file_info.file_stack) > 0) {
		/* Pick off the top of the file stack */
		file_entry = (struct file_entry_t *)(slist_data(file_info.file_stack));
		slist_remove_entry(&file_info.file_stack, file_info.file_stack);
		assert(file_entry->type == DIRECTORY);
		/* Copy the basename to a buffer */
		memset(path_buffer, '\0', PATH_MAX_LEN);
		path_len = strnlen(file_entry->path, PATH_MAX_LEN);
		memcpy(path_buffer, file_entry->path, path_len);
		/* Ignore cases that would cause overflow */
		if (path_len < PATH_MAX_LEN) {
			/* Append a trailing slash */
			path_buffer[path_len] = '/';
			/* Record all contents (may push onto file stack or one of the lists) */
			DIR *directory = opendir(file_entry->path);
			if (traverse(&file_info, directory, path_buffer, ++path_len)) {
				fprintf(stderr, "[FATAL] out of memory\n");
				destroy_info(&file_info);
				return (EXIT_FAILURE);
			} else if (closedir(directory)) {
				fprintf(stderr, "[WARNING] '%s' (close failed)\n", file_entry->path);
			}
		}
		/* Discard this entry */
		destroy_entry(file_entry);
	}

	/* Step 3: Warn about any ignored files */
	if (slist_length(file_info.bad_files) > 0) {
		slist_iterate(&file_info.bad_files, &slist_iterator);
		while (slist_iter_has_more(&slist_iterator)) {
			file_entry = slist_iter_next(&slist_iterator);
			fprintf(stderr, "[WARNING] '%s' ", file_entry->path);
			switch (file_entry->type) {
			case INVALID:
				++file_info.invalid_files;
				fprintf(stderr, "(invalid file)\n");
				break;
			case INACCESSIBLE:
				++file_info.protected_files;
				fprintf(stderr, "(protected file)\n");
				break;
			default:
				++file_info.irregular_files;
				fprintf(stderr, "(irregular file)\n");
				break;
			}
		}
		fprintf(stderr, "[WARNING] %lu file(s) ignored\n",
			(long unsigned)(num_errors(&file_info)));
	}
	#ifndef NDEBUG
	if (num_errors(&file_info) > 0) {
		fprintf(stderr, "[FATAL] cannot parse entire file tree\n");
		destroy_info(&file_info);
		return (EXIT_FAILURE);
	}
	printf("[DEBUG] Found %lu / %lu valid files\n",
		(unsigned long)(num_files(&file_info)),
		(unsigned long)(file_info.total_files));
	#endif

	/* Step 4: Begin the filtering process */
	#ifndef NDEBUG
	printf("[DEBUG] Creating file table...\n");
	#endif
	if (slist_length(file_info.good_files) > 0) {
		file_info.hash_trie = trie_new();
		file_info.shash_trie = trie_new();
		optimize_filter(&file_info);
		/* Extract each file from the list (they should all be regular) */
		slist_iterate(&file_info.good_files, &slist_iterator);
		while (slist_iter_has_more(&slist_iterator)) {
			file_entry = slist_iter_next(&slist_iterator);
			assert(file_entry->type == REGULAR);
			/* Perform a "shallow" hash of the file */
			hash_value = hash_entry(file_entry, SHALLOW);
			#ifndef NDEBUG
			printf("[SHASH] %s\t*%s\n", file_entry->path, hash_value);
			#endif
			/* Check to see if we might have seen this file before */
			if (bloom_filter_query(file_info.shash_filter, hash_value)) {
				/* Get the full hash of the new file */
				hash_value = hash_entry(file_entry, FULL);
				#ifndef NDEBUG
				printf("[+HASH] %s\t*%s\n", file_entry->path, hash_value);
				#endif
				archive(&file_info, file_entry);
				/* Check to see if bloom failed us */
				trie_entry = trie_lookup(file_info.shash_trie, file_entry->shash);
				if (trie_entry == TRIE_NULL) {
					#ifndef NDEBUG
					printf("[DEBUG] '%s' (false positive)\n", file_entry->path);
					#endif
					trie_insert(file_info.shash_trie, file_entry->shash, file_entry);
				} else {
					/* Get the full hash of the old file */
					hash_value = hash_entry(trie_entry, FULL);
					#ifndef NDEBUG
					if (hash_value) {
						printf("[-HASH] %s\t*%s\n", trie_entry->path, hash_value);
					}
					#endif
					archive(&file_info, trie_entry);
				}
			} else {
				/* Add a record of this shash to the filter */
				bloom_filter_insert(file_info.shash_filter, hash_value);
				trie_insert(file_info.shash_trie, hash_value, file_entry);
			}
		}
		persist("bloom_store", &file_info);
	}

	/* Step 5: Output results and cleanup before exit */
	printf("[EXTRA] Found %lu sets of duplicates...\n",
		(unsigned long)(slist_length(file_info.duplicates)));
	slist_iterate(&file_info.duplicates, &slist_iterator);
	for (total_files = total_wasted = bytes_wasted = 0;
		slist_iter_has_more(&slist_iterator);
		total_wasted += bytes_wasted)
	{
		Set *set = slist_iter_next(&slist_iterator);
		int size = set_num_entries(set);
		if (size < 2) { continue; }
		printf("[EXTRA] %lu files (w/ same hash):\n", (unsigned long)(size));
		set_iterate(set, &set_iterator);
		for (bytes_wasted = 0;
			set_iter_has_more(&set_iterator);
			bytes_wasted += file_entry->size,
			++total_files)
		{
			file_entry = set_iter_next(&set_iterator);
			printf("\t%s (%lu bytes)\n",
				file_entry->path,
				(unsigned long)(file_entry->size));
		}
	}
	printf("[EXTRA] %lu bytes in %lu files (wasted)\n",
		(unsigned long)(total_wasted),
		(unsigned long)(total_files));
	destroy_info(&file_info);
	return (EXIT_SUCCESS);
}
Esempio n. 2
0
/* Main execution loop in live mode. Builds the list of processes,
 * collects statistics, and prints using curses. Repeats after some
 * delay, also catching key presses.
 */
static int live_mode(struct process_list* proc_list, screen_t* screen)
{
  WINDOW*         help_win = NULL;
  WINDOW*         error_win = NULL;
  fd_set          fds;
  struct process** p;
  int             num_iter = 0;
  int             with_colors = 0;
  int             pos;

  /* start curses */
  initscr();
  cbreak();
  noecho();
  keypad(stdscr, TRUE);

  /* Prepare help window */
  help_win = prepare_help_win(screen);

  if (has_colors()) {
    /* initialize curses colors */
    with_colors = 1;
    start_color();
    init_pair(1, COLOR_BLACK, COLOR_WHITE);
    init_pair(2, COLOR_WHITE, COLOR_BLACK);
    init_pair(3, COLOR_GREEN, COLOR_BLACK);
    init_pair(4, COLOR_YELLOW, COLOR_BLACK);
    init_pair(5, COLOR_RED, COLOR_BLACK);
    attron(COLOR_PAIR(0));
  }

  tv.tv_sec = 0;
  tv.tv_usec = 200000; /* 200 ms for first iteration */

  header = gen_header(screen, &options, COLS - 1, active_col);

  pos = screen_pos(screen);

  for(num_iter=0; !options.max_iter || num_iter<options.max_iter; num_iter++) {
    int  i, zz, printed, num_fd, num_dead;

    /* print various info */
    erase();
    mvprintw(0, 0, "tiptop -");

    if ((num_errors() > 0) && (COLS >= 37))
      mvprintw(LINES-1, 30, "[errors]");
    if ((options.config_file == 1) && (COLS >= 60))
      mvprintw(0, COLS-60, "[conf]");
    if ((options.euid == 0) && (COLS >= 54))
      mvprintw(0, COLS-54, "[root]");
    if ((options.watch_uid != -1) && (COLS >= 48))
      mvprintw(0, COLS-48, "[uid]");
    if ((options.only_pid || options.only_name) && (COLS >= 43))
      mvprintw(0, COLS-43, "[pid]");
    if (options.show_kernel && (COLS >= 38))
      mvprintw(0, COLS-38, "[kernel]");
    if (options.sticky && (COLS >= 30))
      mvprintw(0, COLS-30, "[sticky]");
    if (options.show_threads && (COLS >= 22))
      mvprintw(0, COLS-22, "[threads]");
    if (options.idle && (COLS >= 13))
      mvprintw(0, COLS-13, "[idle]");
    if (options.debug && (COLS >= 7))
      mvprintw(0, COLS-7, "[debug]");

    if (options.show_epoch && (COLS >= 18))
      mvprintw(LINES-1, COLS-18, "Epoch: %u", time(NULL));

    if (options.show_timestamp)
      mvprintw(LINES-1, 0, "Iteration: %u", num_iter);

    /* print main header */
    if (with_colors)
      attron(COLOR_PAIR(1));
    mvprintw(3, 0, "%s", header);
    for(zz=strlen(header); zz < COLS-1; zz++)
      printw(" ");
    printw("\n");
    if (with_colors)
      attroff(COLOR_PAIR(1));

    /* update the list of processes/threads and accumulate info if needed */
    num_dead = update_proc_list(proc_list, screen, &options);

    if (!options.show_threads)
      accumulate_stats(proc_list);

    p = proc_list->proc_ptrs;

    /* prepare for select */
    FD_ZERO(&fds);
    FD_SET(STDIN_FILENO, &fds);

    /* generate the text version of all rows */
    build_rows(proc_list, screen, COLS - 1);

    /* sort by %CPU */
    qsort(p, proc_list->num_tids, sizeof(struct process*), sorting_fun);

    printed = 0;

    /* Iterate over all threads */
    for(i=0; i < proc_list->num_tids; i++) {

      if (p[i]->skip)
        continue;

      /* highlight watched process, if any */
      if (with_colors) {
        if (p[i]->dead) {
          attron(COLOR_PAIR(5));
        }
        else if ((p[i]->tid == options.watch_pid) ||
                 (options.watch_name && options.show_cmdline &&
                                strstr(p[i]->cmdline, options.watch_name)) ||
                 (options.watch_name && !options.show_cmdline &&
                                strstr(p[i]->name, options.watch_name)))
          attron(COLOR_PAIR(3));
      }

      if (options.show_threads || (p[i]->pid == p[i]->tid)) {
        printw("%s\n", p[i]->txt);
        printed++;
      }

      if (with_colors)
        attroff(COLOR_PAIR(3));

      if (printed >= LINES - 5)  /* stop printing at bottom of window */
        break;
    }

    mvprintw(1, 0, "Tasks: %3d total, %3d displayed",
             proc_list->num_tids, printed);
    if (options.sticky)
      printw(", %3d dead", num_dead);

    /* print the screen name, make sure it fits, or truncate */
    if (with_colors)
      attron(COLOR_PAIR(4));
    if (35 + 20 + 11 + strlen(screen->name) < COLS) {
      mvprintw(1, COLS - 11 - strlen(screen->name),
               "screen %2d: %s\n", pos, screen->name);
    }
    else if (COLS >= 35 + 20 + 11) {
      char screen_str[50] = { 0 };
      snprintf(screen_str, sizeof(screen_str) - 1, "%s\n", screen->name);
      screen_str[COLS - 35 - 20 - 11] = '\0';  /* truncate */
      mvprintw(1, 35+20, "screen %2d: %s", pos, screen_str);
    }
    if (with_colors)
      attroff(COLOR_PAIR(4));

    /* print message if any */
    if (message) {
      if (with_colors)
        attron(COLOR_PAIR(1));
      mvprintw(2, 0, "%s", message);
      if (with_colors)
        attroff(COLOR_PAIR(1));
      message = NULL;  /* reset message */
    }

    refresh();  /* display everything */
    if (options.error) {
      if (options.error == 1) {
        options.error = 2;
        show_error_win(error_win, printed);
      }
      else
        show_error_win(error_win, -1);
    }
    if (options.help)
      show_help_win(help_win, screen);

    if ((num_dead) && (!options.sticky))
      compact_proc_list(proc_list);

    /* wait some delay, or until a key is pressed */
    num_fd = select(1 + STDIN_FILENO, &fds, NULL, NULL, &tv);
    if (num_fd > 0) {
      int c = handle_key();
      if (c == 'q')
        break;
      if (c == '>') {
        if (active_col < screen->num_columns )
          active_col++;
        free(header);
        header = gen_header(screen, &options, COLS - 1, active_col);
      }
      if (c == '<') {
        if (active_col > -1)
          active_col--;
        free(header);
        header = gen_header(screen, &options, COLS - 1, active_col);
      }
      if (c == 'H') {
        if (options.show_threads) {
          reset_values(proc_list);
          message = "Show threads On";
        }
        else
          message = "Show threads Off";
      }
      if (c == 'U') {
        free(header);
        header = gen_header(screen, &options, COLS - 1, active_col);
      }
      if ((c == '+') || (c == '-') || (c == KEY_LEFT) || (c == KEY_RIGHT))
        return c;

      if ((c == 'u') || (c == 'K') || (c == 'p')) /* need to rebuild tasks list */
        return c;

      if (c == 'e') {
        if (options.error > 0) {
          options.error = 0;
          delwin(error_win);
          error_win = NULL;
        }
        else
          options.error = 1;
      }
    }
    tv.tv_sec = options.delay;
    tv.tv_usec = (options.delay - tv.tv_sec) * 1000000.0;
  }

  free(header);

  delwin(help_win);

  endwin();  /* stop curses */
  return 'q';
}