10 typedef struct sProperty
16 typedef struct sDevice
27 int parse_property(char *str, int size, Property *prop)
32 for(i=0; (equals<0 && i<size); ++i)
39 prop->name = malloc(equals+1);
40 strncpy(prop->name, str, equals);
41 prop->name[equals] = 0;
43 prop->value = malloc(size-equals);
44 strncpy(prop->value, str+equals+1, size-equals-1);
45 prop->value[size-equals-1] = 0;
50 Property *get_device_properties(char *node)
61 printf("Running udevadm info -q property -n \"%s\"\n", node);
66 execl("/sbin/udevadm", "udevadm", "info", "-q", "property", "-n", node, NULL);
75 Property *props = NULL;
81 buf = (char *)malloc(bufsize);
93 len = read(pipe_fd[0], buf+pos, bufsize-pos);
102 for(i=0; (newline<0 && i<pos); ++i)
111 buf = (char *)realloc(buf, bufsize);
115 if(parse_property(buf, newline, &prop)==0)
117 props = (Property *)realloc(props, (n_props+2)*sizeof(Property));
118 props[n_props] = prop;
121 memmove(buf, buf+newline+1, pos-newline-1);
132 props[n_props].name = NULL;
133 props[n_props].value = NULL;
136 waitpid(pid, NULL, 0);
150 char *get_property_value(Property *props, char *name)
153 for(i=0; props[i].name; ++i)
154 if(strcmp(props[i].name, name)==0)
155 return props[i].value;
159 int match_property_value(Property *props, char *name, char *value)
161 char *v = get_property_value(props, name);
164 return strcmp(v, value)==0;
167 void free_properties(Property *props)
172 for(i=0; props[i].name; ++i)
175 free(props[i].value);
180 char **get_mounted_devices(void)
184 char **mounted = NULL;
187 mtab = setmntent("/etc/mtab", "r");
191 while((me = getmntent(mtab)))
193 mounted = (char **)realloc(mounted, (n_mounted+2)*sizeof(char *));
194 mounted[n_mounted] = strdup(me->mnt_fsname);
199 mounted[n_mounted] = NULL;
204 int is_mounted(char **mounted, char *devname)
207 for(i=0; mounted[i]; ++i)
208 if(!strcmp(devname, mounted[i]))
213 void free_mounted_devices(char **mounted)
218 for(i=0; mounted[i]; ++i)
223 char **get_device_nodes(char *dirname)
232 char **checked = NULL;
236 dir = opendir(dirname);
240 while((de = readdir(dir)))
245 if(de->d_name[0]=='.' && (de->d_name[1]==0 || (de->d_name[1]=='.' && de->d_name[2]==0)))
248 snprintf(fnbuf, sizeof(fnbuf), "%s/%s", dirname, de->d_name);
252 if(S_ISLNK(st.st_mode))
255 len = readlink(fnbuf, linkbuf, sizeof(linkbuf)-1);
265 for(i=0; (!duplicate && i<n_checked); ++i)
266 if(strcmp(node, checked[i])==0)
272 printf("Device %s is a duplicate\n", fnbuf);
276 checked = (char **)realloc(checked, (n_checked+1)*sizeof(char *));
277 checked[n_checked] = strdup(node);
280 nodes = (char **)realloc(nodes, (n_nodes+2)*sizeof(char *));
281 nodes[n_nodes] = strdup(fnbuf);
288 for(i=0; i<n_checked; ++i)
294 nodes[n_nodes] = NULL;
299 Device *get_devices(void)
302 Device *devices = NULL;
304 char **mounted = NULL;
307 nodes = get_device_nodes("/dev/disk/by-id");
308 mounted = get_mounted_devices();
310 for(i=0; nodes[i]; ++i)
313 printf("Examining device %s\n", nodes[i]);
315 Property *props = get_device_properties(nodes[i]);
319 printf(" No properties\n");
326 for(j=0; props[j].name; ++j)
327 printf(" %s = %s\n", props[j].name, props[j].value);
330 if(match_property_value(props, "ID_BUS", "usb") && match_property_value(props, "DEVTYPE", "partition"))
341 printf(" Using device\n");
343 devname = get_property_value(props, "DEVNAME");
345 label = get_property_value(props, "ID_FS_LABEL");
347 label = get_property_value(props, "ID_FS_UUID");
353 for(ptr=label; *ptr; ++ptr)
358 vendor = get_property_value(props, "ID_VENDOR");
359 model = get_property_value(props, "ID_MODEL");
361 pos = snprintf(buf, sizeof(buf), "%s", label);
363 pos += snprintf(buf+pos, sizeof(buf)-pos, " (%s %s)", vendor, model);
367 devices = (Device *)realloc(devices, (n_devices+2)*sizeof(Device));
368 devices[n_devices].node = nodes[i];
369 devices[n_devices].label = strdup(label);
370 devices[n_devices].description = strdup(buf);
371 devices[n_devices].mounted = is_mounted(mounted, devname);
372 devices[n_devices].time = st.st_mtime;
377 free_properties(props);
381 free_mounted_devices(mounted);
385 devices[n_devices].node = NULL;
386 devices[n_devices].label = NULL;
387 devices[n_devices].description = NULL;
393 void free_devices(Device *devices)
398 for(i=0; devices[i].node; ++i)
400 free(devices[i].node);
401 free(devices[i].label);
402 free(devices[i].description);
407 void row_activated(GtkTreeView *list, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data)
411 int umount = *(int *)user_data;
413 model = gtk_tree_view_get_model(list);
415 if(gtk_tree_model_get_iter(model, &iter, path))
421 gtk_tree_model_get(model, &iter, 1, &device, -1);
431 printf("Running pumount %s\n", device->node);
433 printf("Running pmount %s %s\n", device->node, device->label);
441 execl("/usr/bin/pumount", "pumount", device->node, NULL);
443 execl("/usr/bin/pmount", "pmount", device->node, device->label, NULL);
458 len = read(pipe_fd[0], buf+pos, sizeof(buf)-pos-1);
466 waitpid(pid, &status, 0);
467 if(!WIFEXITED(status) || WEXITSTATUS(status))
471 dialog = gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", buf);
472 g_signal_connect(dialog, "response", >k_main_quit, NULL);
473 gtk_widget_show_all(dialog);
486 int main(int argc, char **argv)
492 GtkTreeSelection *selection;
501 gtk_init(&argc, &argv);
503 while((opt = getopt(argc, argv, "vu"))!=-1) switch(opt)
513 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
514 gtk_container_set_border_width(GTK_CONTAINER(window), 5);
515 g_signal_connect(window, "destroy", >k_main_quit, NULL);
517 viewport = gtk_viewport_new(NULL, NULL);
518 gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_IN);
519 gtk_container_add(GTK_CONTAINER(window), viewport);
521 list = gtk_tree_view_new();
522 gtk_container_add(GTK_CONTAINER(viewport), list);
523 g_signal_connect(list, "row-activated", (GCallback)&row_activated, &umount);
525 store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
526 gtk_tree_view_set_model(GTK_TREE_VIEW(list), GTK_TREE_MODEL(store));
527 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(list),
528 -1, "Device", gtk_cell_renderer_text_new(), "text", 0, NULL);
530 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(list));
532 devices = get_devices();
537 for(i=0; devices[i].node; ++i)
538 if(!devices[i].mounted==!umount)
540 gtk_list_store_append(store, &iter);
541 gtk_list_store_set(store, &iter, 0, devices[i].description, 1, &devices[i], -1);
542 if(devices[i].time>latest)
544 latest = devices[i].time;
545 gtk_tree_selection_select_iter(selection, &iter);
554 gtk_widget_show_all(window);
559 dialog = gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
560 "No devices to %s", (umount ? "unmount" : "mount"));
561 g_signal_connect(dialog, "response", >k_main_quit, NULL);
562 gtk_widget_show_all(dialog);
567 free_devices(devices);