문제

I want my program always know all of the mountpoints. After a quick google I found that getmntent() and friends can tell me what is mounted. I realize I could do this everytime that I needed to know what was mounted, but is there some way to recognise when something gets mounted/unmounted so I don't have to keep reading the file? Is this what dBus does?

Any hints would be helpful. I'm trying to start programming (I took a course on C in 2002, when I was in college.) and found a feature I want to implement in an open source program.

도움이 되었습니까?

해결책

Based on the mention of getmntent(), I'm going to guess you're dealing with Linux (other Unices also include it, but they're a lot less common nowadays...). If that's the case, man inotify should get you started.

다른 팁

If you're coding for Linux (or are using GNOME libraries nonetheless), GNOME's GIO provides a good API for this. Here's a trivial drive monitor I wrote in C that uses GTK and GIO:

#include <gio/gio.h>
#include <gtk/gtk.h>
#include <string.h>

typedef struct {
    GtkWidget *window;
    GtkWidget *vbox;
    GtkWidget *scrolled_window;
    GtkWidget *view;
    GtkWidget *button;

    GtkListStore *store;
    GVolumeMonitor *monitor;
} Context[1];

enum {
    COL_DRIVE,
    COL_ICON,
    COL_NAME,
    NUM_COLS
};

static int find_drive(GtkTreeModel *model, GDrive *drive, GtkTreeIter *iter)
{
    gboolean valid;

    valid = gtk_tree_model_get_iter_first(model, iter);
    while (valid) {
        GDrive *cur;
        gtk_tree_model_get(model, iter, COL_DRIVE, &cur, -1);

        if (cur == drive)
            return 1;

        valid = gtk_tree_model_iter_next(model, iter);
    }

    return 0;
}

static void set_drive_iter(Context ctx, GDrive *drive, GtkTreeIter *iter)
{
    GIcon *icon = g_drive_get_icon(drive);
    gchar *name = g_drive_get_name(drive);

    gtk_list_store_set(ctx->store, iter,
        COL_DRIVE, drive,
        COL_ICON, icon,
        COL_NAME, name,
        -1);

    g_free(name);
}

static void add_drive(Context ctx, GDrive *drive)
{
    GtkTreeIter iter;
    gtk_list_store_append(ctx->store, &iter);
    set_drive_iter(ctx, drive, &iter);
}

static void refresh_drive_list(Context ctx)
{
    GList *drives, *l;
    drives = g_volume_monitor_get_connected_drives(ctx->monitor);

    gtk_list_store_clear(ctx->store);

    for (l = drives; l; l = l->next)
        add_drive(ctx, l->data);
}

static void update_drive(Context ctx, GDrive *drive)
{
    GtkTreeModel *model = GTK_TREE_MODEL(ctx->store);
    GtkTreeIter iter;

    if (find_drive(model, drive, &iter))
        set_drive_iter(ctx, drive, &iter);
    else
        refresh_drive_list(ctx); //Shouldn't happen
}

static void remove_drive(Context ctx, GDrive *drive)
{
    GtkTreeModel *model = GTK_TREE_MODEL(ctx->store);
    GtkTreeIter iter;

    if (find_drive(model, drive, &iter))
        gtk_list_store_remove(ctx->store, &iter);
    else
        refresh_drive_list(ctx); //Shouldn't happen
}

static void init_drive_list(Context ctx)
{
    ctx->store = gtk_list_store_new(3, G_TYPE_POINTER, G_TYPE_ICON, G_TYPE_STRING);
    refresh_drive_list(ctx);
}

static void init_drive_view(Context ctx)
{
    GtkTreeViewColumn *column;
    GtkCellRenderer *renderer;

    ctx->view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(ctx->store));
    g_object_set(ctx->view,
        "headers-visible", FALSE,
        NULL);

    renderer = gtk_cell_renderer_pixbuf_new();
    g_object_set(renderer, "stock-size", GTK_ICON_SIZE_DIALOG, NULL);
    column = gtk_tree_view_column_new_with_attributes("Icon", renderer, "gicon", COL_ICON, NULL);
    gtk_tree_view_column_set_resizable(column, TRUE);
    gtk_tree_view_append_column(GTK_TREE_VIEW(ctx->view), column);

    renderer = gtk_cell_renderer_text_new();
    column = gtk_tree_view_column_new_with_attributes("Name", renderer, "text", COL_NAME, NULL);
    gtk_tree_view_column_set_resizable(column, TRUE);
    gtk_tree_view_append_column(GTK_TREE_VIEW(ctx->view), column);
}

