8 start_service_by_name(void)
12 GDBusConnection *conn;
14 conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error);
16 fprintf(stderr, "Could not get session bus connection: %s\n",
22 var = g_dbus_connection_call_sync(conn,
23 "org.freedesktop.DBus",
24 "/org/freedesktop/DBus",
25 "org.freedesktop.DBus",
28 "org.lightmediascanner", 0),
29 G_VARIANT_TYPE("(u)"),
30 G_DBUS_CALL_FLAGS_NONE,
39 fprintf(stderr, "Could not start org.lightmediascanner: %s\n",
52 void (*action)(struct app *app);
59 print_server(GDBusProxy *proxy)
64 nameowner = g_dbus_proxy_get_name_owner(proxy);
66 puts("Server is not running.");
70 printf("Server at %s\n", nameowner);
71 props = g_dbus_proxy_get_cached_property_names(proxy);
75 for (itr = props; *itr != NULL; itr++) {
76 GVariant *value = g_dbus_proxy_get_cached_property(proxy, *itr);
77 char *str = g_variant_print(value, TRUE);
78 printf("\t%s = %s\n", *itr, str);
79 g_variant_unref(value);
88 do_status(struct app *app)
90 print_server(app->proxy);
91 g_main_loop_quit(app->loop);
92 app->ret = EXIT_SUCCESS;
96 on_properties_changed(GDBusProxy *proxy, GVariant *changed, const char *const *invalidated, gpointer user_data)
98 struct app *app = user_data;
100 printf("%015.3f --- Properties Changed ---\n",
101 g_timer_elapsed(app->timer, NULL));
103 if (g_variant_n_children(changed) > 0) {
108 printf("Changed Properties:");
109 g_variant_get(changed, "a{sv}", &itr);
110 while (g_variant_iter_loop(itr, "{&sv}", &prop, &value)) {
112 str = g_variant_print(value, TRUE);
113 printf(" %s=%s", prop, str);
116 g_variant_iter_free(itr);
120 if (invalidated[0] != NULL) {
121 const char * const *itr;
122 printf("Invalidated Properties:");
123 for (itr = invalidated; *itr != NULL; itr++)
132 do_delayed_print_server(gpointer data)
134 GDBusProxy *proxy = data;
138 nameowner = g_dbus_proxy_get_name_owner(proxy);
145 props = g_dbus_proxy_get_cached_property_names(proxy);
147 g_timeout_add(1000, do_delayed_print_server, proxy);
157 on_name_owner_notify(GObject *object, GParamSpec *pspec, gpointer user_data)
159 GDBusProxy *proxy = G_DBUS_PROXY(object);
160 struct app *app = user_data;
162 printf("%015.3f --- Name Owner Changed ---\n",
163 g_timer_elapsed(app->timer, NULL));
164 do_delayed_print_server(proxy);
168 do_monitor(struct app *app)
170 app->timer = g_timer_new();
171 g_timer_start(app->timer);
173 print_server(app->proxy);
174 g_signal_connect(app->proxy, "g-properties-changed",
175 G_CALLBACK(on_properties_changed),
177 g_signal_connect(app->proxy, "notify::g-name-owner",
178 G_CALLBACK(on_name_owner_notify),
183 on_properties_changed_check_lock(GDBusProxy *proxy, GVariant *changed, const char *const *invalidated, gpointer user_data)
185 struct app *app = user_data;
186 gboolean lost_lock = FALSE;
188 if (g_variant_n_children(changed) > 0) {
193 g_variant_get(changed, "a{sv}", &itr);
194 while (g_variant_iter_loop(itr, "{&sv}", &prop, &value)) {
195 if (strcmp(prop, "WriteLocked") == 0) {
196 if (!g_variant_get_boolean(value))
201 g_variant_iter_free(itr);
204 if (invalidated[0] != NULL) {
205 const char * const *itr;
206 for (itr = invalidated; *itr != NULL; itr++) {
207 if (strcmp(*itr, "WriteLocked") == 0) {
215 fputs("Lost lock, exit.\n", stderr);
216 app->ret = EXIT_FAILURE;
217 g_main_loop_quit(app->loop);
222 do_write_lock(struct app *app)
225 GError *error = NULL;
228 nameowner = g_dbus_proxy_get_name_owner(app->proxy);
230 fputs("Server is not running, cannot get write lock!\n", stderr);
231 app->ret = EXIT_FAILURE;
232 g_main_loop_quit(app->loop);
236 printf("Server at %s, try to get write lock\n", nameowner);
239 g_signal_connect(app->proxy, "g-properties-changed",
240 G_CALLBACK(on_properties_changed_check_lock),
243 ret = g_dbus_proxy_call_sync(app->proxy, "RequestWriteLock",
245 G_DBUS_CALL_FLAGS_NONE, -1, NULL,
249 fprintf(stderr, "Could not get write lock: %s\n", error->message);
251 app->ret = EXIT_FAILURE;
252 g_main_loop_quit(app->loop);
256 g_variant_unref(ret);
257 puts("Got write lock, close program to release it.");
261 on_properties_changed_check_scan(GDBusProxy *proxy, GVariant *changed, const char *const *invalidated, gpointer user_data)
263 struct app *app = user_data;
265 if (g_variant_n_children(changed) > 0) {
270 g_variant_get(changed, "a{sv}", &itr);
271 while (g_variant_iter_loop(itr, "{&sv}", &prop, &value)) {
272 if (strcmp(prop, "IsScanning") == 0) {
273 if (g_variant_get_boolean(value) && !app->timer) {
274 app->timer = g_timer_new();
275 g_timer_start(app->timer);
276 } else if (!g_variant_get_boolean(value) && app->timer) {
277 g_timer_stop(app->timer);
278 app->ret = EXIT_SUCCESS;
279 g_main_loop_quit(app->loop);
281 g_variant_unref(value);
284 g_variant_unref(value);
286 g_variant_iter_free(itr);
289 if (invalidated[0] != NULL) {
290 const char * const *itr;
291 for (itr = invalidated; *itr != NULL; itr++) {
292 if (strcmp(*itr, "IsScanning") == 0) {
293 fputs("Lost server, exit.\n", stderr);
294 app->ret = EXIT_FAILURE;
295 g_main_loop_quit(app->loop);
303 on_signal(GDBusProxy *proxy, gchar *sender, gchar *signal, GVariant *params, gpointer user_data)
305 if (g_str_equal(signal, "ScanProgress")) {
306 const gchar *category = NULL, *path = NULL;
307 guint64 uptodate = 0, processed = 0, deleted = 0,
308 skipped = 0, errors = 0;
310 g_variant_get(params, "(&s&sttttt)",
319 printf("Scan Progress %s:%s uptodate=%"G_GUINT64_FORMAT", "
320 "processed=%"G_GUINT64_FORMAT", deleted=%"G_GUINT64_FORMAT", "
321 "skipped=%"G_GUINT64_FORMAT", errors=%"G_GUINT64_FORMAT"\n",
322 category, path, uptodate, processed, deleted, skipped, errors);
327 populate_scan_params(gpointer key, gpointer value, gpointer user_data)
329 const char *category = key;
330 const GArray *paths = value;
331 GVariantBuilder *builder = user_data;
332 GVariantBuilder *sub;
335 sub = g_variant_builder_new(G_VARIANT_TYPE("as"));
336 for (itr = (char **)paths->data; *itr != NULL; itr++)
337 g_variant_builder_add(sub, "s", *itr);
339 g_variant_builder_add(builder, "{sv}", category, g_variant_builder_end(sub));
340 g_variant_builder_unref(sub);
344 do_free_array(gpointer data)
346 g_array_free(data, TRUE);
350 do_scan(struct app *app)
352 GVariantBuilder *builder;
354 GError *error = NULL;
357 GHashTable *categories;
359 nameowner = g_dbus_proxy_get_name_owner(app->proxy);
361 fputs("Server is not running, cannot start scan!\n", stderr);
362 app->ret = EXIT_FAILURE;
363 g_main_loop_quit(app->loop);
367 printf("Server at %s, try to start scan\n", nameowner);
370 g_signal_connect(app->proxy, "g-properties-changed",
371 G_CALLBACK(on_properties_changed_check_scan),
373 g_signal_connect(app->proxy, "g-signal",
374 G_CALLBACK(on_signal),
377 categories = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, do_free_array);
378 for (i = 0; i < app->argc; i++) {
380 char *arg = app->argv[i];
381 char *sep = strchr(arg, ':');
386 fprintf(stderr, "Ignored scan parameter: invalid format '%s'\n",
394 arr = g_hash_table_lookup(categories, arg);
396 arr = g_array_new(TRUE, FALSE, sizeof(char *));
397 g_hash_table_insert(categories, arg, arr);
401 g_array_append_val(arr, path);
404 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
405 g_hash_table_foreach(categories, populate_scan_params, builder);
407 ret = g_dbus_proxy_call_sync(app->proxy, "Scan",
408 g_variant_new("(a{sv})", builder),
409 G_DBUS_CALL_FLAGS_NONE, -1, NULL,
411 g_variant_builder_unref(builder);
412 g_hash_table_destroy(categories);
415 fprintf(stderr, "Could not start scan: %s\n", error->message);
417 app->ret = EXIT_FAILURE;
418 g_main_loop_quit(app->loop);
422 g_variant_unref(ret);
426 do_stop(struct app *app)
429 GError *error = NULL;
432 nameowner = g_dbus_proxy_get_name_owner(app->proxy);
434 fputs("Server is not running, cannot stop scan!\n", stderr);
435 app->ret = EXIT_FAILURE;
436 g_main_loop_quit(app->loop);
440 printf("Server at %s, try to stop scan\n", nameowner);
443 ret = g_dbus_proxy_call_sync(app->proxy, "Stop",
445 G_DBUS_CALL_FLAGS_NONE, -1, NULL,
449 fprintf(stderr, "Could not stop scan: %s\n", error->message);
451 app->ret = EXIT_FAILURE;
452 g_main_loop_quit(app->loop);
456 app->ret = EXIT_SUCCESS;
457 g_main_loop_quit(app->loop);
458 g_variant_unref(ret);
462 do_action(gpointer data)
464 struct app *app = data;
470 print_help(const char *prog)
475 "Action is one of:\n"
476 "\tstatus print server properties and exit.\n"
477 "\tmonitor monitor server and its properties.\n"
478 "\twrite-lock try to get a write-lock and keep it while running.\n"
479 "\tscan [params] start scan. May receive parameters as a series of \n"
480 "\t CATEGORY:PATH to limit scan.\n"
481 "\tstop stop ongoing scan.\n"
482 "\thelp this message.\n"
488 main(int argc, char *argv[])
490 GError *error = NULL;
495 fprintf(stderr, "Missing action, see --help.\n");
499 for (i = 1; i < argc; i++) {
500 if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
506 if (strcmp(argv[1], "status") == 0)
507 app.action = do_status;
508 else if (strcmp(argv[1], "monitor") == 0)
509 app.action = do_monitor;
510 else if (strcmp(argv[1], "write-lock") == 0)
511 app.action = do_write_lock;
512 else if (strcmp(argv[1], "scan") == 0)
513 app.action = do_scan;
514 else if (strcmp(argv[1], "stop") == 0)
515 app.action = do_stop;
516 else if (strcmp(argv[1], "help") == 0) {
520 fprintf(stderr, "Unknown action '%s', see --help.\n", argv[1]);
524 if (!start_service_by_name())
528 app.loop = g_main_loop_new(NULL, FALSE);
529 app.proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SESSION,
530 G_DBUS_PROXY_FLAGS_NONE,
532 "org.lightmediascanner",
533 "/org/lightmediascanner/Scanner1",
534 "org.lightmediascanner.Scanner1",
538 g_error("Could not create proxy: %s", error->message);
545 app.ret = EXIT_SUCCESS;
547 g_idle_add(do_action, &app);
549 g_main_loop_run(app.loop);
550 g_object_unref(app.proxy);
551 g_main_loop_unref(app.loop);
554 printf("Elapsed time: %0.3f seconds\n",
555 g_timer_elapsed(app.timer, NULL));
556 g_timer_destroy(app.timer);