Example #1
0
void clear_mounts(controller *c){
	unmount_target();
	while(c){
		device *d;

		for(d = c->blockdevs ; d ; d = d->next){
			device *p;

			// Don't free mnttype. There's still a filesystem.
			free_stringlist(&d->mnt);
			free_stringlist(&d->mntops);
			for(p = d->parts ; p ; p = p->next){
				free_stringlist(&p->mnt);
				free_stringlist(&p->mntops);
			}
		}
		c = c->next;
	}
}
Example #2
0
GList *limit_stringlist(GList *which_list, gint num_entries, gboolean keep_end) {
	GList *retlist, *freelist;
	if (keep_end) {
		gint len;
		freelist = g_list_first(which_list);
		len = g_list_length(freelist);
		if (len <= num_entries) return which_list;
		retlist = g_list_nth(freelist, len - num_entries);
		unlink_before(retlist);
	} else {
		retlist = g_list_first(which_list);
		freelist = g_list_nth(retlist, num_entries);
		if (freelist) unlink_before(freelist);
	}
	if (freelist) free_stringlist(freelist);
	return retlist;
}
Example #3
0
void
filefilter_gui(Tfilter * filter)
{
	GtkCellRenderer *renderer;
	GtkTreeViewColumn *column;
	GList *tmplist, *reglist;
	GtkWidget *table, *hbox, *but, *vbox, *scrolwin;
#ifdef WIN32
	GList *mimelist = NULL;
	gchar *last_mime = NULL;
#endif

	Tfilefiltergui *ffg = g_new0(Tfilefiltergui, 1);
	ffg->curfilter = filter;
	if (filter) {
		ffg->origname = g_strdup(filter->name);
	}
	if (!filter) {
		ffg->curfilter = g_new0(Tfilter, 1);
		ffg->curfilter->name = g_strdup(_("New filter"));
	}

	DEBUG_MSG("filefilter_gui, editing filter %p\n", ffg->curfilter);
	ffg->win =
		window_full2(_("Edit filter"), GTK_WIN_POS_MOUSE, 10, G_CALLBACK(filefiltergui_destroy_lcb), ffg,
					 TRUE, NULL);
	gtk_window_set_default_size(GTK_WINDOW(ffg->win), 400, 400);
	ffg->lstore = gtk_list_store_new(3, G_TYPE_STRING, GDK_TYPE_PIXBUF, G_TYPE_BOOLEAN);

	/* fill the list model from the currently known filetypes */
	reglist = g_content_types_get_registered();

#ifdef WIN32
	tmplist = g_list_first(reglist);
	while (tmplist) {
		mimelist = g_list_prepend(mimelist, g_content_type_get_mime_type(tmplist->data));
		tmplist = g_list_next(tmplist);
	}
	mimelist = g_list_reverse(g_list_sort(mimelist, (GCompareFunc) g_strcmp0));
	tmplist = g_list_first(mimelist);
	while (tmplist) {
		if (!last_mime || g_strcmp0(last_mime, tmplist->data) != 0) {
			GtkTreeIter it;
			last_mime = tmplist->data;
			if (MIME_ISDIR(tmplist->data)) {
				gtk_list_store_prepend(ffg->lstore, &it);
				gtk_list_store_set(ffg->lstore, &it, 0, tmplist->data, 2, 0, -1);
			}
		}
		tmplist = g_list_next(tmplist);
	}
/*	GList *winlist = NULL;
	gchar *mimetype;
	gint llen, lpos;
	while(reglist) {
		mimetype = g_content_type_get_mime_type(reglist->data);
		if ((llen = g_list_length(winlist))) {
			tmplist = g_list_copy(winlist);
			for (lpos = 0; llen != -1 && lpos < llen; lpos++) {
				if (!g_strcmp0(mimetype, tmplist->data))
					llen = -1;
				else
					tmplist = g_list_next(tmplist);
			}
			g_list_free(tmplist);
		}
		if (llen != -1)
			winlist = g_list_append(winlist, mimetype);
		reglist = g_list_next(reglist);
	}
	tmplist = g_list_first(g_list_reverse(g_list_sort(winlist, (GCompareFunc) g_strcmp0)));*/
	free_stringlist(mimelist);
#else
	tmplist = g_list_first(g_list_sort(reglist, (GCompareFunc) g_strcmp0));
	while (tmplist) {
		GtkTreeIter it;
		if (!MIME_ISDIR(tmplist->data)) {
			gtk_list_store_prepend(ffg->lstore, &it);
			gtk_list_store_set(ffg->lstore, &it, 0, tmplist->data, 2, 0, -1);
		}
		tmplist = g_list_next(tmplist);
	}
#endif

	g_list_foreach(reglist, (GFunc) g_free, NULL);
	g_list_free(reglist);
	/* add the patterns from the current filter */
	tmplist = g_list_first(ffg->curfilter->patterns);
	while (tmplist) {
		GtkTreeIter it;
		Tfilterpattern *pat = (Tfilterpattern *) tmplist->data;
		gtk_list_store_prepend(ffg->lstore, &it);
		gtk_list_store_set(ffg->lstore, &it, 0, pat->pattern, 1, NULL, 2, 1, -1);
		tmplist = g_list_next(tmplist);
	}

	ffg->in_model = gtk_tree_model_filter_new(GTK_TREE_MODEL(ffg->lstore), NULL);
	gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(ffg->in_model),
										   filefiltergui_infilter_visiblefunc, ffg, NULL);
	ffg->out_model = gtk_tree_model_filter_new(GTK_TREE_MODEL(ffg->lstore), NULL);
	gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(ffg->out_model),
										   filefiltergui_outfilter_visiblefunc, ffg, NULL);

	table = gtk_table_new(5, 4, FALSE);
	gtk_table_set_row_spacings(GTK_TABLE(table), 5);

	ffg->nameentry = dialog_entry_in_table(ffg->curfilter->name, table, 0, 1, 0, 1);

	ffg->inversecheck =
		dialog_check_button_in_table(_("Hide files that match the filter"), !ffg->curfilter->mode, table, 0,
									 1, 1, 2);

	ffg->patentry = dialog_entry_in_table("*.*", table, 2, 3, 1, 2);
	but = gtk_button_new_with_label(_("Add pattern"));
	g_signal_connect(but, "clicked", G_CALLBACK(filefiltergui_addpattern_clicked_lcb), ffg);
	gtk_table_attach(GTK_TABLE(table), but, 3, 4, 1, 2, GTK_FILL, GTK_FILL, 0, 0);

	ffg->in_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(ffg->in_model));
	renderer = gtk_cell_renderer_text_new();
	column = gtk_tree_view_column_new_with_attributes(_("Mime type"), renderer, "text", 0, NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(ffg->in_view), column);
	renderer = gtk_cell_renderer_pixbuf_new();
	column = gtk_tree_view_column_new_with_attributes(_("Icon"), renderer, "pixbuf", 1, NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(ffg->in_view), column);
	scrolwin = gtk_scrolled_window_new(NULL, NULL);
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolwin), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
	gtk_container_add(GTK_CONTAINER(scrolwin), ffg->in_view);
	gtk_table_attach_defaults(GTK_TABLE(table), scrolwin, 2, 4, 2, 3);

	ffg->out_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(ffg->out_model));
	renderer = gtk_cell_renderer_text_new();
	column = gtk_tree_view_column_new_with_attributes(_("Mime type"), renderer, "text", 0, NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(ffg->out_view), column);
	renderer = gtk_cell_renderer_pixbuf_new();
	column = gtk_tree_view_column_new_with_attributes(_("Icon"), renderer, "pixbuf", 1, NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(ffg->out_view), column);
	scrolwin = gtk_scrolled_window_new(NULL, NULL);
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolwin), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
	gtk_container_add(GTK_CONTAINER(scrolwin), ffg->out_view);
	gtk_table_attach_defaults(GTK_TABLE(table), scrolwin, 0, 1, 2, 3);

	vbox = gtk_vbox_new(TRUE, 5);
	but = gtk_button_new_with_label("->");
	g_signal_connect(but, "clicked", G_CALLBACK(filefiltergui_2right_clicked), ffg);
	gtk_box_pack_start(GTK_BOX(vbox), but, TRUE, TRUE, 0);
	but = gtk_button_new_with_label("<-");
	g_signal_connect(but, "clicked", G_CALLBACK(filefiltergui_2left_clicked), ffg);
	gtk_box_pack_start(GTK_BOX(vbox), but, TRUE, TRUE, 0);
	gtk_table_attach(GTK_TABLE(table), vbox, 1, 2, 2, 3, GTK_EXPAND | GTK_FILL, GTK_EXPAND, 5, 5);

