00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <locale.h>
00027 #include <glib.h>
00028
00029 #include "xmms_configuration.h"
00030 #include "xmmsc/xmmsc_util.h"
00031 #include "xmmspriv/xmms_plugin.h"
00032 #include "xmmspriv/xmms_config.h"
00033 #include "xmmspriv/xmms_playlist.h"
00034 #include "xmmspriv/xmms_collection.h"
00035 #include "xmmspriv/xmms_signal.h"
00036 #include "xmmspriv/xmms_symlink.h"
00037 #include "xmmspriv/xmms_checkroot.h"
00038 #include "xmmspriv/xmms_medialib.h"
00039 #include "xmmspriv/xmms_output.h"
00040 #include "xmmspriv/xmms_ipc.h"
00041 #include "xmmspriv/xmms_log.h"
00042 #include "xmmspriv/xmms_sqlite.h"
00043 #include "xmmspriv/xmms_xform.h"
00044 #include "xmmspriv/xmms_bindata.h"
00045 #include "xmmspriv/xmms_utils.h"
00046 #include "xmmspriv/xmms_visualization.h"
00047
00048 #include <stdio.h>
00049 #include <stdlib.h>
00050 #include <string.h>
00051 #include <unistd.h>
00052 #include <signal.h>
00053 #include <sys/stat.h>
00054 #include <fcntl.h>
00055
00056
00057
00058
00059 static void quit (xmms_object_t *object, xmms_error_t *error);
00060 static GTree *stats (xmms_object_t *object, xmms_error_t *error);
00061 static void hello (xmms_object_t *object, gint protocolver, const gchar *client, xmms_error_t *error);
00062 static void install_scripts (const gchar *into_dir);
00063 static xmms_xform_object_t *xform_obj;
00064 static xmms_bindata_t *bindata_obj;
00065
00066 XMMS_CMD_DEFINE (quit, quit, xmms_object_t*, NONE, NONE, NONE);
00067 XMMS_CMD_DEFINE (hello, hello, xmms_object_t *, NONE, INT32, STRING);
00068 XMMS_CMD_DEFINE (stats, stats, xmms_object_t *, DICT, NONE, NONE);
00069 XMMS_CMD_DEFINE (plugin_list, xmms_plugin_client_list, xmms_object_t *, LIST, INT32, NONE);
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088 struct xmms_main_St {
00089 xmms_object_t object;
00090 xmms_output_t *output;
00091 time_t starttime;
00092 };
00093
00094 typedef struct xmms_main_St xmms_main_t;
00095
00096
00097 static GMainLoop *mainloop;
00098
00099
00100 static gchar *conffile = NULL;
00101
00102
00103
00104
00105 static GTree *
00106 stats (xmms_object_t *object, xmms_error_t *error)
00107 {
00108 GTree *ret;
00109 gint starttime;
00110
00111 ret = g_tree_new_full ((GCompareDataFunc) strcmp, NULL,
00112 NULL, (GDestroyNotify) xmmsv_unref);
00113
00114 starttime = ((xmms_main_t*)object)->starttime;
00115
00116 g_tree_insert (ret, (gpointer) "version",
00117 xmmsv_new_string (XMMS_VERSION));
00118 g_tree_insert (ret, (gpointer) "uptime",
00119 xmmsv_new_int (time (NULL) - starttime));
00120
00121 return ret;
00122 }
00123
00124
00125
00126
00127
00128
00129
00130
00131 static void
00132 do_scriptdir (const gchar *scriptdir)
00133 {
00134 GError *err = NULL;
00135 GDir *dir;
00136 const gchar *f;
00137 gchar *argv[2] = {NULL, NULL};
00138
00139 XMMS_DBG ("Running scripts in %s", scriptdir);
00140 if (!g_file_test (scriptdir, G_FILE_TEST_IS_DIR)) {
00141 g_mkdir_with_parents (scriptdir, 0755);
00142 install_scripts (scriptdir);
00143 }
00144
00145 dir = g_dir_open (scriptdir, 0, &err);
00146 if (!dir) {
00147 xmms_log_error ("Could not open script dir '%s' error: %s", scriptdir, err->message);
00148 return;
00149 }
00150
00151 while ((f = g_dir_read_name (dir))) {
00152 argv[0] = g_strdup_printf ("%s/%s", scriptdir, f);
00153 if (g_file_test (argv[0], G_FILE_TEST_IS_EXECUTABLE)) {
00154 if (!g_spawn_async (g_get_home_dir (),
00155 argv, NULL, 0, NULL, NULL, NULL, &err)) {
00156 xmms_log_error ("Could not run script '%s', error: %s",
00157 argv[0], err->message);
00158 }
00159 }
00160 g_free (argv[0]);
00161 }
00162
00163 g_dir_close (dir);
00164
00165 }
00166
00167
00168
00169
00170
00171 static void
00172 load_config ()
00173 {
00174 gchar configdir[PATH_MAX];
00175
00176 if (!conffile) {
00177 conffile = XMMS_BUILD_PATH ("xmms2.conf");
00178 }
00179
00180 g_assert (strlen (conffile) <= XMMS_MAX_CONFIGFILE_LEN);
00181
00182 if (!xmms_userconfdir_get (configdir, sizeof (configdir))) {
00183 xmms_log_error ("Could not get path to config dir");
00184 } else if (!g_file_test (configdir, G_FILE_TEST_IS_DIR)) {
00185 g_mkdir_with_parents (configdir, 0755);
00186 }
00187
00188 xmms_config_init (conffile);
00189 }
00190
00191
00192
00193
00194
00195
00196
00197 static void
00198 change_output (xmms_object_t *object, xmmsv_t *_data, gpointer userdata)
00199 {
00200 xmms_output_plugin_t *plugin;
00201 xmms_main_t *mainobj = (xmms_main_t*)userdata;
00202 const gchar *outname;
00203
00204 if (!mainobj->output)
00205 return;
00206
00207 outname = xmms_config_property_get_string ((xmms_config_property_t *) object);
00208
00209 xmms_log_info ("Switching to output %s", outname);
00210
00211 plugin = (xmms_output_plugin_t *)xmms_plugin_find (XMMS_PLUGIN_TYPE_OUTPUT, outname);
00212 if (!plugin) {
00213 xmms_log_error ("Baaaaad output plugin, try to change the output.plugin config variable to something usefull");
00214 } else {
00215 if (!xmms_output_plugin_switch (mainobj->output, plugin)) {
00216 xmms_log_error ("Baaaaad output plugin, try to change the output.plugin config variable to something usefull");
00217 }
00218 }
00219 }
00220
00221
00222
00223
00224
00225 static void
00226 xmms_main_destroy (xmms_object_t *object)
00227 {
00228 xmms_main_t *mainobj = (xmms_main_t *) object;
00229 xmms_object_cmd_arg_t arg;
00230 xmms_config_property_t *cv;
00231
00232 cv = xmms_config_lookup ("core.shutdownpath");
00233 do_scriptdir (xmms_config_property_get_string (cv));
00234
00235
00236 xmms_object_cmd_arg_init (&arg);
00237
00238 xmms_object_cmd_call (XMMS_OBJECT (mainobj->output),
00239 XMMS_IPC_CMD_STOP, &arg);
00240
00241 g_usleep (G_USEC_PER_SEC);
00242
00243 xmms_visualization_destroy ();
00244 xmms_object_unref (mainobj->output);
00245
00246 xmms_object_unref (xform_obj);
00247
00248 xmms_config_save ();
00249
00250 xmms_config_shutdown ();
00251
00252 xmms_plugin_shutdown ();
00253
00254 xmms_ipc_object_unregister (XMMS_IPC_OBJECT_MAIN);
00255 xmms_ipc_shutdown ();
00256
00257 xmms_log_shutdown ();
00258 }
00259
00260
00261
00262
00263 static void
00264 hello (xmms_object_t *object, gint protocolver, const gchar *client, xmms_error_t *error)
00265 {
00266 if (protocolver != XMMS_IPC_PROTOCOL_VERSION) {
00267 xmms_log_info ("Client '%s' with bad protocol version (%d, not %d) connected", client, protocolver, XMMS_IPC_PROTOCOL_VERSION);
00268 xmms_error_set (error, XMMS_ERROR_INVAL, "Bad protocol version");
00269 return;
00270 }
00271 XMMS_DBG ("Client '%s' connected", client);
00272 }
00273
00274 static gboolean
00275 kill_server (gpointer object) {
00276 xmms_object_emit_f (XMMS_OBJECT (object),
00277 XMMS_IPC_SIGNAL_QUIT,
00278 XMMSV_TYPE_INT32,
00279 time (NULL)-((xmms_main_t*)object)->starttime);
00280
00281 xmms_object_unref (object);
00282
00283 exit (EXIT_SUCCESS);
00284 }
00285
00286
00287
00288
00289
00290 static void
00291 quit (xmms_object_t *object, xmms_error_t *error)
00292 {
00293
00294
00295
00296
00297
00298 g_timeout_add (1, kill_server, object);
00299 }
00300
00301 static void
00302 install_scripts (const gchar *into_dir)
00303 {
00304 GDir *dir;
00305 GError *err = NULL;
00306 gchar path[PATH_MAX];
00307 const gchar *f;
00308 gchar *s;
00309
00310 s = strrchr (into_dir, G_DIR_SEPARATOR);
00311 if (!s)
00312 return;
00313
00314 s++;
00315
00316 g_snprintf (path, PATH_MAX, "%s/scripts/%s", SHAREDDIR, s);
00317 xmms_log_info ("Installing scripts from %s", path);
00318 dir = g_dir_open (path, 0, &err);
00319 if (!dir) {
00320 xmms_log_error ("Global script directory not found");
00321 return;
00322 }
00323
00324 while ((f = g_dir_read_name (dir))) {
00325 gchar *source = g_strdup_printf ("%s/%s", path, f);
00326 gchar *dest = g_strdup_printf ("%s/%s", into_dir, f);
00327 if (!xmms_symlink_file (source, dest)) {
00328 break;
00329 }
00330 g_free (source);
00331 g_free (dest);
00332 }
00333
00334 g_dir_close (dir);
00335 }
00336
00337
00338
00339
00340 void
00341 print_version ()
00342 {
00343 printf ("XMMS2 version " XMMS_VERSION "\n");
00344 printf ("Copyright (C) 2003-2009 XMMS2 Team\n");
00345 printf ("This is free software; see the source for copying conditions.\n");
00346 printf ("There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n");
00347 printf ("PARTICULAR PURPOSE.\n");
00348 printf (" Using glib version %d.%d.%d (compiled against "
00349 G_STRINGIFY (GLIB_MAJOR_VERSION) "."
00350 G_STRINGIFY (GLIB_MINOR_VERSION) "."
00351 G_STRINGIFY (GLIB_MICRO_VERSION) ")\n",
00352 glib_major_version,
00353 glib_minor_version,
00354 glib_micro_version);
00355 xmms_sqlite_print_version ();
00356
00357 exit (EXIT_SUCCESS);
00358 }
00359
00360
00361
00362
00363 int
00364 main (int argc, char **argv)
00365 {
00366 xmms_output_plugin_t *o_plugin;
00367 xmms_config_property_t *cv;
00368 xmms_main_t *mainobj;
00369 int loglevel = 1;
00370 xmms_playlist_t *playlist;
00371 gchar default_path[XMMS_PATH_MAX + 16], *tmp;
00372 gboolean verbose = FALSE;
00373 gboolean quiet = FALSE;
00374 gboolean version = FALSE;
00375 gboolean nologging = FALSE;
00376 gboolean runasroot = FALSE;
00377 gboolean showhelp = FALSE;
00378 const gchar *outname = NULL;
00379 const gchar *ipcpath = NULL;
00380 gchar *ppath = NULL;
00381 int status_fd = -1;
00382 GOptionContext *context = NULL;
00383 GError *error = NULL;
00384
00385 setlocale (LC_ALL, "");
00386
00387
00388
00389
00390 GOptionEntry opts[] = {
00391 {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Increase verbosity", NULL},
00392 {"quiet", 'q', 0, G_OPTION_ARG_NONE, &quiet, "Decrease verbosity", NULL},
00393 {"version", 'V', 0, G_OPTION_ARG_NONE, &version, "Print version", NULL},
00394 {"no-logging", 'n', 0, G_OPTION_ARG_NONE, &nologging, "Disable logging", NULL},
00395 {"output", 'o', 0, G_OPTION_ARG_STRING, &outname, "Use 'x' as output plugin", "<x>"},
00396 {"ipc-socket", 'i', 0, G_OPTION_ARG_FILENAME, &ipcpath, "Listen to socket 'url'", "<url>"},
00397 {"plugindir", 'p', 0, G_OPTION_ARG_FILENAME, &ppath, "Search for plugins in directory 'foo'", "<foo>"},
00398 {"conf", 'c', 0, G_OPTION_ARG_FILENAME, &conffile, "Specify alternate configuration file", "<file>"},
00399 {"status-fd", 's', 0, G_OPTION_ARG_INT, &status_fd, "Specify a filedescriptor to write to when started", "fd"},
00400 {"yes-run-as-root", 0, 0, G_OPTION_ARG_NONE, &runasroot, "Give me enough rope to shoot myself in the foot", NULL},
00401 {"show-help", 'h', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &showhelp, "Use --help or -? instead", NULL},
00402 {NULL}
00403 };
00404
00405
00406 if (glib_major_version != GLIB_MAJOR_VERSION ||
00407 glib_minor_version < GLIB_MINOR_VERSION) {
00408 g_print ("xmms2d is build against version %d.%d,\n"
00409 "but is (runtime) linked against %d.%d.\n"
00410 "Refusing to start.\n",
00411 GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION,
00412 glib_major_version, glib_minor_version);
00413 exit (EXIT_FAILURE);
00414 }
00415
00416 xmms_signal_block ();
00417
00418 context = g_option_context_new ("- XMMS2 Daemon");
00419 g_option_context_add_main_entries (context, opts, NULL);
00420 if (!g_option_context_parse (context, &argc, &argv, &error) || error) {
00421 g_print ("Error parsing options: %s\n", error->message);
00422 g_clear_error (&error);
00423 exit (EXIT_FAILURE);
00424 }
00425 if (showhelp) {
00426 #if GLIB_CHECK_VERSION(2,14,0)
00427 g_print (g_option_context_get_help (context, TRUE, NULL));
00428 exit (EXIT_SUCCESS);
00429 #else
00430 g_print ("Please use --help or -? for help\n");
00431 exit (EXIT_FAILURE);
00432 #endif
00433 }
00434 g_option_context_free (context);
00435
00436 if (argc != 1) {
00437 g_print ("There were unknown options, aborting!\n");
00438 exit (EXIT_FAILURE);
00439 }
00440
00441 if (xmms_checkroot ()) {
00442 if (runasroot) {
00443 g_print ("***************************************\n");
00444 g_print ("Warning! You are running XMMS2D as root, this is a bad idea!\nBut I'll allow it since you asked nicely.\n");
00445 g_print ("***************************************\n\n");
00446 } else {
00447 g_print ("PLEASE DON'T RUN XMMS2D AS ROOT!\n\n(if you really must, read the help)\n");
00448 exit (EXIT_FAILURE);
00449 }
00450 }
00451
00452 if (verbose) {
00453 loglevel++;
00454 } else if (quiet) {
00455 loglevel--;
00456 }
00457
00458 if (version) {
00459 print_version ();
00460 }
00461
00462 g_thread_init (NULL);
00463
00464 g_random_set_seed (time (NULL));
00465
00466 xmms_log_init (loglevel);
00467 xmms_ipc_init ();
00468
00469 load_config ();
00470
00471 cv = xmms_config_property_register ("core.logtsfmt",
00472 "%H:%M:%S ",
00473 NULL, NULL);
00474
00475 xmms_log_set_format (xmms_config_property_get_string (cv));
00476
00477 xmms_fallback_ipcpath_get (default_path, sizeof (default_path));
00478
00479 cv = xmms_config_property_register ("core.ipcsocket",
00480 default_path,
00481 on_config_ipcsocket_change,
00482 NULL);
00483
00484 if (!ipcpath) {
00485
00486
00487
00488
00489 ipcpath = xmms_config_property_get_string (cv);
00490 }
00491
00492 if (!xmms_ipc_setup_server (ipcpath)) {
00493 xmms_ipc_shutdown ();
00494 xmms_log_fatal ("IPC failed to init!");
00495 }
00496
00497 if (!xmms_plugin_init (ppath)) {
00498 return 1;
00499 }
00500
00501 playlist = xmms_playlist_init ();
00502 xform_obj = xmms_xform_object_init ();
00503 bindata_obj = xmms_bindata_init ();
00504
00505 mainobj = xmms_object_new (xmms_main_t, xmms_main_destroy);
00506
00507
00508 cv = xmms_config_property_register ("output.plugin",
00509 XMMS_OUTPUT_DEFAULT,
00510 change_output, mainobj);
00511
00512 if (outname) {
00513 xmms_config_setvalue (NULL, "output.plugin", outname, NULL);
00514 }
00515
00516 outname = xmms_config_property_get_string (cv);
00517 xmms_log_info ("Using output plugin: %s", outname);
00518 o_plugin = (xmms_output_plugin_t *)xmms_plugin_find (XMMS_PLUGIN_TYPE_OUTPUT, outname);
00519 if (!o_plugin) {
00520 xmms_log_error ("Baaaaad output plugin, try to change the"
00521 "output.plugin config variable to something usefull");
00522 }
00523
00524 mainobj->output = xmms_output_new (o_plugin, playlist);
00525 if (!mainobj->output) {
00526 xmms_log_fatal ("Failed to create output object!");
00527 }
00528 xmms_visualization_init (mainobj->output);
00529
00530 if (status_fd != -1) {
00531 write (status_fd, "+", 1);
00532 }
00533
00534 xmms_signal_init (XMMS_OBJECT (mainobj));
00535
00536 xmms_ipc_object_register (XMMS_IPC_OBJECT_MAIN,
00537 XMMS_OBJECT (mainobj));
00538
00539 xmms_ipc_broadcast_register (XMMS_OBJECT (mainobj),
00540 XMMS_IPC_SIGNAL_QUIT);
00541
00542 xmms_object_cmd_add (XMMS_OBJECT (mainobj),
00543 XMMS_IPC_CMD_QUIT,
00544 XMMS_CMD_FUNC (quit));
00545 xmms_object_cmd_add (XMMS_OBJECT (mainobj),
00546 XMMS_IPC_CMD_HELLO,
00547 XMMS_CMD_FUNC (hello));
00548 xmms_object_cmd_add (XMMS_OBJECT (mainobj),
00549 XMMS_IPC_CMD_PLUGIN_LIST,
00550 XMMS_CMD_FUNC (plugin_list));
00551 xmms_object_cmd_add (XMMS_OBJECT (mainobj),
00552 XMMS_IPC_CMD_STATS,
00553 XMMS_CMD_FUNC (stats));
00554
00555
00556 mainobj->starttime = time (NULL);
00557
00558
00559 g_strlcpy (default_path, ipcpath, sizeof (default_path));
00560
00561 tmp = strchr (default_path, ';');
00562 if (tmp) {
00563 *tmp = '\0';
00564 }
00565
00566 putenv (g_strdup_printf ("XMMS_PATH=%s", default_path));
00567
00568
00569 putenv (g_strdup_printf ("XMMS_PATH_FULL=%s", ipcpath));
00570
00571 tmp = XMMS_BUILD_PATH ("shutdown.d");
00572 cv = xmms_config_property_register ("core.shutdownpath",
00573 tmp, NULL, NULL);
00574 g_free (tmp);
00575
00576 tmp = XMMS_BUILD_PATH ("startup.d");
00577 cv = xmms_config_property_register ("core.startuppath",
00578 tmp, NULL, NULL);
00579 g_free (tmp);
00580
00581
00582 do_scriptdir (xmms_config_property_get_string (cv));
00583
00584 mainloop = g_main_loop_new (NULL, FALSE);
00585
00586 g_main_loop_run (mainloop);
00587
00588 return 0;
00589 }
00590
00591