char *minibuf_read_variable_name(char *msg)
{
	char *ms;
	historyp hp;

	hp = make_variable_history();

	for (;;) {
		ms = minibuf_read_history(msg, "", hp);

		if (ms == NULL) {
			free_history(hp);
			cancel();
			return NULL;
		}

		if (ms[0] == '\0') {
			free_history(hp);
			minibuf_error("No variable name given");
			return NULL;
		} else if (get_variable(ms) == NULL) {
			minibuf_error("Undefined variable name");
			waitkey(2 * 1000);
		} else {
			minibuf_clear();
			break;
		}
	}

	free_history(hp);

	return ms;
}
Example #2
0
static void rline_set_history_intrinsic (void)
{
   int i, num;
   char **data;
   SLrline_Type *rli;
   SLang_Array_Type *at;

   if (-1 == SLang_pop_array_of_type (&at, SLANG_STRING_TYPE))
     return;

   if (NULL == (rli = Active_Rline_Info))
     {
	SLang_free_array (at);
	return;
     }
   
   free_history (rli->root);
   rli->tail = rli->root = rli->last = NULL;

   data = (char **)at->data;
   num = at->num_elements;
   for (i = 0; i < num; i++)
     {
	if (-1 == SLrline_add_to_history (rli, data[i]))
	  break;
     }
   SLang_free_array (at);
}
Example #3
0
int main(int argc, char const *argv[])
{
	// Create input line and start command history
	char input_line[LINE_MAX];
	init_commandHistory();
	// for handling signals
	signal (SIGINT, SIG_IGN);
	signal (SIGINT, handle_signal);

	// Welcome screen with description of built in commands
	printf("/****************************************/ \n");
	printf("/*	Welcome to David Cosman Shell	*/ \n");
	printf("/* exit: quit shell			*/ \n");
	printf("/* history: display last 10 commands	*/ \n");
	printf("/****************************************/ \n");
	for (;;) {
		// input prompt
		printf("\nDavidCosman> ");
		
		// Read command and give to history
		fgets(input_line, sizeof(input_line) / sizeof(char), stdin);
		
		// put history item here
		char* history_entry = create_commandHistory_entry(input_line);
		
		int input_stream = 0;			// store input stream here
		char* cmd = input_line;			// pointer to command from input_line
		char* nextPipe = strchr (cmd, '|');	// go to next piped command
		bool isFirst = true;			// bool to keep track of first command in input_line
		
		// If there are pipes, then run this:
		while ( nextPipe != NULL) {
			*nextPipe = '\0';
			struct commandType command = {
				.line = cmd,
				.firstCommand = isFirst,
				.lastCommand = false
			};
			input_stream = run (&command, input_stream);
			// go to next piped command
			cmd = nextPipe + 1;
			nextPipe = strchr(cmd, '|');
			isFirst = false;
		}
		
		// Run last command
		struct commandType command = {
			.line = cmd,
			.firstCommand = isFirst,
			.lastCommand = true
		};
		run (&command, input_stream);
		add_commandHistory_entry (history_entry);

	}
	printf("\n");
	// clean up here
	free_history();
	return EXIT_SUCCESS;
}
Example #4
0
void MYMENU_FileOpen()
{
    OPENFILENAMEA ofn;
    ZeroMemory( &ofn, sizeof( ofn ) );
    
    ofn.lStructSize = sizeof( ofn ); // SEE NOTE BELOW
    ofn.hwndOwner = hwnd;
    ofn.lpstrFilter = "CSV Files (*.csv)\0*.csv\0Kiss Files (*.kiss)\0*.kiss\0All Files (*.*)\0*.*\0";
    ofn.lpstrFile = szFileName;
    ofn.nMaxFile = MAX_PATH;
    ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
    ofn.lpstrDefExt = "csv";
    
    if ( GetOpenFileName( &ofn ) ) {
        if ( prompt_save_changes() ) {
            FILE* fp = fopen( szFileName, "r" );
            if ( fp == NULL )
                return;
            free_table( table );
            free_history();
            // parse
            table = create_table();
            if ( strncmp( ofn.lpstrFile + ofn.nFileExtension, "csv", 3 ) == 0 )
                import_csv( fp, table );
            else if ( strncmp( ofn.lpstrFile + ofn.nFileExtension, "kiss", 4 ) == 0 )
                import_kiss( fp, table );
            fclose( fp );
            set_caption( szFileName );
            auto_adapt_layout( table );
            update_selection_rect();
            update_table_view( hwnd );
            unsaved = 0;
        }
    }
}
Example #5
0
void SLrline_close (SLrline_Type *rli)
{
   if (rli == NULL)
     return;
   
   if (rli->name != NULL)
     {
	char hookname[1024];
	SLrline_Type *arli = Active_Rline_Info;
	Active_Rline_Info = rli;
	SLsnprintf (hookname, sizeof(hookname), "%s_rline_close_hook", rli->name);
	if (0 == SLang_run_hooks (hookname, 0))
	  (void) SLang_run_hooks ("rline_close_hook", 1, rli->name);
	Active_Rline_Info = arli;
	SLang_free_slstring (rli->name);
     }

   free_history (rli->root);
   free_history_item (rli->saved_line);
   SLang_free_function (rli->list_completions_callback);
   SLang_free_function (rli->completion_callback);
   SLfree ((char *)rli->prompt);
   SLfree ((char *)rli->buf);
   SLfree ((char *)rli);
}
Example #6
0
void	free_history(t_cmd_list *list)
{
  if (list)
    {
      if (list->next)
        free_history(list->next);
      free_string(list->cmd);
      free(list->str);
      free(list);
    }
}
Example #7
0
void MYMENU_FileNew()
{
    free_table( table );
    free_history();
    // a new table
    table = create_table();
    set_caption( NULL );
    restore_view();
    update_row_tails();
    update_col_tails();
    update_selection_rect();
    update_table_view( hwnd );
    unsaved = 1;
}
t_history	*history_list_config(t_config *config,
				     t_history *history, int flag)
{
  int	size;
  t_history *tmp;

  size = 0;
  tmp = history;
  if (!flag)
    if (history_file_config(config, history))
      return (NULL);
  while (tmp && tmp->prev && config && config->option
	 && config->option[SAVEHIST] > size)
    {
      tmp = tmp->prev;
      ++size;
    }
  if (tmp && tmp->next && tmp->prev && tmp->prev->prev)
    tmp->next->prev = free_history(tmp);
  return (history);
}
Example #9
0
static int judge_backwards(struct gspan *gs, GList *right_most_path, GList *projection,
						GHashTable *pm_backwards)
{
	GList *l1, *l2, *l3, *values = NULL;
	int i;
	int rmp0;

	rmp0 = 	GPOINTER_TO_INT(g_list_nth_data(right_most_path, 0));

	for (i=g_list_length(right_most_path)-2,l1=g_list_last(right_most_path);
					i >= 0; i--, l1 = g_list_previous(l1)) {
		int rmp = GPOINTER_TO_INT(l1->data);
		int rmpi = GPOINTER_TO_INT(g_list_nth_data(right_most_path, i));


		for(l2 = g_list_first(projection); l2; l2 = g_list_next(l2)) {
			struct pre_dfs *p = (struct pre_dfs *)l2->data;
			struct history *h;
			struct edge *last_edge;
			struct node *last_node, *to_node, *from_node;
			struct edge *edge;
			
			h = alloc_history();
			build_history(h, p);

			last_edge = (struct edge *)
					g_list_nth_data(h->edges, rmp0);
			last_node = graph_get_node(gs->min_graph, 
								last_edge->to);
			edge = (struct edge *)
					g_list_nth_data(h->edges, rmpi);
			to_node = graph_get_node(gs->min_graph, edge->to);
			from_node = graph_get_node(gs->min_graph, edge->from);

			for (l3 = g_list_first(last_node->edges); l3; 
							l3 = g_list_next(l3)) {
				struct edge *e = (struct edge *)l3->data;

				if (g_list_find(h->has_edges, 
							GINT_TO_POINTER(e->id)))
					continue;

				if (!g_list_find(h->has_nodes, 
							GINT_TO_POINTER(e->to)))
					continue;

				if (e->to == edge->from && 
						(e->label > edge->label || 
						(e->label == edge->label &&
							last_node->label > 
							to_node->label))) {
					struct dfs_code *dfsc;
					struct pre_dfs *npdfs;
					int from_id;
					int to_id;

					from_id = ((struct dfs_code *)
							g_list_nth_data(
							gs->min_dfs_codes, 
							rmp0))->to;

					to_id = ((struct dfs_code *)
							g_list_nth_data(
							gs->min_dfs_codes,
							rmpi))->from;
#ifdef DEBUG
					printf("!! %d %d %d ", i, rmp, rmpi);
					print_dfs(g_list_nth_data(
							gs->min_dfs_codes,
							rmpi));
					printf("\n");
					print_id_list(right_most_path);
#endif
					dfsc = malloc(sizeof(struct dfs_code));
					if (!dfsc) {
						perror("malloc dfsc in jb()");
						exit(1);
					}
					dfsc->from = from_id;
					dfsc->to = to_id;
					dfsc->from_label = last_node->label;
					dfsc->edge_label = e->label;
					dfsc->to_label = from_node->label;

					npdfs = malloc(sizeof(struct pre_dfs));
					if (!npdfs) {
						perror("malloc npdfs in jb()");
						exit(1);
					}
					npdfs->id = 0;
					npdfs->edge = e;
					npdfs->prev = p;

					if (g_hash_table_contains(pm_backwards, 
									dfsc))
						values = g_hash_table_lookup(
							pm_backwards,dfsc);
					values = g_list_append(values, npdfs);
					g_hash_table_insert(pm_backwards, dfsc,
									values);
					values = NULL;

				}
			}
			free_history(h);
		}

		if (g_hash_table_size(pm_backwards) > 0)
			return 1;
	}

	return 0;
}
Example #10
0
static int judge_forwards(struct gspan *gs, GList *right_most_path, GList *projection,
					GHashTable *pm_forwards, int min_label)
{
	int rmp0;
	struct history *h;
	GList *l1, *l2, *l3, *l4, *values = NULL;

	rmp0 = 	GPOINTER_TO_INT(g_list_nth_data(right_most_path, 0));

	for(l1 = g_list_first(projection); l1; l1 = g_list_next(l1)) {
		struct pre_dfs *p = (struct pre_dfs *)l1->data;
		struct node *last_node;
		struct edge *last_edge;
	
		h = alloc_history();
		build_history(h,p);

		last_edge = g_list_nth_data(h->edges, rmp0);
		last_node = graph_get_node(gs->min_graph, last_edge->to);
		for (l2 = g_list_first(last_node->edges); l2; 
						l2 = g_list_next(l2)) {
			struct edge *e = (struct edge *)l2->data;
			struct node *to_node;
			struct dfs_code *dfsc;
			struct pre_dfs *npdfs;
			int to_id;
			
			to_node = graph_get_node(gs->min_graph, e->to);

			if (g_list_find(h->has_nodes, 
						GINT_TO_POINTER(e->to)) || 
						to_node->label < min_label) {
#ifdef DEBUG
				printf("here1\n");
#endif
				continue;
			}
			
			to_id = ((struct dfs_code *)g_list_nth_data(
						gs->min_dfs_codes, rmp0))->to;

			dfsc = malloc(sizeof(struct dfs_code));
			if (!dfsc) {
				perror("malloc dfsc in jf()");
				exit(1);
			}
			dfsc->from = to_id;
			dfsc->to = to_id + 1;
			dfsc->from_label = last_node->label;
			dfsc->edge_label = e->label;
			dfsc->to_label = to_node->label;

			npdfs = malloc(sizeof(struct pre_dfs));
			if (!npdfs) {
				perror("malloc npdfs in jf()");
				exit(1);
			}
			npdfs->id = 0;
			npdfs->edge = e;
			npdfs->prev = p;

			if (g_hash_table_contains(pm_forwards, dfsc))
				values = g_hash_table_lookup(
							pm_forwards,dfsc);
			values = g_list_append(values, npdfs);
			g_hash_table_insert(pm_forwards, dfsc, values);
			values = NULL;

		}

		free_history(h);
	}

	
	if (g_hash_table_size(pm_forwards) == 0) {
		for(l1 = g_list_first(right_most_path); l1; 
							l1 = g_list_next(l1)) {
			int rmp = GPOINTER_TO_INT(l1->data);
			
			for (l2=g_list_first(projection); l2; l2 = g_list_next(l2)) {
				struct pre_dfs *p = (struct pre_dfs *)l2->data;
				struct edge *cur_edge;
				struct node *cur_node;
				struct node *cur_to;

				h = alloc_history();
				build_history(h, p);

				cur_edge = g_list_nth_data(h->edges, rmp);
				cur_node = graph_get_node(gs->min_graph, 
								cur_edge->from);
				cur_to = graph_get_node(gs->min_graph, 
								cur_edge->to);

				for (l3 = g_list_first(cur_node->edges); l3;
							l3 = g_list_next(l3)) {
					struct edge *e = (struct edge *)l3->data;
					struct node *to_node;
					
					to_node = graph_get_node(gs->min_graph, e->to);

					if (cur_edge->to == to_node->id || 
							g_list_find(h->has_nodes, 
									GINT_TO_POINTER(to_node->id)) || 
									to_node->label < min_label) {
#ifdef DEBUG
						printf("here2\n");
#endif
						continue;
					}

					if (cur_edge->label < e->label || 
							(cur_edge->label == e->label &&
							cur_to->label <= to_node->label)) {
						int from_id, to_id;
						struct dfs_code *dfsc;
						struct pre_dfs *npdfs;
						

						from_id = ((struct dfs_code *)g_list_nth_data(
								gs->min_dfs_codes, rmp))->from;

						to_id = ((struct dfs_code *)g_list_nth_data(
								gs->min_dfs_codes, rmp0))->to;

						dfsc = malloc(sizeof(struct dfs_code));
						if (!dfsc) {
							perror("malloc dfsc in jf()");
							exit(1);
						}
						dfsc->from = from_id;
						dfsc->to = to_id + 1;
						dfsc->from_label = cur_node->label;
						dfsc->edge_label = e->label;
						dfsc->to_label = to_node->label;

						npdfs = malloc(sizeof(struct pre_dfs));
						if (!npdfs) {
							perror("malloc npdfs in jf()");
							exit(1);
						}
						npdfs->id = 0;
						npdfs->edge = e;
						npdfs->prev = p;

						if (g_hash_table_contains(pm_forwards, dfsc))
							values = g_hash_table_lookup(
									pm_forwards,dfsc);
						values = g_list_append(values, npdfs);
						g_hash_table_insert(pm_forwards, dfsc, values);
						values = NULL;
					}
				}

				free_history(h);
			}

			if (g_hash_table_size(pm_forwards) > 0) 
				break;
		}
	}

	if (g_hash_table_size(pm_forwards) > 0) 
		return 1;
	return 0;
}
Example #11
0
File: save.c Project: mbi/NitroHack
void freedynamicdata(void)
{
	int i;
	struct level *lev;
	
	if (!objects)
	    return; /* no cleanup necessary */
	
	unload_qtlist();
	free_invbuf();	/* let_to_name (invent.c) */
	free_youbuf();	/* You_buf,&c (pline.c) */
	tmp_at(DISP_FREEMEM, 0);	/* temporary display effects */
# define free_animals()	 mon_animal_list(FALSE)

	for (i = 0; i < MAXLINFO; i++) {
	    lev = levels[i];
	    levels[i] = NULL;
	    if (!lev) continue;
	    
	    /* level-specific data */
	    dmonsfree(lev);	/* release dead monsters */
	    free_timers(lev);
	    free_light_sources(lev);
	    free_monchn(lev->monlist);
	    free_worm(lev);		/* release worm segment information */
	    freetrapchn(lev->lev_traps);
	    free_objchn(lev->objlist);
	    free_objchn(lev->buriedobjlist);
	    free_objchn(lev->billobjs);
	    free_engravings(lev);
	    freedamage(lev);
	    
	    free(lev);
	}

	/* game-state data */
	free_objchn(invent);
	free_objchn(migrating_objs);
	free_monchn(migrating_mons);
	free_monchn(mydogs);		/* ascension or dungeon escape */
	free_animals();
	free_oracles();
	freefruitchn();
	freenames();
	free_waterlevel();
	free_dungeon();
	free_history();

	if (iflags.ap_rules) {
	    free(iflags.ap_rules->rules);
	    iflags.ap_rules->rules = NULL;
	    free(iflags.ap_rules);
	}
	iflags.ap_rules = NULL;
	free(artilist);
	free(objects);
	objects = NULL;
	artilist = NULL;
	
	if (active_birth_options)
	    free_optlist(active_birth_options);
	active_birth_options = NULL;
	
	return;
}
Example #12
0
int
main(int argc, char **argv)
{
	char dbpath[PATH_MAX] = "/tmp/tesla.rrd";
	libusb_context *ctx = NULL;
	libusb_device_handle *dev_handle = NULL;

	signal(SIGINT, sigint_handler);

	int c = 0;
	while ((c = getopt(argc, argv, "hd")) != -1) {
		switch (c) {
		case 'd':
			++_debug;
			break;
		case 'h':
		default:
			usage();
			return 0;
		}
	}
	argc -= optind;
	argv += optind;

	if (argc == 1)
		realpath(argv[0], dbpath);

	if (access(dbpath, F_OK) == -1) {
		DPRINTF(1, "Creating db: %s\n", dbpath);
		if (RRD_create(dbpath, 60))
			return -1;
	}
	DPRINTF(2, "Using DB: %s\n", dbpath);

	DPRINTF(1, "Please plug your CM160 device...\n");
	if (scan_usb(ctx, &dev_handle))
		return 1;

	if (prepare_device(dev_handle))
		return 1;

	DPRINTF(1, "Start acquiring data...\n");

	struct record_history *hist;
	if (init_history(&hist))
		return 1;

	while (!stop)
		if (get_data(dbpath, hist, dev_handle))
			stop = 1;

	DPRINTF(2, "\nClosing connection with the device\n");
	if (libusb_release_interface(dev_handle, INTERFACE))
		fprintf(stderr, "Cannot release interface.\n");
	libusb_reset_device(dev_handle);
	libusb_close(dev_handle);
	libusb_exit(ctx);

	free_history(&hist);
	return 0;
}
Example #13
0
int	remove_history(t_history **history)
{
  free_history((*history));
  (*history) = NULL;
  return (0);
}
Example #14
0
static int scrub_start(int argc, char **argv, int resume)
{
	int fdmnt;
	int prg_fd = -1;
	int fdres = -1;
	int ret;
	pid_t pid;
	int c;
	int i;
	int err = 0;
	int e_uncorrectable = 0;
	int e_correctable = 0;
	int print_raw = 0;
	char *path;
	int do_background = 1;
	int do_wait = 0;
	int do_print = 0;
	int do_quiet = 0;
	int do_record = 1;
	int readonly = 0;
	int do_stats_per_dev = 0;
	int ioprio_class = IOPRIO_CLASS_IDLE;
	int ioprio_classdata = 0;
	int n_start = 0;
	int n_skip = 0;
	int n_resume = 0;
	struct btrfs_ioctl_fs_info_args fi_args;
	struct btrfs_ioctl_dev_info_args *di_args = NULL;
	struct scrub_progress *sp = NULL;
	struct scrub_fs_stat fs_stat;
	struct timeval tv;
	struct sockaddr_un addr = {
		.sun_family = AF_UNIX,
	};
	pthread_t *t_devs = NULL;
	pthread_t t_prog;
	struct scrub_file_record **past_scrubs = NULL;
	struct scrub_file_record *last_scrub = NULL;
	char *datafile = strdup(SCRUB_DATA_FILE);
	char fsid[BTRFS_UUID_UNPARSED_SIZE];
	char sock_path[PATH_MAX] = "";
	struct scrub_progress_cycle spc;
	pthread_mutex_t spc_write_mutex = PTHREAD_MUTEX_INITIALIZER;
	void *terr;
	u64 devid;
	DIR *dirstream = NULL;
	int force = 0;
	int nothing_to_resume = 0;

	while ((c = getopt(argc, argv, "BdqrRc:n:f")) != -1) {
		switch (c) {
		case 'B':
			do_background = 0;
			do_wait = 1;
			do_print = 1;
			break;
		case 'd':
			do_stats_per_dev = 1;
			break;
		case 'q':
			do_quiet = 1;
			break;
		case 'r':
			readonly = 1;
			break;
		case 'R':
			print_raw = 1;
			break;
		case 'c':
			ioprio_class = (int)strtol(optarg, NULL, 10);
			break;
		case 'n':
			ioprio_classdata = (int)strtol(optarg, NULL, 10);
			break;
		case 'f':
			force = 1;
			break;
		case '?':
		default:
			usage(resume ? cmd_scrub_resume_usage :
						cmd_scrub_start_usage);
		}
	}

	/* try to catch most error cases before forking */

	if (check_argc_exact(argc - optind, 1)) {
		usage(resume ? cmd_scrub_resume_usage :
					cmd_scrub_start_usage);
	}

	spc.progress = NULL;
	if (do_quiet && do_print)
		do_print = 0;

	if (mkdir_p(datafile)) {
		warning_on(!do_quiet,
    "cannot create scrub data file, mkdir %s failed: %s. Status recording disabled",
			datafile, strerror(errno));
		do_record = 0;
	}
	free(datafile);

	path = argv[optind];

	fdmnt = open_path_or_dev_mnt(path, &dirstream, !do_quiet);
	if (fdmnt < 0)
		return 1;

	ret = get_fs_info(path, &fi_args, &di_args);
	if (ret) {
		error_on(!do_quiet,
			"getting dev info for scrub failed: %s",
			 strerror(-ret));
		err = 1;
		goto out;
	}
	if (!fi_args.num_devices) {
		error_on(!do_quiet, "no devices found");
		err = 1;
		goto out;
	}

	uuid_unparse(fi_args.fsid, fsid);
	fdres = scrub_open_file_r(SCRUB_DATA_FILE, fsid);
	if (fdres < 0 && fdres != -ENOENT) {
		warning_on(!do_quiet, "failed to open status file: %s",
			strerror(-fdres));
	} else if (fdres >= 0) {
		past_scrubs = scrub_read_file(fdres, !do_quiet);
		if (IS_ERR(past_scrubs))
			warning_on(!do_quiet, "failed to read status file: %s",
				strerror(-PTR_ERR(past_scrubs)));
		close(fdres);
	}

	/*
	 * Check for stale information in the status file, ie. if it's
	 * canceled=0, finished=0 but no scrub is running.
	 */
	if (!is_scrub_running_in_kernel(fdmnt, di_args, fi_args.num_devices))
		force = 1;

	/*
	 * check whether any involved device is already busy running a
	 * scrub. This would cause damaged status messages and the state
	 * "aborted" without the explanation that a scrub was already
	 * running. Therefore check it first, prevent it and give some
	 * feedback to the user if scrub is already running.
	 * Note that if scrub is started with a block device as the
	 * parameter, only that particular block device is checked. It
	 * is a normal mode of operation to start scrub on multiple
	 * single devices, there is no reason to prevent this.
	 */
	if (!force && is_scrub_running_on_fs(&fi_args, di_args, past_scrubs)) {
		error_on(!do_quiet,
			"Scrub is already running.\n"
			"To cancel use 'btrfs scrub cancel %s'.\n"
			"To see the status use 'btrfs scrub status [-d] %s'",
			path, path);
		err = 1;
		goto out;
	}

	t_devs = malloc(fi_args.num_devices * sizeof(*t_devs));
	sp = calloc(fi_args.num_devices, sizeof(*sp));
	spc.progress = calloc(fi_args.num_devices * 2, sizeof(*spc.progress));

	if (!t_devs || !sp || !spc.progress) {
		error_on(!do_quiet, "scrub failed: %s", strerror(errno));
		err = 1;
		goto out;
	}

	for (i = 0; i < fi_args.num_devices; ++i) {
		devid = di_args[i].devid;
		ret = pthread_mutex_init(&sp[i].progress_mutex, NULL);
		if (ret) {
			error_on(!do_quiet, "pthread_mutex_init failed: %s",
				strerror(ret));
			err = 1;
			goto out;
		}
		last_scrub = last_dev_scrub(past_scrubs, devid);
		sp[i].scrub_args.devid = devid;
		sp[i].fd = fdmnt;
		if (resume && last_scrub && (last_scrub->stats.canceled ||
					     !last_scrub->stats.finished)) {
			++n_resume;
			sp[i].scrub_args.start = last_scrub->p.last_physical;
			sp[i].resumed = last_scrub;
		} else if (resume) {
			++n_skip;
			sp[i].skip = 1;
			sp[i].resumed = last_scrub;
			continue;
		} else {
			++n_start;
			sp[i].scrub_args.start = 0ll;
			sp[i].resumed = NULL;
		}
		sp[i].skip = 0;
		sp[i].scrub_args.end = (u64)-1ll;
		sp[i].scrub_args.flags = readonly ? BTRFS_SCRUB_READONLY : 0;
		sp[i].ioprio_class = ioprio_class;
		sp[i].ioprio_classdata = ioprio_classdata;
	}

	if (!n_start && !n_resume) {
		if (!do_quiet)
			printf("scrub: nothing to resume for %s, fsid %s\n",
			       path, fsid);
		nothing_to_resume = 1;
		goto out;
	}

	ret = prg_fd = socket(AF_UNIX, SOCK_STREAM, 0);
	while (ret != -1) {
		ret = scrub_datafile(SCRUB_PROGRESS_SOCKET_PATH, fsid, NULL,
					sock_path, sizeof(sock_path));
		/* ignore EOVERFLOW, try using a shorter path for the socket */
		addr.sun_path[sizeof(addr.sun_path) - 1] = '\0';
		strncpy(addr.sun_path, sock_path, sizeof(addr.sun_path) - 1);
		ret = bind(prg_fd, (struct sockaddr *)&addr, sizeof(addr));
		if (ret != -1 || errno != EADDRINUSE)
			break;
		/*
		 * bind failed with EADDRINUSE. so let's see if anyone answers
		 * when we make a call to the socket ...
		 */
		ret = connect(prg_fd, (struct sockaddr *)&addr, sizeof(addr));
		if (!ret || errno != ECONNREFUSED) {
			/* ... yes, so scrub must be running. error out */
			error("scrub already running");
			close(prg_fd);
			prg_fd = -1;
			goto out;
		}
		/*
		 * ... no, this means someone left us alone with an unused
		 * socket in the file system. remove it and try again.
		 */
		ret = unlink(sock_path);
	}
	if (ret != -1)
		ret = listen(prg_fd, 100);
	if (ret == -1) {
		warning_on(!do_quiet,
   "failed to open the progress status socket at %s: %s. Progress cannot be queried",
			sock_path[0] ? sock_path :
			SCRUB_PROGRESS_SOCKET_PATH, strerror(errno));
		if (prg_fd != -1) {
			close(prg_fd);
			prg_fd = -1;
			if (sock_path[0])
				unlink(sock_path);
		}
	}

	if (do_record) {
		/* write all-zero progress file for a start */
		ret = scrub_write_progress(&spc_write_mutex, fsid, sp,
					   fi_args.num_devices);
		if (ret) {
			warning_on(!do_quiet,
   "failed to write the progress status file: %s. Status recording disabled",
				strerror(-ret));
			do_record = 0;
		}
	}

	if (do_background) {
		pid = fork();
		if (pid == -1) {
			error_on(!do_quiet, "cannot scrub, fork failed: %s",
				strerror(errno));
			err = 1;
			goto out;
		}

		if (pid) {
			int stat;
			scrub_handle_sigint_parent();
			if (!do_quiet)
				printf("scrub %s on %s, fsid %s (pid=%d)\n",
				       n_start ? "started" : "resumed",
				       path, fsid, pid);
			if (!do_wait) {
				err = 0;
				goto out;
			}
			ret = wait(&stat);
			if (ret != pid) {
				error_on(!do_quiet, "wait failed (ret=%d): %s",
					ret, strerror(errno));
				err = 1;
				goto out;
			}
			if (!WIFEXITED(stat) || WEXITSTATUS(stat)) {
				error_on(!do_quiet, "scrub process failed");
				err = WIFEXITED(stat) ? WEXITSTATUS(stat) : -1;
				goto out;
			}
			err = 0;
			goto out;
		}
	}

	scrub_handle_sigint_child(fdmnt);

	for (i = 0; i < fi_args.num_devices; ++i) {
		if (sp[i].skip) {
			sp[i].scrub_args.progress = sp[i].resumed->p;
			sp[i].stats = sp[i].resumed->stats;
			sp[i].ret = 0;
			sp[i].stats.finished = 1;
			continue;
		}
		devid = di_args[i].devid;
		gettimeofday(&tv, NULL);
		sp[i].stats.t_start = tv.tv_sec;
		ret = pthread_create(&t_devs[i], NULL,
					scrub_one_dev, &sp[i]);
		if (ret) {
			if (do_print)
			error("creating scrub_one_dev[%llu] thread failed: %s",
				devid, strerror(ret));
			err = 1;
			goto out;
		}
	}

	spc.fdmnt = fdmnt;
	spc.prg_fd = prg_fd;
	spc.do_record = do_record;
	spc.write_mutex = &spc_write_mutex;
	spc.shared_progress = sp;
	spc.fi = &fi_args;
	ret = pthread_create(&t_prog, NULL, scrub_progress_cycle, &spc);
	if (ret) {
		if (do_print)
			error("creating progress thread failed: %s",
				strerror(ret));
		err = 1;
		goto out;
	}

	err = 0;
	for (i = 0; i < fi_args.num_devices; ++i) {
		if (sp[i].skip)
			continue;
		devid = di_args[i].devid;
		ret = pthread_join(t_devs[i], NULL);
		if (ret) {
			if (do_print)
			  error("pthread_join failed for scrub_one_dev[%llu]: %s",
				devid, strerror(ret));
			++err;
			continue;
		}
		if (sp[i].ret) {
			switch (sp[i].ioctl_errno) {
			case ENODEV:
				if (do_print)
					warning("device %lld not present",
						devid);
				continue;
			case ECANCELED:
				++err;
				break;
			default:
				if (do_print)
		error("scrubbing %s failed for device id %lld: ret=%d, errno=%d (%s)",
					path, devid,
					sp[i].ret, sp[i].ioctl_errno,
					strerror(sp[i].ioctl_errno));
				++err;
				continue;
			}
		}
		if (sp[i].scrub_args.progress.uncorrectable_errors > 0)
			e_uncorrectable++;
		if (sp[i].scrub_args.progress.corrected_errors > 0
		    || sp[i].scrub_args.progress.unverified_errors > 0)
			e_correctable++;
	}

	if (do_print) {
		const char *append = "done";
		if (!do_stats_per_dev)
			init_fs_stat(&fs_stat);
		for (i = 0; i < fi_args.num_devices; ++i) {
			if (do_stats_per_dev) {
				print_scrub_dev(&di_args[i],
						&sp[i].scrub_args.progress,
						print_raw,
						sp[i].ret ? "canceled" : "done",
						&sp[i].stats);
			} else {
				if (sp[i].ret)
					append = "canceled";
				add_to_fs_stat(&sp[i].scrub_args.progress,
						&sp[i].stats, &fs_stat);
			}
		}
		if (!do_stats_per_dev) {
			printf("scrub %s for %s\n", append, fsid);
			print_fs_stat(&fs_stat, print_raw);
		}
	}

	ret = pthread_cancel(t_prog);
	if (!ret)
		ret = pthread_join(t_prog, &terr);

	/* check for errors from the handling of the progress thread */
	if (do_print && ret) {
		error("progress thread handling failed: %s",
			strerror(ret));
	}

	/* check for errors returned from the progress thread itself */
	if (do_print && terr && terr != PTHREAD_CANCELED)
		error("recording progress failed: %s",
			strerror(-PTR_ERR(terr)));

	if (do_record) {
		ret = scrub_write_progress(&spc_write_mutex, fsid, sp,
					   fi_args.num_devices);
		if (ret && do_print)
			error("failed to record the result: %s",
				strerror(-ret));
	}

	scrub_handle_sigint_child(-1);

out:
	free_history(past_scrubs);
	free(di_args);
	free(t_devs);
	free(sp);
	free(spc.progress);
	if (prg_fd > -1) {
		close(prg_fd);
		if (sock_path[0])
			unlink(sock_path);
	}
	close_file_or_dir(fdmnt, dirstream);

	if (err)
		return 1;
	if (nothing_to_resume)
		return 2;
	if (e_uncorrectable) {
		error_on(!do_quiet, "there are uncorrectable errors");
		return 3;
	}
	if (e_correctable)
		warning_on(!do_quiet,
			"errors detected during scrubbing, corrected");

	return 0;
}
Example #15
0
static int scrub_start(int argc, char **argv, int resume)
{
	int fdmnt;
	int prg_fd = -1;
	int fdres = -1;
	int ret;
	pid_t pid;
	int c;
	int i;
	int err = 0;
	int e_uncorrectable = 0;
	int e_correctable = 0;
	int print_raw = 0;
	char *path;
	int do_background = 1;
	int do_wait = 0;
	int do_print = 0;
	int do_quiet = 0;
	int do_record = 1;
	int readonly = 0;
	int do_stats_per_dev = 0;
	int ioprio_class = IOPRIO_CLASS_IDLE;
	int ioprio_classdata = 0;
	int n_start = 0;
	int n_skip = 0;
	int n_resume = 0;
	struct btrfs_ioctl_fs_info_args fi_args;
	struct btrfs_ioctl_dev_info_args *di_args = NULL;
	struct scrub_progress *sp = NULL;
	struct scrub_fs_stat fs_stat;
	struct timeval tv;
	struct sockaddr_un addr = {
		.sun_family = AF_UNIX,
	};
	pthread_t *t_devs = NULL;
	pthread_t t_prog;
	pthread_attr_t t_attr;
	struct scrub_file_record **past_scrubs = NULL;
	struct scrub_file_record *last_scrub = NULL;
	char *datafile = strdup(SCRUB_DATA_FILE);
	char fsid[37];
	char sock_path[BTRFS_PATH_NAME_MAX + 1] = "";
	struct scrub_progress_cycle spc;
	pthread_mutex_t spc_write_mutex = PTHREAD_MUTEX_INITIALIZER;
	void *terr;
	u64 devid;

	optind = 1;
	while ((c = getopt(argc, argv, "BdqrRc:n:")) != -1) {
		switch (c) {
		case 'B':
			do_background = 0;
			do_wait = 1;
			do_print = 1;
			break;
		case 'd':
			do_stats_per_dev = 1;
			break;
		case 'q':
			do_quiet = 1;
			break;
		case 'r':
			readonly = 1;
			break;
		case 'R':
			print_raw = 1;
			break;
		case 'c':
			ioprio_class = (int)strtol(optarg, NULL, 10);
			break;
		case 'n':
			ioprio_classdata = (int)strtol(optarg, NULL, 10);
			break;
		case '?':
		default:
			usage(resume ? cmd_scrub_resume_usage :
						cmd_scrub_start_usage);
		}
	}

	/* try to catch most error cases before forking */

	if (check_argc_exact(argc - optind, 1)) {
		usage(resume ? cmd_scrub_resume_usage :
					cmd_scrub_start_usage);
	}

	spc.progress = NULL;
	if (do_quiet && do_print)
		do_print = 0;

	if (mkdir_p(datafile)) {
		ERR(!do_quiet, "WARNING: cannot create scrub data "
			       "file, mkdir %s failed: %s. Status recording "
			       "disabled\n", datafile, strerror(errno));
		do_record = 0;
	}
	free(datafile);

	path = argv[optind];

	fdmnt = open_path_or_dev_mnt(path);

	if (fdmnt < 0) {
		ERR(!do_quiet, "ERROR: can't access '%s'\n", path);
		return 12;
	}

	ret = get_fs_info(path, &fi_args, &di_args);
	if (ret) {
		ERR(!do_quiet, "ERROR: getting dev info for scrub failed: "
		    "%s\n", strerror(-ret));
		err = 1;
		goto out;
	}
	if (!fi_args.num_devices) {
		ERR(!do_quiet, "ERROR: no devices found\n");
		err = 1;
		goto out;
	}

	uuid_unparse(fi_args.fsid, fsid);
	fdres = scrub_open_file_r(SCRUB_DATA_FILE, fsid);
	if (fdres < 0 && fdres != -ENOENT) {
		ERR(!do_quiet, "WARNING: failed to open status file: "
		    "%s\n", strerror(-fdres));
	} else if (fdres >= 0) {
		past_scrubs = scrub_read_file(fdres, !do_quiet);
		if (IS_ERR(past_scrubs))
			ERR(!do_quiet, "WARNING: failed to read status file: "
			    "%s\n", strerror(-PTR_ERR(past_scrubs)));
		close(fdres);
	}

	t_devs = malloc(fi_args.num_devices * sizeof(*t_devs));
	sp = calloc(fi_args.num_devices, sizeof(*sp));
	spc.progress = calloc(fi_args.num_devices * 2, sizeof(*spc.progress));

	if (!t_devs || !sp || !spc.progress) {
		ERR(!do_quiet, "ERROR: scrub failed: %s", strerror(errno));
		err = 1;
		goto out;
	}

	ret = pthread_attr_init(&t_attr);
	if (ret) {
		ERR(!do_quiet, "ERROR: pthread_attr_init failed: %s\n",
		    strerror(ret));
		err = 1;
		goto out;
	}

	for (i = 0; i < fi_args.num_devices; ++i) {
		devid = di_args[i].devid;
		ret = pthread_mutex_init(&sp[i].progress_mutex, NULL);
		if (ret) {
			ERR(!do_quiet, "ERROR: pthread_mutex_init failed: "
			    "%s\n", strerror(ret));
			err = 1;
			goto out;
		}
		last_scrub = last_dev_scrub(past_scrubs, devid);
		sp[i].scrub_args.devid = devid;
		sp[i].fd = fdmnt;
		if (resume && last_scrub && (last_scrub->stats.canceled ||
					     !last_scrub->stats.finished)) {
			++n_resume;
			sp[i].scrub_args.start = last_scrub->p.last_physical;
			sp[i].resumed = last_scrub;
		} else if (resume) {
			++n_skip;
			sp[i].skip = 1;
			sp[i].resumed = last_scrub;
			continue;
		} else {
			++n_start;
			sp[i].scrub_args.start = 0ll;
			sp[i].resumed = NULL;
		}
		sp[i].skip = 0;
		sp[i].scrub_args.end = (u64)-1ll;
		sp[i].scrub_args.flags = readonly ? BTRFS_SCRUB_READONLY : 0;
		sp[i].ioprio_class = ioprio_class;
		sp[i].ioprio_classdata = ioprio_classdata;
	}

	if (!n_start && !n_resume) {
		if (!do_quiet)
			printf("scrub: nothing to resume for %s, fsid %s\n",
			       path, fsid);
		err = 0;
		goto out;
	}

	ret = prg_fd = socket(AF_UNIX, SOCK_STREAM, 0);
	while (ret != -1) {
		ret = scrub_datafile(SCRUB_PROGRESS_SOCKET_PATH, fsid, NULL,
					sock_path, sizeof(sock_path));
		/* ignore EOVERFLOW, try using a shorter path for the socket */
		addr.sun_path[sizeof(addr.sun_path) - 1] = '\0';
		strncpy(addr.sun_path, sock_path, sizeof(addr.sun_path) - 1);
		ret = bind(prg_fd, (struct sockaddr *)&addr, sizeof(addr));
		if (ret != -1 || errno != EADDRINUSE)
			break;
		/*
		 * bind failed with EADDRINUSE. so let's see if anyone answers
		 * when we make a call to the socket ...
		 */
		ret = connect(prg_fd, (struct sockaddr *)&addr, sizeof(addr));
		if (!ret || errno != ECONNREFUSED) {
			/* ... yes, so scrub must be running. error out */
			fprintf(stderr, "ERROR: scrub already running\n");
			close(prg_fd);
			prg_fd = -1;
			goto out;
		}
		/*
		 * ... no, this means someone left us alone with an unused
		 * socket in the file system. remove it and try again.
		 */
		ret = unlink(sock_path);
	}
	if (ret != -1)
		ret = listen(prg_fd, 100);
	if (ret == -1) {
		ERR(!do_quiet, "WARNING: failed to open the progress status "
		    "socket at %s: %s. Progress cannot be queried\n",
		    sock_path[0] ? sock_path : SCRUB_PROGRESS_SOCKET_PATH,
		    strerror(errno));
		if (prg_fd != -1) {
			close(prg_fd);
			prg_fd = -1;
			if (sock_path[0])
				unlink(sock_path);
		}
	}

	if (do_record) {
		/* write all-zero progress file for a start */
		ret = scrub_write_progress(&spc_write_mutex, fsid, sp,
					   fi_args.num_devices);
		if (ret) {
			ERR(!do_quiet, "WARNING: failed to write the progress "
			    "status file: %s. Status recording disabled\n",
			    strerror(-ret));
			do_record = 0;
		}
	}

	if (do_background) {
		pid = fork();
		if (pid == -1) {
			ERR(!do_quiet, "ERROR: cannot scrub, fork failed: "
					"%s\n", strerror(errno));
			err = 1;
			goto out;
		}

		if (pid) {
			int stat;
			scrub_handle_sigint_parent();
			if (!do_quiet)
				printf("scrub %s on %s, fsid %s (pid=%d)\n",
				       n_start ? "started" : "resumed",
				       path, fsid, pid);
			if (!do_wait) {
				err = 0;
				goto out;
			}
			ret = wait(&stat);
			if (ret != pid) {
				ERR(!do_quiet, "ERROR: wait failed: (ret=%d) "
				    "%s\n", ret, strerror(errno));
				err = 1;
				goto out;
			}
			if (!WIFEXITED(stat) || WEXITSTATUS(stat)) {
				ERR(!do_quiet, "ERROR: scrub process failed\n");
				err = WIFEXITED(stat) ? WEXITSTATUS(stat) : -1;
				goto out;
			}
			err = 0;
			goto out;
		}
	}

	scrub_handle_sigint_child(fdmnt);

	for (i = 0; i < fi_args.num_devices; ++i) {
		if (sp[i].skip) {
			sp[i].scrub_args.progress = sp[i].resumed->p;
			sp[i].stats = sp[i].resumed->stats;
			sp[i].ret = 0;
			sp[i].stats.finished = 1;
			continue;
		}
		devid = di_args[i].devid;
		gettimeofday(&tv, NULL);
		sp[i].stats.t_start = tv.tv_sec;
		ret = pthread_create(&t_devs[i], &t_attr,
					scrub_one_dev, &sp[i]);
		if (ret) {
			if (do_print)
				fprintf(stderr, "ERROR: creating "
					"scrub_one_dev[%llu] thread failed: "
					"%s\n", devid, strerror(ret));
			err = 1;
			goto out;
		}
	}

	spc.fdmnt = fdmnt;
	spc.prg_fd = prg_fd;
	spc.do_record = do_record;
	spc.write_mutex = &spc_write_mutex;
	spc.shared_progress = sp;
	spc.fi = &fi_args;
	ret = pthread_create(&t_prog, &t_attr, scrub_progress_cycle, &spc);
	if (ret) {
		if (do_print)
			fprintf(stderr, "ERROR: creating progress thread "
				"failed: %s\n", strerror(ret));
		err = 1;
		goto out;
	}

	err = 0;
	for (i = 0; i < fi_args.num_devices; ++i) {
		if (sp[i].skip)
			continue;
		devid = di_args[i].devid;
		ret = pthread_join(t_devs[i], NULL);
		if (ret) {
			if (do_print)
				fprintf(stderr, "ERROR: pthread_join failed "
					"for scrub_one_dev[%llu]: %s\n", devid,
					strerror(ret));
			++err;
			continue;
		}
		if (sp[i].ret && sp[i].ioctl_errno == ENODEV) {
			if (do_print)
				fprintf(stderr, "WARNING: device %lld not "
					"present\n", devid);
			continue;
		}
		if (sp[i].ret && sp[i].ioctl_errno == ECANCELED) {
			++err;
		} else if (sp[i].ret) {
			if (do_print)
				fprintf(stderr, "ERROR: scrubbing %s failed "
					"for device id %lld (%s)\n", path,
					devid, strerror(sp[i].ioctl_errno));
			++err;
			continue;
		}
		if (sp[i].scrub_args.progress.uncorrectable_errors > 0)
			e_uncorrectable++;
		if (sp[i].scrub_args.progress.corrected_errors > 0
		    || sp[i].scrub_args.progress.unverified_errors > 0)
			e_correctable++;
	}

	if (do_print) {
		const char *append = "done";
		if (!do_stats_per_dev)
			init_fs_stat(&fs_stat);
		for (i = 0; i < fi_args.num_devices; ++i) {
			if (do_stats_per_dev) {
				print_scrub_dev(&di_args[i],
						&sp[i].scrub_args.progress,
						print_raw,
						sp[i].ret ? "canceled" : "done",
						&sp[i].stats);
			} else {
				if (sp[i].ret)
					append = "canceled";
				add_to_fs_stat(&sp[i].scrub_args.progress,
						&sp[i].stats, &fs_stat);
			}
		}
		if (!do_stats_per_dev) {
			printf("scrub %s for %s\n", append, fsid);
			print_fs_stat(&fs_stat, print_raw);
		}
	}

	ret = pthread_cancel(t_prog);
	if (!ret)
		ret = pthread_join(t_prog, &terr);

	/* check for errors from the handling of the progress thread */
	if (do_print && ret) {
		fprintf(stderr, "ERROR: progress thread handling failed: %s\n",
			strerror(ret));
	}

	/* check for errors returned from the progress thread itself */
	if (do_print && terr && terr != PTHREAD_CANCELED) {
		fprintf(stderr, "ERROR: recording progress "
			"failed: %s\n", strerror(-PTR_ERR(terr)));
	}

	if (do_record) {
		ret = scrub_write_progress(&spc_write_mutex, fsid, sp,
					   fi_args.num_devices);
		if (ret && do_print) {
			fprintf(stderr, "ERROR: failed to record the result: "
				"%s\n", strerror(-ret));
		}
	}

	scrub_handle_sigint_child(-1);

out:
	free_history(past_scrubs);
	free(di_args);
	free(t_devs);
	free(sp);
	free(spc.progress);
	if (prg_fd > -1) {
		close(prg_fd);
		if (sock_path[0])
			unlink(sock_path);
	}
	close(fdmnt);

	if (err)
		return 1;
	if (e_correctable)
		return 7;
	if (e_uncorrectable)
		return 8;
	return 0;
}
Example #16
0
static int cmd_scrub_status(int argc, char **argv)
{
	char *path;
	struct btrfs_ioctl_fs_info_args fi_args;
	struct btrfs_ioctl_dev_info_args *di_args = NULL;
	struct scrub_file_record **past_scrubs = NULL;
	struct scrub_file_record *last_scrub;
	struct scrub_fs_stat fs_stat;
	struct sockaddr_un addr = {
		.sun_family = AF_UNIX,
	};
	int ret;
	int i;
	int fdmnt;
	int print_raw = 0;
	int do_stats_per_dev = 0;
	int c;
	char fsid[37];
	int fdres = -1;
	int err = 0;

	optind = 1;
	while ((c = getopt(argc, argv, "dR")) != -1) {
		switch (c) {
		case 'd':
			do_stats_per_dev = 1;
			break;
		case 'R':
			print_raw = 1;
			break;
		case '?':
		default:
			usage(cmd_scrub_status_usage);
		}
	}

	if (check_argc_exact(argc - optind, 1))
		usage(cmd_scrub_status_usage);

	path = argv[optind];

	fdmnt = open_path_or_dev_mnt(path);

	if (fdmnt < 0) {
		fprintf(stderr, "ERROR: can't access to '%s'\n", path);
		return 12;
	}

	ret = get_fs_info(path, &fi_args, &di_args);
	if (ret) {
		fprintf(stderr, "ERROR: getting dev info for scrub failed: "
				"%s\n", strerror(-ret));
		err = 1;
		goto out;
	}
	if (!fi_args.num_devices) {
		fprintf(stderr, "ERROR: no devices found\n");
		err = 1;
		goto out;
	}

	uuid_unparse(fi_args.fsid, fsid);

	fdres = socket(AF_UNIX, SOCK_STREAM, 0);
	if (fdres == -1) {
		fprintf(stderr, "ERROR: failed to create socket to "
			"receive progress information: %s\n",
			strerror(errno));
		err = 1;
		goto out;
	}
	scrub_datafile(SCRUB_PROGRESS_SOCKET_PATH, fsid,
			NULL, addr.sun_path, sizeof(addr.sun_path));
	/* ignore EOVERFLOW, just use shorter name and hope for the best */
	addr.sun_path[sizeof(addr.sun_path) - 1] = '\0';
	ret = connect(fdres, (struct sockaddr *)&addr, sizeof(addr));
	if (ret == -1) {
		close(fdres);
		fdres = scrub_open_file_r(SCRUB_DATA_FILE, fsid);
		if (fdres < 0 && fdres != -ENOENT) {
			fprintf(stderr, "WARNING: failed to open status file: "
				"%s\n", strerror(-fdres));
			err = 1;
			goto out;
		}
	}

	if (fdres >= 0) {
		past_scrubs = scrub_read_file(fdres, 1);
		if (IS_ERR(past_scrubs))
			fprintf(stderr, "WARNING: failed to read status: %s\n",
				strerror(-PTR_ERR(past_scrubs)));
	}

	printf("scrub status for %s\n", fsid);

	if (do_stats_per_dev) {
		for (i = 0; i < fi_args.num_devices; ++i) {
			last_scrub = last_dev_scrub(past_scrubs,
							di_args[i].devid);
			if (!last_scrub) {
				print_scrub_dev(&di_args[i], NULL, print_raw,
						NULL, NULL);
				continue;
			}
			print_scrub_dev(&di_args[i], &last_scrub->p, print_raw,
					last_scrub->stats.finished ?
							"history" : "status",
					&last_scrub->stats);
		}
	} else {
		init_fs_stat(&fs_stat);
		for (i = 0; i < fi_args.num_devices; ++i) {
			last_scrub = last_dev_scrub(past_scrubs,
							di_args[i].devid);
			if (!last_scrub)
				continue;
			add_to_fs_stat(&last_scrub->p, &last_scrub->stats,
					&fs_stat);
		}
		print_fs_stat(&fs_stat, print_raw);
	}

out:
	free_history(past_scrubs);
	free(di_args);
	if (fdres > -1)
		close(fdres);

	return err;
}
Example #17
0
int press_record(char *data_filename, char *wave_filename) {
  /* The overall goal here is to seamlessly decode as many different audio
     inputs as possible.

     There's a lot of subtlety to decoding analog input with an FFT,
     especially for a protocol like this one with a symbol that's
     half a wavelength.

     Instead of making proper hardware to amplify and filter the
     output of the TI99/4a, I made this software capable of decoding
     the weak, noisy crap obtained from connecting the microphone
     output to a line-in without any filter or amplifier.

     I perform an FFT over one wavelength once per sample. Computing
     the FFT for every sample is probably overkill, but it's
     significantly faster than realtime even on an old PowerBook G4,
     and it doesn't hurt to average out noise better.

     Using a buffer size of one wavelength means that the first and
     second harmonics are centered at exactly the frequencies we're
     looking at. I believe it's necessary to use a window function, so
     that alternating 0s and ones can be differentiated. I'm using the
     Hamming window (half a sine wave), but there may be better ones.
     
     There can be a lot of noise in the signal, so I keep a
     half-symbol size buffer of the difference between the signal
     strengths of the two frequencies and use the average.  (It it was
     a whole buffer, it would blur out the boundaries between
     symbols.)  If the difference between the low and high and low
     frequncies drops below or rises above the midpoint, it triggers a
     new signal.

*/


  void *in_file;
  FILE *out_file;
  size_t num_harmonics;
  sf_count_t samples_read;
  fftw_complex *harmonics;
  fftw_plan get_frequencies;
  size_t offset = 0;
  double *audio_samples;
  int (*read_samples)(void *device, double *buffer, size_t count);

  /* Initialize the FFT

     If the FFT is over the wavelength of the low frequency (twice the symbol size)

     sample 0 - DC
     sample 1 - wavelen of 2 symbols - "Zero"
     sample 2 - wavelen of 1 symbol - "One"

     This doesn't have a very narrow filter, so it might be susceptable to interference.     
   */
  num_harmonics = DEFAULT_WAVELENGTH/2+1;
  harmonics = (fftw_complex*) fftw_malloc(sizeof(fftw_complex)*num_harmonics);

  audio_samples = (double*) fftw_malloc(sizeof(double)*DEFAULT_WAVELENGTH);
  if (wave_filename == NULL) {
    read_samples = &read_from_mic;
    init_mic_input(&in_file);

  } else {
    read_samples = &read_from_file;
    init_file_input(&in_file,wave_filename);
  }
  init_audio_buffer(read_samples, in_file);
  init_history();
  init_window();
  if (data_filename == NULL)
    out_file = stdout;
  else
    out_file = fopen(data_filename,"wb");

  get_frequencies = fftw_plan_dft_r2c_1d(DEFAULT_WAVELENGTH, audio_samples,
					 harmonics,
					 FFTW_ESTIMATE | FFTW_DESTROY_INPUT);


  while ((samples_read = audio_at_offset(read_samples, in_file, audio_samples, offset++, DEFAULT_WAVELENGTH))>0) {
    apply_window_func(audio_samples);
    fftw_execute(get_frequencies);
    if (process_harmonics(harmonics, num_harmonics, out_file))
      break;
  }
  cosby_print("Done!\n");

  if (data_filename != NULL)    
    fclose(out_file);
 
  fftw_destroy_plan(get_frequencies);

  fftw_free(harmonics);
  fftw_free(audio_samples);
  if (wave_filename == NULL) {
  } else {
    free_audio_buffer(in_file);
  }
  free_history();
  free_window();

  return 1;
}