#if GTK_CHECK_VERSION(3,0,0)
	hbox = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
#else
	hbox = gtk_hbutton_box_new();
#endif
	gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
	gtk_box_set_spacing(GTK_BOX(hbox), 12);
	but = bf_stock_cancel_button(G_CALLBACK(filefiltergui_cancel_clicked), ffg);
	gtk_box_pack_start(GTK_BOX(hbox), but, FALSE, FALSE, 0);
	but = bf_stock_ok_button(G_CALLBACK(filefiltergui_ok_clicked), ffg);
	gtk_box_pack_start(GTK_BOX(hbox), but, FALSE, FALSE, 0);

	gtk_table_attach(GTK_TABLE(table), hbox, 2, 4, 4, 5, GTK_SHRINK, GTK_SHRINK, 0, 0);

	gtk_container_add(GTK_CONTAINER(ffg->win), table);
	gtk_widget_show_all(ffg->win);
}
Example #4
0
/**
 * msg_queue_check:
 *
 * checks the queue for any messages
 * this is called by the master program, usually by gtk_timeout_add()
 * the messages it will listen to are the types:
 * - MSG_QUEUE_ASK_ALIVE - we should respond with a type MSG_QUEUE_SEND_ALIVE
 * - MSG_QUEUE_OPENFILE - open a filename
 * - MSG_QUEUE_OPENPROJECT - open a filename as project
 * - MSG_QUEUE_OPENNEWWIN - open a new window
 */