static void print_drive_info(GDrive *drive)
{
    GIcon *icon;
    gchar *name, *icon_string;

    name = g_drive_get_name(drive);
    icon = g_drive_get_icon(drive);
    icon_string = g_icon_to_string(icon);
    g_object_unref(icon);

    g_print("\tname: %s\n\ticon: %s\n",
        name ? name : "(null)",
        icon_string ? icon_string : "(null)");

    g_free(name);
    g_free(icon_string);
}

static void on_drive_changed(GVolumeMonitor *volume_monitor, GDrive *drive, Context ctx)
{
    g_print("Drive changed:\n");
    print_drive_info(drive);
    update_drive(ctx, drive);
}

static void on_drive_connected(GVolumeMonitor *volume_monitor, GDrive *drive, Context ctx)
{
    g_print("Drive connected:\n");
    print_drive_info(drive);
    add_drive(ctx, drive);
}

static void on_drive_disconnected(GVolumeMonitor *volume_monitor, GDrive *drive, Context ctx)
{
    g_print("Drive disconnected:\n");
    print_drive_info(drive);
    remove_drive(ctx, drive);
}

static void on_refresh_clicked(GtkButton *button, Context ctx)
{
    refresh_drive_list(ctx);
}

int main(int argc, char *argv[])
{
    Context ctx;
    memset(ctx, 0, sizeof(ctx));
    gtk_init(&argc, &argv);

    ctx->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    g_signal_connect(ctx->window, "destroy", G_CALLBACK(gtk_main_quit), NULL);

    ctx->vbox = gtk_vbox_new(FALSE, 0);
    gtk_widget_show(ctx->vbox);
    gtk_container_add(GTK_CONTAINER(ctx->window), ctx->vbox);

    ctx->scrolled_window = gtk_scrolled_window_new(NULL, NULL);
    gtk_scrolled_window_set_policy(
        GTK_SCROLLED_WINDOW(ctx->scrolled_window),
        GTK_POLICY_AUTOMATIC,
        GTK_POLICY_AUTOMATIC);
    gtk_box_pack_start(GTK_BOX(ctx->vbox), ctx->scrolled_window, TRUE, TRUE, 0);
    gtk_widget_show(ctx->scrolled_window);

    ctx->monitor = g_volume_monitor_get();
    g_signal_connect(ctx->monitor, "drive-changed", G_CALLBACK(on_drive_changed), ctx);
    g_signal_connect(ctx->monitor, "drive-connected", G_CALLBACK(on_drive_connected), ctx);
    g_signal_connect(ctx->monitor, "drive-disconnected", G_CALLBACK(on_drive_disconnected), ctx);

    init_drive_list(ctx);
    init_drive_view(ctx);
    gtk_widget_show(ctx->view);
    gtk_container_add(GTK_CONTAINER(ctx->scrolled_window), ctx->view);

    ctx->button = gtk_button_new_from_stock(GTK_STOCK_REFRESH);
    g_signal_connect(ctx->button, "clicked", G_CALLBACK(on_refresh_clicked), ctx);
    gtk_widget_show(ctx->button);
    gtk_box_pack_start(GTK_BOX(ctx->vbox), ctx->button, FALSE, FALSE, 0);

    gtk_window_set_default_size(GTK_WINDOW(ctx->window), 500, 500);
    gtk_widget_show(ctx->window);

    gtk_main();
    return 0;
}

Compile with gcc $(pkg-config --cflags --libs gtk+-2.0) volumes.c -o volumes . Test it by running it, then plugging in a pen drive. It should update on the fly. It even displays appropriate icons.

Note that this monitors drives, not mounts. GVolumeMonitor can monitor mounts as well (see "mount-added" and "mount-removed" in devhelp). You'll have to learn a little bit about the GObject system to use this. Good luck!

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top