Example #1
0
/** \brief Main function.
 *
 * @param argc Number of arguments from the system.
 * @param argv Arguments from the system.
 * @return Program exit code.
 */
int main(int argc, char **argv)
{
	// Option arguments.
	static const struct option opts_long[] =
	{
		{ "2chan", no_argument, NULL, '2' },
		{ "benchmark", no_argument, NULL, 'h' },
		{ "enable-case", no_argument, NULL, 'c' },
		{ "help", no_argument, NULL, 'h' },
		{ "enable-leet", no_argument, NULL, 'l' },
		{ "generate", no_argument, NULL, 'g' },
		{ "nthreads", required_argument, NULL, 'n' },
		{ "progress-file", required_argument, NULL, 'p' },
		{ "start-from", required_argument, NULL, 's' },
		{ "wildcard", no_argument, NULL, 'w' },
		{ NULL, 0, 0, 0 }
	};
	static const char *opts_short = "2cbhlgn:p:s:w";

	// Local args.
	uint8_t enable_generate = 0,
					enable_leet = 0,
					enable_case = 0,
					enable_wildcard = 0;
	while(1)
	{
		int indexptr = 0;
		int opt = getopt_long(argc, argv, opts_short, opts_long, &indexptr);

		if(opt == -1)
		{
			break;
		}

		switch(opt)
		{
			case '2':
				if(einfo.name)
				{
					fputs("Tripcode algorithm may only be specified once.", stderr);
					exit_cleanup();
					return 1;
				}
				einfo = encrypt_info_2chan;
				break;

			case 'b':
				flag_print_benchmarks = 1;
				break;

			case 'c':
				enable_case = 1;
				break;

			case 'h':
				puts(usage);
				exit_cleanup();
				return 0;

			case 'l':
				enable_leet = 1;
				break;

			case 'g':
				enable_generate = 1;
				break;

			case 'n':
				thread_count = strtol(optarg, NULL, 10);
				if((thread_count == LONG_MAX) || (thread_count == LONG_MIN))
				{
					fprintf(stderr, "Invalid thread count: %i\n", (int)thread_count);
					exit_cleanup();
					return 1;
				}
				break;

			case 'p':
				if(progress_filename)
				{
					fputs("Progress file may only be specified once.", stderr);
					exit_cleanup();
					return 1;
				}
				progress_filename = strdup(optarg);
				break;

			case 's':
				if(current_tripcode)
				{
					fputs("Starting code may only be specified once.", stderr);
					exit_cleanup();
					return 1;
				}
				current_tripcode_len = strlen(optarg);
				current_tripcode = memdup(optarg, current_tripcode_len + 1);
				printf("Using starting code: %s\n", current_tripcode);
				break;

			case 'w':
				enable_wildcard = 1;
				break;

			default:
				puts(usage);
				exit_cleanup();
				return 1;
		}
	}

	while(optind < argc)
	{
		char *opt = argv[optind++];
		size_t len = strlen(opt);

		if(len > 0)
		{
			if(!search_tripcodes)
			{
				search_tripcodes = (tripcode_t*)malloc(sizeof(tripcode_t));
				search_tripcode_count = 1;
			}
			else
			{
				search_tripcodes =
					(tripcode_t*)realloc(search_tripcodes,
							sizeof(tripcode_t) * (++search_tripcode_count));
			}
			tripcode_t *trip = search_tripcodes + (search_tripcode_count - 1);
			trip->trip = (char*)memdup(opt, len + 1);
			trip->len = len;
		}
		else
		{
			fputs("Empty string are not valid searching.", stderr);
			return 1;
		}
	}

	// Sanity check for tripcode count.
	if(search_tripcode_count <= 0)
	{
		fprintf(stderr, "Please specify at least one tripcode.\n");
		return 1;
	}

	// If no algo selected yet, pick 2chan.
	if(!einfo.name)
	{
		einfo = encrypt_info_2chan;
	}
	printf("Using algorithm: %s\n", einfo.name);
	str_enumerate_init(einfo.search_space);

	// Thread cap based on search space size.
	{
		long int sspacesize = get_search_space_size();
		if(sspacesize < thread_count)
		{
			printf("WARNING: current search space limits to %i threads\n",
					(int)sspacesize);
			thread_count = sspacesize;
		}
	}

	// Decide character transform.
	if(!enable_generate)
	{
		char_transform_func = char_transform_identity;
		strstr_func = strstr_normal;
		printf("Using character transform: ");
		if(enable_case && !enable_leet && !enable_wildcard)
		{
			puts("none");
		}
		else
		{
			unsigned flag_line = 0;
			if(enable_case)
			{
				if(enable_leet)
				{
					flag_line = fprint_list_spacing(stdout, flag_line);
					printf("1337");
					char_transform_func = char_transform_leet;
				}
			}
			else
			{
				flag_line = fprint_list_spacing(stdout, flag_line);
				printf("case_insensitive");
				char_transform_func = char_transform_nocase;
				if(enable_leet)
				{
					flag_line = fprint_list_spacing(stdout, flag_line);
					printf("1337");
					char_transform_func = char_transform_nocase_leet;
				}
			}
			if(enable_wildcard)
			{
				flag_line = fprint_list_spacing(stdout, flag_line);
				printf("wildcard");
				strstr_func = strstr_wildcard;
			}
			puts("");
		}
	}

	// If generate trip requested, do it and exit.
	if(enable_generate)
	{
		for(size_t ii = 0; (ii < search_tripcode_count); ++ii)
		{
			tripcode_t *trip = search_tripcodes + ii;
			char *enc = einfo.encrypt_function(trip->trip, trip->len);
			printf("Password %s encrypts to tripcode %s\n",
					trip->trip,
					enc);
			free(enc);
		}

		exit_cleanup();
		return 0;
	}

	// Sanity check for tripcode lengths.
	for(size_t ii = 0; (ii < search_tripcode_count); ++ii)
	{
		tripcode_t *trip = search_tripcodes + ii;
		if(trip->len > einfo.max_code_length)
		{
			fprintf(stderr,
					"Code %s is %u chars long, too much for current algo (%u).\n",
					trip->trip,
					(unsigned)(trip->len),
					(unsigned)(einfo.max_code_length - 1));
			exit_cleanup();
			return 1;
		}

		// Perform case transform in precalc!
		for(size_t jj = 0; (jj < trip->len); ++jj)
		{
			trip->trip[jj] = (char)char_transform_func(trip->trip[jj]);
		}
	}

	// Only read current tripcode if it's not yet specified.
	if(progress_filename)
	{
		char *prog = progress_read(progress_filename);

		if(prog)
		{
			if(current_tripcode)
			{
				fprintf(stderr, "Not overwriting starting code from file: %s\n",
						prog);
				free(prog);
			}
			else
			{
				printf("Using starting code from file: %s\n", prog);
				current_tripcode = prog;
				current_tripcode_len = strlen(prog);
			}
		}
	}

	// Try the initial tripcode if it has been specified.
	int64_t benchmark_processed = 0;
	if(current_tripcode)
	{
		benchmark_processed +=
			einfo.test_function(current_tripcode, current_tripcode_len, stdout);
	}

	pthread_cond_init(&term_cond, NULL);
	pthread_mutex_init(&term_mutex, NULL);
	signal(SIGINT, tripcrunch_signal_handler);
	signal(SIGTERM, tripcrunch_signal_handler);

	// Enter critical section and create all threads.
	pthread_mutex_lock(&term_mutex);
	pthread_t *threads =
		(pthread_t*)malloc(sizeof(pthread_t) * (unsigned)thread_count);
	for(int ii = 0; (ii < thread_count); ++ii)
	{
		// Reserve the thread info for passing to the threads.
		thread_info_t *tinfo = (thread_info_t*)malloc(sizeof(thread_info_t));

		// Give the next tripcode to the string.
		current_tripcode =
			str_enumerate_1(current_tripcode, &current_tripcode_len);
		tinfo->trip.trip = memdup(current_tripcode, current_tripcode_len + 1);
		tinfo->trip.len = current_tripcode_len;
		int err =
			pthread_create(threads + ii, NULL, threadfunc_tripcrunch, tinfo);
		if(err)
		{
			fprintf(stderr, "ERROR %s\n", strerror(err));
			return 1; // Should never happen, okay to not clean up.
		}
	}

	// Wait for exit, then leave critical section.
	int64_t benchmark_start = get_current_time_int64();
	pthread_mutex_unlock(&term_mutex);

	// Immediately start joining the threads.
	for(int ii = 0; (ii < thread_count); ++ii)
	{
		void **thr_ret = NULL;
		pthread_join(threads[ii], thr_ret);
		if(!thr_ret)
		{
			fprintf(stderr, "ERROR: no return value from thread %i\n", ii);
			return 1; // Should never happen, okay to not clean up.
		}
		thread_info_t *tinfo = (thread_info_t*)(*thr_ret);


		char *trip = tinfo->trip.trip;
		size_t len = tinfo->trip.len;
		int64_t count = tinfo->count;
		printf("Thread %i: %s (%.0f trips)\n", ii, tinfo->trip.trip,
				(double)(tinfo->count));
		benchmark_processed += count;

		int cmp = str_enumcmp(current_tripcode, current_tripcode_len, trip, len);
		if((cmp > 0) || ((ii <= 0) && count))
		{
			free(current_tripcode);
			current_tripcode = memdup(trip, len + 1);
			current_tripcode_len = len;
		}

		free(trip);
		free(tinfo);
	}

	// All threads have been joined, time to end the benchmark and free the
	// thread table.
	int64_t benchmark_end = get_current_time_int64();
	free(threads);

	// Must save progress before other cleanup.
	if(progress_filename)
	{
		progress_save(progress_filename, current_tripcode);
	}

	// Current tripcode is not necessarily initialized.
	if(current_tripcode)
	{
		printf("Last search: %s\n", current_tripcode);
	}
	exit_cleanup();

	// Only print benchmarks if requested.
	if(flag_print_benchmarks)
	{
		double trips = (double)benchmark_processed,
		 			 secs = (double)(benchmark_end - benchmark_start) / 1000000.0;

		printf("Benchmark: %.0f trips / %.2f secs -> %.2f trips/sec\n",
				trips,
				secs,
				trips / secs);
	}

	pthread_cond_destroy(&term_cond);
	pthread_mutex_destroy(&term_mutex);
	return 0;
}
Example #2
0
File: main.c Project: rdebath/sgt
int main(int argc, char **argv) {
    char user[64];

    screen_init();
    if (setjmp(fatal_error_jmp_buf) == 0) {
	char *setname = DEFAULTSET;
	levelset *set;
	level *l;
	gamestate *gs;
	progress p;
	int i, action, n, saveslot = 0;
	gamestate *saves[10];

	get_user(user, sizeof(user));

	/*
	 * Pick up argv[1] in case it describes an alternate level
	 * set.
	 */
	if (argc > 1)
	    setname = argv[1];

	set = levelset_load(setname);
	p = progress_load(set, user);
	for (i = 0; i < 10; i++)
	    saves[i] = savepos_load(set, user, i);

	while (1) {
	    action = screen_main_menu(set, saves, p.levnum+1, p.levnum);
	    if (action > 0) {
		l = set->levels[action-1];
		gs = init_game(l);
		gs->levnum = action;
		saveslot = 0;
	    } else if (action == -100) {
		break;		       /* direct quit from main menu */
	    } else if (action <= -10) {
		/* delete a saved position */
		n = -action-10;
		if (saves[n])
		    gamestate_free(saves[n]);
		saves[n] = NULL;
		savepos_del(set, user, n);
		gs = NULL;
	    } else {
		/* load a saved position */
		n = -action;
		if (!saves[n])   /* don't segfault */
		    continue;
		gs = gamestate_copy(saves[n]);
		l = set->levels[gs->levnum-1];
		saveslot = n;
	    }
	    if (gs) {
		screen_level_init();
		while (gs->status == PLAYING) {
		    gamestate *newgs;
		    int k;
		    screen_level_display(gs, NULL);
		    k = screen_level_getmove();
		    if (k == 'h' || k == 'j' || k == 'l' || k == 'k') {
			newgs = make_move(gs, k);
			gamestate_free(gs);
			gs = newgs;
		    } else if (k == 's') {
			n = screen_saveslot_ask('s', saves, saveslot);
			if (n >= 0) {
			    saveslot = n;
			    saves[saveslot] = gamestate_copy(gs);
			    savepos_save(set, user, saveslot, gs);
			}
		    } else if (k == 'r') {
			n = screen_saveslot_ask('r', saves, saveslot);
			if (n >= 0 && saves[n]) {
			    saveslot = n;
			    gamestate_free(gs);
			    gs = gamestate_copy(saves[saveslot]);
			    l = set->levels[gs->levnum-1];
			}
		    } else if (k == 'q') {
			break;
		    }
		}
		if (gs->status != PLAYING) {
		    int increased_level = FALSE;
		    char *msg;
		    if (gs->status == DIED) {
			msg = "GAME OVER";
		    } else if (gs->status == COMPLETED) {
			msg = "LEVEL COMPLETE";
			if (p.levnum < gs->levnum) {
			    p.levnum = gs->levnum;
			    p.date = time(NULL);
			    progress_save(set, user, p);
			    increased_level = TRUE;
			}
		    } else {
			msg = "!INTERNAL ERROR!";
		    }
		    screen_level_display(gs, msg);
		    screen_level_finish();
		    if (increased_level && p.levnum == set->nlevels) {
			screen_completed_game();
		    }
		}
	    }
	}
    } else {
	screen_finish();
	fprintf(stderr, "Fatal error: %s\n", fatal_error_string);
	exit(2);
    }
    screen_finish();
    return 0;
}