static gboolean msg_queue_check(gint started_by_gtk_timeout)
{
	struct msgbuf {
		long mtype;
		char mtext[MSQ_QUEUE_SIZE];
	} msgp;
	gint retval;
	if (main_v->bfwinlist == NULL || BFWIN(main_v->bfwinlist->data)->documentlist == NULL) {
		DEBUG_MSG("msg_queue_check, no documentlist yet, so we do not continue\n");
		return TRUE;
	}

	if (msg_queue.msgid == -1) {
		return FALSE;
	}
	retval =	msgrcv(msg_queue.msgid, &msgp, MSQ_QUEUE_SIZE, -MSG_QUEUE_OPENFILE, IPC_NOWAIT);
	if (retval != -1) {
		DEBUG_MSG("msg_queue_check, found type %ld\n", msgp.mtype);
		if (msgp.mtype == MSG_QUEUE_ASK_ALIVE) {
			struct small_msgbuf {
				long mtype;
				char mtext[MSQ_QUEUE_SMALL_SIZE];
			} small_msgp;
			DEBUG_MSG("msg_queue_check, a keepalive is asked from %s, sending!\n", msgp.mtext);
			small_msgp.mtype = MSG_QUEUE_SEND_ALIVE;
			strncpy(small_msgp.mtext, msgp.mtext, MSQ_QUEUE_SMALL_SIZE - 1);
			msgsnd(msg_queue.msgid, (void *) &small_msgp, MSQ_QUEUE_SMALL_SIZE * sizeof(char),
				   IPC_NOWAIT);
		} else if (msgp.mtype == MSG_QUEUE_OPENFILE) {
			GList *lastlist = g_list_last(main_v->bfwinlist);
			gboolean delay_activate = TRUE;
			if (g_list_length(BFWIN(lastlist->data)->documentlist) < 2 && 
			       doc_is_empty_non_modified_and_nameless(BFWIN(lastlist->data)->current_document)) {
                       delay_activate = FALSE;
			}
			DEBUG_MSG("msg_queue_check, a filename %s is received\n", msgp.mtext);
			if (!doc_new_with_file(BFWIN(lastlist->data),msgp.mtext, delay_activate, FALSE)) {
				msg_queue.file_error_list = g_list_append(msg_queue.file_error_list, g_strdup(msgp.mtext));
			}
			msg_queue_check(0);	/* call myself again, there may have been multiple files */
			if (started_by_gtk_timeout) {
				if (msg_queue.file_error_list) {
					gchar *message, *tmp;
					tmp = stringlist_to_string(msg_queue.file_error_list, "\n");
					free_stringlist(msg_queue.file_error_list);
					msg_queue.file_error_list = NULL;
					message = g_strconcat(_("These files were not opened:\n"), tmp, NULL);
					g_free(tmp);
					warning_dialog(BFWIN(main_v->bfwinlist->data)->main_window,_("Unable to open file(s)\n"), message);
					g_free(message);
				}
/*				gtk_notebook_set_page(GTK_NOTEBOOK(main_v->notebook),g_list_length(main_v->documentlist) - 1);
				notebook_changed(-1);*/
			}
		} else if (msgp.mtype == MSG_QUEUE_OPENPROJECT) {
			GList *lastlist = g_list_last(main_v->bfwinlist);
			DEBUG_MSG("msg_queue_check, a project %s is received\n", msgp.mtext);
			project_open_from_file(BFWIN(lastlist->data), msgp.mtext);
			msg_queue_check(0);	/* call myself again, there may have been multiple projects */
		} else if (msgp.mtype == MSG_QUEUE_OPENNEWWIN) {
			/* now check if this is indeed send by another process
			if the message queue was dead during the startup of this process,
			it might be started by this very process */
			int otherpid = atoi(msgp.mtext);
			DEBUG_MSG("msg_queue_check, a new window is requested by PID=%d\n",otherpid);
			if (otherpid != (int) getpid()) {
				DEBUG_MSG("msg_queue_check, the PID is not ours, opening new window\n");
				gui_new_window(NULL, NULL);
			}
		}
#ifdef DEBUG
		 else {
		 	DEBUG_MSG("msg_queue_check, unknown message queue type %ld\n", msgp.mtype);
		 }
#endif
		
	} else {
#ifdef MSG_QUEUE_DEBUG
		DEBUG_MSG("msg_queue_check, found errno(%d)=%s\n", errno, g_strerror(errno));
#endif
	/*
	43 = Identifier removed
	*/
		if (errno == 22 || errno == 43) {
			DEBUG_MSG("msg_queue_check, re-opening message queue ?!?!?\n");
			/* the msg_queue was removed !?!?! */
			if (msg_queue_open()) {
				DEBUG_MSG("msg_queue_check, another process has opened the message_queue, stopping server\n");
				msg_queue.server = FALSE;
				return FALSE;
			}
		}
	}
	return TRUE;
}
Example #5
0
static gboolean parse_config_file(GList * config_list, gchar * filename)
{
	gboolean retval = FALSE;
	gchar *tmpstring = NULL, *tmpstring2;
	gchar **tmparray;
	GList *rclist, *tmplist, *tmplist2;
	Tconfig_list_item *tmpitem;

	DEBUG_MSG("parse_config_file, started\n");

	rclist = NULL;
	rclist = get_list(filename, rclist,FALSE);
	
	if (rclist == NULL) {
		DEBUG_MSG("no rclist, returning!\n");
		return retval;
	}

	/* empty all variables that have type GList ('l') */
	tmplist = g_list_first(config_list);
	while (tmplist != NULL) {
		tmpitem = (Tconfig_list_item *) tmplist->data;
		DEBUG_MSG("parse_config_file, type=%c, identifier=%s\n", tmpitem->type, tmpitem->identifier);
		if (tmpitem->type == 'l' || tmpitem->type == 'a') {
			DEBUG_MSG("parse_config_file, freeing list before filling it\n");
			free_stringlist((GList *) * (void **) tmpitem->pointer);
			*(void **) tmpitem->pointer = (GList *)NULL;
		}
		DEBUG_MSG("parse_config_file, type=%c, identifier=%s\n", tmpitem->type, tmpitem->identifier);
		tmplist = g_list_next(tmplist);
	}
	DEBUG_MSG("parse_config_file, all the type 'l' and 'a' have been emptied\n");
	DEBUG_MSG("parse_config_file, length rclist=%d\n", g_list_length(rclist));
/* And now for parsing every line in the config file, first check if there is a valid identifier at the start. */
	tmplist = g_list_first(rclist);
	while (tmplist) {
		tmpstring = (gchar *) tmplist->data;

		if (tmpstring != NULL) {
			DEBUG_MSG("parse_config_file, tmpstring=%s\n", tmpstring);
			g_strchug(tmpstring);

			tmplist2 = g_list_first(config_list);
			while (tmplist2) {
				tmpitem = (Tconfig_list_item *) tmplist2->data;
#ifdef DEVELOPMENT
				if (!tmpitem || !tmpitem->identifier || !tmpstring) {
					g_print("WARNING: almost a problem!\n");
				}
#endif
				if (g_strncasecmp(tmpitem->identifier, tmpstring, strlen(tmpitem->identifier)) == 0) {
					/* we have found the correct identifier */
					retval = TRUE;
					DEBUG_MSG("parse_config_file, identifier=%s, string=%s\n", tmpitem->identifier, tmpstring);
					/* move pointer past the identifier */
					tmpstring += strlen(tmpitem->identifier);
					trunc_on_char(tmpstring, '\n');
					g_strstrip(tmpstring);

					switch (tmpitem->type) {
					case 'i':
						*(int *) (void *) tmpitem->pointer = atoi(tmpstring);
						break;
					case 's':
						*(void **) tmpitem->pointer = (char *) realloc((char *) *(void **) tmpitem->pointer, strlen(tmpstring) + 1);
						strcpy((char *) *(void **) tmpitem->pointer, tmpstring);
						break;
					case 'e':
						tmpstring2 = unescape_string(tmpstring, FALSE); /* I wonder if that should be TRUE */
						*(void **) tmpitem->pointer = (char *) realloc((char *) *(void **) tmpitem->pointer, strlen(tmpstring2) + 1);
						strcpy((char *) *(void **) tmpitem->pointer, tmpstring2);
						g_free(tmpstring2);
						break;
					case 'l':
					case 'm':
						tmpstring2 = g_strdup(tmpstring);
						* (void **) tmpitem->pointer = g_list_prepend((GList *) * (void **) tmpitem->pointer, tmpstring2);
						DEBUG_MSG("parse_config_file, *(void **)tmpitem->pointer=%p\n", *(void **) tmpitem->pointer);
						break;
					case 'a':
						tmparray = string_to_array(tmpstring);
						if (tmpitem->len <= 0 || tmpitem->len == count_array(tmparray)) {
							* (void **) tmpitem->pointer = g_list_prepend((GList *) * (void **) tmpitem->pointer, tmparray);
						} else {
							DEBUG_MSG("parse_config_file, not storing array, count_array() != tmpitem->len\n");
							g_strfreev(tmparray);
						}
						DEBUG_MSG("parse_config_file, *(void **)tmpitem->pointer=%p\n", *(void **) tmpitem->pointer);
						break;
					default:
						break;
					}
					tmplist2 = g_list_last(tmplist2);
				}
				tmplist2 = g_list_next(tmplist2);
			}
		}
		tmplist = g_list_next(tmplist);
	}
	DEBUG_MSG("parse_config_file, parsed all entries, freeing list read from file\n");	
	free_stringlist(rclist);
	return retval;
}
Example #6
0
static gint save_config_file(GList * config_list, gchar * filename)
{
	gchar *tmpstring = NULL, *tmpstring2;
	GList *rclist, *tmplist, *tmplist2;
	Tconfig_list_item *tmpitem;

	DEBUG_MSG("save_config_file, started\n");

	rclist = NULL;

/* We must first make a list with 1 string per item. */
	tmplist = g_list_first(config_list);
	while (tmplist != NULL) {
		DEBUG_MSG("save_config_file, tmpitem at %p\n", tmplist->data);
		tmpitem = tmplist->data;
		DEBUG_MSG("save_config_file, identifier=%s datatype %c\n", tmpitem->identifier,tmpitem->type);
		switch (tmpitem->type) {
		case 'i':
			DEBUG_MSG("save_config_file, converting \"%p\" to integer\n", tmpitem);
			DEBUG_MSG("save_config_file, converting \"%s %i\"\n", tmpitem->identifier, *(int *) (void *) tmpitem->pointer);

			tmpstring = g_strdup_printf("%s %i", tmpitem->identifier, *(int *) (void *) tmpitem->pointer);

			DEBUG_MSG("save_config_file, adding %s\n", tmpstring);

			rclist = g_list_append(rclist, tmpstring);
			break;
		case 's':
			DEBUG_MSG("save_config_file, converting \"%p\" to string\n", tmpitem);
			DEBUG_MSG("save_config_file, converting \"%s %s\"\n", tmpitem->identifier, (gchar *) * (void **) tmpitem->pointer);
			if (*(void **) tmpitem->pointer) {
				tmpstring = g_strdup_printf("%s %s", tmpitem->identifier, (gchar *) * (void **) tmpitem->pointer);

				DEBUG_MSG("save_config_file, adding %s\n", tmpstring);

				rclist = g_list_append(rclist, tmpstring);
			}
			break;
		case 'e':
			DEBUG_MSG("save_config_file, converting \"%p\"\n", tmpitem);
			DEBUG_MSG("save_config_file, converting \"%s %s\"\n", tmpitem->identifier, (gchar *) * (void **) tmpitem->pointer);
			if (*(void **) tmpitem->pointer) {
				tmpstring2 = escape_string((gchar*)*(void**)tmpitem->pointer, FALSE);
				tmpstring = g_strdup_printf("%s %s", tmpitem->identifier, tmpstring2);

				DEBUG_MSG("save_config_file, adding %s\n", tmpstring);

				rclist = g_list_append(rclist, tmpstring);
				g_free(tmpstring2);
			}
			break;
		case 'l':
		case 'm': {
			gint max = -1; /* by setting it to -1, it will never become zero if we substract 1 every round */
			DEBUG_MSG("save_config_file, type %c, tmpitem(%p), &tmpitem=%p\n", tmpitem->type, tmpitem, &tmpitem);
			if (tmpitem->type == 'm') max = tmpitem->len;
			tmplist2 = g_list_last((GList *) * (void **) tmpitem->pointer);
			while (tmplist2 != NULL && max != 0) {
				tmpstring2 = (char *) tmplist2->data;
				DEBUG_MSG("save_config_file, tmpstring2(%p)=%s\n", tmpstring2, tmpstring2);
				tmpstring = g_strdup_printf("%s %s", tmpitem->identifier, tmpstring2);
				DEBUG_MSG("save_config_file, tmpstring(%p)=%s\n", tmpstring, tmpstring);
				rclist = g_list_append(rclist, tmpstring);
				tmplist2 = g_list_previous(tmplist2);
				max--;
			}
			} break;
		case 'a':
			DEBUG_MSG("save_config_file, tmpitem(%p), &tmpitem=%p\n", tmpitem, &tmpitem);
			tmplist2 = g_list_last((GList *) * (void **) tmpitem->pointer);
			DEBUG_MSG("save_config_file, the tmplist2(%p)\n", tmplist2);
			while (tmplist2 != NULL) {
				tmpstring2 = array_to_string((char **) tmplist2->data);
				tmpstring = g_strdup_printf("%s %s", tmpitem->identifier, tmpstring2);
				DEBUG_MSG("save_config_file, tmpstring(%p)=%s\n", tmpstring, tmpstring);
				rclist = g_list_append(rclist, tmpstring);
				tmplist2 = g_list_previous(tmplist2);
				g_free(tmpstring2);
			}
			break;
		default:
			break;
		}
		tmplist = g_list_next(tmplist);

	}

	put_stringlist(filename, rclist);
	free_stringlist(rclist);
	return 1;
}
Example #7
0
int parse_mounts(const glightui *gui,const char *fn){
	char *mnt,*dev,*ops,*fs;
	off_t len,idx;
	char *map;
	int fd;

	if((map = map_virt_file(fn,&fd,&len)) == MAP_FAILED){
		return -1;
	}
	idx = 0;
	dev = mnt = fs = ops = NULL;
	while(idx < len){
		char buf[PATH_MAX + 1];
		struct statvfs vfs;
		struct stat st;
		device *d;
		char *rp;
		int r;

		free(dev); free(mnt); free(fs); free(ops);
		if((r = parse_mount(map + idx,len - idx,&dev,&mnt,&fs,&ops)) < 0){
			goto err;
		}
		idx += r;
		if(statvfs(mnt,&vfs)){
			int skip = 0;

			// We might have mounted a new target atop or above an
			// already existing one, in which case we'll need
			// possibly recreate the directory structure on the
			// newly-mounted filesystem.
			if(growlight_target){
				if(strncmp(mnt,growlight_target,strlen(growlight_target)) == 0){
					if(make_parent_directories(mnt) == 0){
						skip = 1;
					} // FIXME else remount? otherwise writes
					// go to new filesystem rather than old...?
				}
			}
			if(!skip){
				diag("Couldn't stat fs %s (%s?)\n",mnt,strerror(errno));
				r = -1;
				continue;
			}
		}
		if(*dev != '/'){ // have to get zfs's etc
			if(fstype_virt_p(fs)){
				continue;
			}
			if((d = lookup_device(dev)) == NULL){
				verbf("virtfs %s at %s\n",fs,mnt);
				continue;
			}
		}else{
			rp = dev;
			if(lstat(rp,&st) == 0){
				if(S_ISLNK(st.st_mode)){
					if((r = readlink(dev,buf,sizeof(buf))) < 0){
						diag("Couldn't deref %s (%s?)\n",dev,strerror(errno));
						continue;
					}
					if((size_t)r >= sizeof(buf)){
						diag("Name too long for %s (%d?)\n",dev,r);
						continue;
					}
					buf[r] = '\0';
					rp = buf;
				}
			}
			if((d = lookup_device(rp)) == NULL){
				continue;
			}
		}
		free(dev);
		dev = NULL;
		if(d->mnttype && strcmp(d->mnttype,fs)){
			diag("Already had mounttype for %s: %s (got %s)\n",
					d->name,d->mnttype,fs);
			free(d->mnttype);
			d->mnttype = NULL;
			free_stringlist(&d->mntops);
			free_stringlist(&d->mnt);
			d->mnttype = fs;
		}else{
			free(fs);
		}
		fs = NULL;
		if(add_string(&d->mnt,mnt)){
			goto err;
		}
		if(add_string(&d->mntops,ops)){
			goto err;
		}
		d->mntsize = (uintmax_t)vfs.f_bsize * vfs.f_blocks;
		if(d->layout == LAYOUT_PARTITION){
			d = d->partdev.parent;
		}
		d->uistate = gui->block_event(d,d->uistate);
		if(growlight_target){
			if(strcmp(mnt,growlight_target) == 0){
				mount_target();
			}
		}
	}
	free(mnt); free(fs); free(ops);
	mnt = fs = ops = NULL;
	munmap_virt(map,len);
	close(fd);
	return 0;

err:
	free(dev); free(mnt); free(fs); free(ops);
	munmap_virt(map,len);
	close(fd);
	return -1;
}