XMMS2

src/xmms/main.c

Go to the documentation of this file.
00001 /*  XMMS2 - X Music Multiplexer System
00002  *  Copyright (C) 2003-2009 XMMS2 Team
00003  *
00004  *  PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!!
00005  *
00006  *  This library is free software; you can redistribute it and/or
00007  *  modify it under the terms of the GNU Lesser General Public
00008  *  License as published by the Free Software Foundation; either
00009  *  version 2.1 of the License, or (at your option) any later version.
00010  *
00011  *  This library is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  *  Lesser General Public License for more details.
00015  */
00016 
00017 /**
00018  * @mainpage
00019  * @image html pixmaps/xmms2-128.png
00020  */
00021 
00022 /** @file
00023  * This file controls the XMMS2 main loop.
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  * Forward declarations of the methods in the main object
00058  */
00059 static void xmms_main_client_quit (xmms_object_t *object, xmms_error_t *error);
00060 static GTree *xmms_main_client_stats (xmms_object_t *object, xmms_error_t *error);
00061 static GList *xmms_main_client_plugin_list (xmms_object_t *main, gint32 type, xmms_error_t *err);
00062 static void xmms_main_client_hello (xmms_object_t *object, gint protocolver, const gchar *client, xmms_error_t *error);
00063 static void install_scripts (const gchar *into_dir);
00064 static void spawn_script_setup (gpointer data);
00065 static xmms_xform_object_t *xform_obj;
00066 static xmms_bindata_t *bindata_obj;
00067 
00068 XMMS_CMD_DEFINE (quit, xmms_main_client_quit, xmms_object_t*, NONE, NONE, NONE);
00069 XMMS_CMD_DEFINE (hello, xmms_main_client_hello, xmms_object_t *, NONE, INT32, STRING);
00070 XMMS_CMD_DEFINE (stats, xmms_main_client_stats, xmms_object_t *, DICT, NONE, NONE);
00071 XMMS_CMD_DEFINE (plugin_list, xmms_main_client_plugin_list, xmms_object_t *, LIST, INT32, NONE);
00072 
00073 /** @defgroup XMMSServer XMMSServer
00074   * @brief look at this if you want to code inside the server.
00075   * The XMMS2 project is split into a server and a multiple clients.
00076   * This documents the server part.
00077   */
00078 
00079 /**
00080   * @defgroup Main Main
00081   * @ingroup XMMSServer
00082   * @brief main object
00083   * @{
00084   */
00085 
00086 
00087 /**
00088  * Main object, when this is unreffed, XMMS2 is quiting.
00089  */
00090 struct xmms_main_St {
00091     xmms_object_t object;
00092     xmms_output_t *output;
00093     xmms_visualization_t *vis;
00094     time_t starttime;
00095 };
00096 
00097 typedef struct xmms_main_St xmms_main_t;
00098 
00099 /** This is the mainloop of the xmms2 server */
00100 static GMainLoop *mainloop;
00101 
00102 /** The path of the configfile */
00103 static gchar *conffile = NULL;
00104 
00105 /**
00106  * This returns the main stats for the server
00107  */
00108 static GTree *
00109 xmms_main_client_stats (xmms_object_t *object, xmms_error_t *error)
00110 {
00111     GTree *ret;
00112     gint starttime;
00113 
00114     ret = g_tree_new_full ((GCompareDataFunc) strcmp, NULL,
00115                            NULL, (GDestroyNotify) xmmsv_unref);
00116 
00117     starttime = ((xmms_main_t*)object)->starttime;
00118 
00119     g_tree_insert (ret, (gpointer) "version",
00120                    xmmsv_new_string (XMMS_VERSION));
00121     g_tree_insert (ret, (gpointer) "uptime",
00122                    xmmsv_new_int (time (NULL) - starttime));
00123 
00124     return ret;
00125 }
00126 
00127 static gboolean
00128 xmms_main_client_list_foreach (xmms_plugin_t *plugin, gpointer data)
00129 {
00130     xmmsv_t *dict;
00131     GList **list = data;
00132 
00133     dict = xmmsv_build_dict (
00134             XMMSV_DICT_ENTRY_STR ("name", xmms_plugin_name_get (plugin)),
00135             XMMSV_DICT_ENTRY_STR ("shortname", xmms_plugin_shortname_get (plugin)),
00136             XMMSV_DICT_ENTRY_STR ("version", xmms_plugin_version_get (plugin)),
00137             XMMSV_DICT_ENTRY_STR ("description", xmms_plugin_description_get (plugin)),
00138             XMMSV_DICT_ENTRY_INT ("type", xmms_plugin_type_get (plugin)),
00139             XMMSV_DICT_END);
00140 
00141     *list = g_list_prepend (*list, dict);
00142 
00143     return TRUE;
00144 }
00145 
00146 static GList *
00147 xmms_main_client_plugin_list (xmms_object_t *main, gint32 type, xmms_error_t *err)
00148 {
00149     GList *list = NULL;
00150     xmms_plugin_foreach (type, xmms_main_client_list_foreach, &list);
00151     return list;
00152 }
00153 
00154 
00155 /**
00156  * @internal Execute all programs or scripts in a directory. Used when starting
00157  * up and shutting down the daemon.
00158  *
00159  * @param[in] scriptdir Directory to search for executable programs/scripts.
00160  * started.
00161  * @param     arg1 value passed to executed scripts as argument 1. This makes
00162  * it possible to handle start and stop in one script
00163  */
00164 static void
00165 do_scriptdir (const gchar *scriptdir, const gchar *arg1)
00166 {
00167     GError *err = NULL;
00168     GDir *dir;
00169     const gchar *f;
00170     gchar *argv[3] = {NULL, NULL, NULL};
00171 
00172     XMMS_DBG ("Running scripts in %s", scriptdir);
00173     if (!g_file_test (scriptdir, G_FILE_TEST_IS_DIR)) {
00174         g_mkdir_with_parents (scriptdir, 0755);
00175         install_scripts (scriptdir);
00176     }
00177 
00178     dir = g_dir_open (scriptdir, 0, &err);
00179     if (!dir) {
00180         xmms_log_error ("Could not open script dir '%s' error: %s", scriptdir, err->message);
00181         return;
00182     }
00183 
00184     argv[1] = g_strdup (arg1);
00185     while ((f = g_dir_read_name (dir))) {
00186         argv[0] = g_strdup_printf ("%s/%s", scriptdir, f);
00187         if (g_file_test (argv[0], G_FILE_TEST_IS_EXECUTABLE)) {
00188             if (!g_spawn_async (g_get_home_dir (), argv, NULL, 0,
00189                                 spawn_script_setup, NULL, NULL, &err)) {
00190                 xmms_log_error ("Could not run script '%s', error: %s",
00191                                 argv[0], err->message);
00192             }
00193         }
00194         g_free (argv[0]);
00195     }
00196     g_free (argv[1]);
00197 
00198     g_dir_close (dir);
00199 
00200 }
00201 
00202 /**
00203  * @internal Setup function for processes spawned by do_scriptdir
00204  */
00205 static void
00206 spawn_script_setup (gpointer data)
00207 {
00208     xmms_signal_restore ();
00209 }
00210 
00211 /**
00212  * @internal Load the xmms2d configuration file. Creates the config directory
00213  * if needed.
00214  */
00215 static void
00216 load_config (void)
00217 {
00218     gchar configdir[PATH_MAX];
00219 
00220     if (!conffile) {
00221         conffile = XMMS_BUILD_PATH ("xmms2.conf");
00222     }
00223 
00224     g_assert (strlen (conffile) <= XMMS_MAX_CONFIGFILE_LEN);
00225 
00226     if (!xmms_userconfdir_get (configdir, sizeof (configdir))) {
00227         xmms_log_error ("Could not get path to config dir");
00228     } else if (!g_file_test (configdir, G_FILE_TEST_IS_DIR)) {
00229         g_mkdir_with_parents (configdir, 0755);
00230     }
00231 
00232     xmms_config_init (conffile);
00233 }
00234 
00235 /**
00236  * @internal Switch to using another output plugin
00237  * @param object An object
00238  * @param data The name of the output plugin to switch to
00239  * @param userdata The #xmms_main_t object
00240  */
00241 static void
00242 change_output (xmms_object_t *object, xmmsv_t *_data, gpointer userdata)
00243 {
00244     xmms_output_plugin_t *plugin;
00245     xmms_main_t *mainobj = (xmms_main_t*)userdata;
00246     const gchar *outname;
00247 
00248     if (!mainobj->output)
00249         return;
00250 
00251     outname = xmms_config_property_get_string ((xmms_config_property_t *) object);
00252 
00253     xmms_log_info ("Switching to output %s", outname);
00254 
00255     plugin = (xmms_output_plugin_t *)xmms_plugin_find (XMMS_PLUGIN_TYPE_OUTPUT, outname);
00256     if (!plugin) {
00257         xmms_log_error ("Baaaaad output plugin, try to change the output.plugin config variable to something usefull");
00258     } else {
00259         if (!xmms_output_plugin_switch (mainobj->output, plugin)) {
00260             xmms_log_error ("Baaaaad output plugin, try to change the output.plugin config variable to something usefull");
00261         }
00262     }
00263 }
00264 
00265 /**
00266  * @internal Destroy the main object
00267  * @param[in] object The object to destroy
00268  */
00269 static void
00270 xmms_main_destroy (xmms_object_t *object)
00271 {
00272     xmms_main_t *mainobj = (xmms_main_t *) object;
00273     xmms_object_cmd_arg_t arg;
00274     xmms_config_property_t *cv;
00275 
00276     cv = xmms_config_lookup ("core.shutdownpath");
00277     do_scriptdir (xmms_config_property_get_string (cv), "stop");
00278 
00279     /* stop output */
00280     xmms_object_cmd_arg_init (&arg);
00281 
00282     xmms_object_cmd_call (XMMS_OBJECT (mainobj->output),
00283                           XMMS_IPC_CMD_STOP, &arg);
00284 
00285     g_usleep (G_USEC_PER_SEC); /* wait for the output thread to end */
00286 
00287     xmms_object_unref (mainobj->vis);
00288     xmms_object_unref (mainobj->output);
00289 
00290     xmms_object_unref (xform_obj);
00291 
00292     xmms_config_save ();
00293 
00294     xmms_config_shutdown ();
00295 
00296     xmms_plugin_shutdown ();
00297 
00298     xmms_ipc_object_unregister (XMMS_IPC_OBJECT_MAIN);
00299     xmms_ipc_shutdown ();
00300 
00301     xmms_log_shutdown ();
00302 }
00303 
00304 /**
00305  * @internal Function to respond to the 'hello' sent from clients on connect
00306  */
00307 static void
00308 xmms_main_client_hello (xmms_object_t *object, gint protocolver, const gchar *client, xmms_error_t *error)
00309 {
00310     if (protocolver != XMMS_IPC_PROTOCOL_VERSION) {
00311         xmms_log_info ("Client '%s' with bad protocol version (%d, not %d) connected", client, protocolver, XMMS_IPC_PROTOCOL_VERSION);
00312         xmms_error_set (error, XMMS_ERROR_INVAL, "Bad protocol version");
00313         return;
00314     }
00315     XMMS_DBG ("Client '%s' connected", client);
00316 }
00317 
00318 static gboolean
00319 kill_server (gpointer object) {
00320     xmms_object_emit_f (XMMS_OBJECT (object),
00321                         XMMS_IPC_SIGNAL_QUIT,
00322                         XMMSV_TYPE_INT32,
00323                         time (NULL)-((xmms_main_t*)object)->starttime);
00324 
00325     xmms_object_unref (object);
00326 
00327     exit (EXIT_SUCCESS);
00328 }
00329 
00330 
00331 /**
00332  * @internal Function to respond to the 'quit' command sent from a client
00333  */
00334 static void
00335 xmms_main_client_quit (xmms_object_t *object, xmms_error_t *error)
00336 {
00337     /*
00338      * to be able to return from this method
00339      * we add a timeout that will kill the server
00340      * very "ugly"
00341      */
00342     g_timeout_add (1, kill_server, object);
00343 }
00344 
00345 static void
00346 install_scripts (const gchar *into_dir)
00347 {
00348     GDir *dir;
00349     GError *err = NULL;
00350     gchar path[PATH_MAX];
00351     const gchar *f;
00352     gchar *s;
00353 
00354     s = strrchr (into_dir, G_DIR_SEPARATOR);
00355     if (!s)
00356         return;
00357 
00358     s++;
00359 
00360     g_snprintf (path, PATH_MAX, "%s/scripts/%s", SHAREDDIR, s);
00361     xmms_log_info ("Installing scripts from %s", path);
00362     dir = g_dir_open (path, 0, &err);
00363     if (!dir) {
00364         xmms_log_error ("Global script directory not found");
00365         return;
00366     }
00367 
00368     while ((f = g_dir_read_name (dir))) {
00369         gchar *source = g_strdup_printf ("%s/%s", path, f);
00370         gchar *dest = g_strdup_printf ("%s/%s", into_dir, f);
00371         if (!xmms_symlink_file (source, dest)) {
00372             g_free (source);
00373             g_free (dest);
00374             break;
00375         }
00376         g_free (source);
00377         g_free (dest);
00378     }
00379 
00380     g_dir_close (dir);
00381 }
00382 
00383 /**
00384  * Just print version and quit
00385  */
00386 static void
00387 print_version (void)
00388 {
00389     printf ("XMMS2 version " XMMS_VERSION "\n");
00390     printf ("Copyright (C) 2003-2009 XMMS2 Team\n");
00391     printf ("This is free software; see the source for copying conditions.\n");
00392     printf ("There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n");
00393     printf ("PARTICULAR PURPOSE.\n");
00394     printf (" Using glib version %d.%d.%d (compiled against "
00395             G_STRINGIFY (GLIB_MAJOR_VERSION) "."
00396             G_STRINGIFY (GLIB_MINOR_VERSION) "."
00397             G_STRINGIFY (GLIB_MICRO_VERSION) ")\n",
00398             glib_major_version,
00399             glib_minor_version,
00400             glib_micro_version);
00401     xmms_sqlite_print_version ();
00402 
00403     exit (EXIT_SUCCESS);
00404 }
00405 
00406 /**
00407  * The xmms2 daemon main initialisation function
00408  */
00409 int
00410 main (int argc, char **argv)
00411 {
00412     xmms_output_plugin_t *o_plugin;
00413     xmms_config_property_t *cv;
00414     xmms_main_t *mainobj;
00415     int loglevel = 1;
00416     xmms_playlist_t *playlist;
00417     gchar default_path[XMMS_PATH_MAX + 16], *tmp;
00418     gboolean verbose = FALSE;
00419     gboolean quiet = FALSE;
00420     gboolean version = FALSE;
00421     gboolean nologging = FALSE;
00422     gboolean runasroot = FALSE;
00423     gboolean showhelp = FALSE;
00424     const gchar *outname = NULL;
00425     const gchar *ipcpath = NULL;
00426     gchar *ppath = NULL;
00427     int status_fd = -1;
00428     GOptionContext *context = NULL;
00429     GError *error = NULL;
00430 
00431     setlocale (LC_ALL, "");
00432 
00433     /**
00434      * The options that the server accepts.
00435      */
00436     GOptionEntry opts[] = {
00437         {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Increase verbosity", NULL},
00438         {"quiet", 'q', 0, G_OPTION_ARG_NONE, &quiet, "Decrease verbosity", NULL},
00439         {"version", 'V', 0, G_OPTION_ARG_NONE, &version, "Print version", NULL},
00440         {"no-logging", 'n', 0, G_OPTION_ARG_NONE, &nologging, "Disable logging", NULL},
00441         {"output", 'o', 0, G_OPTION_ARG_STRING, &outname, "Use 'x' as output plugin", "<x>"},
00442         {"ipc-socket", 'i', 0, G_OPTION_ARG_FILENAME, &ipcpath, "Listen to socket 'url'", "<url>"},
00443         {"plugindir", 'p', 0, G_OPTION_ARG_FILENAME, &ppath, "Search for plugins in directory 'foo'", "<foo>"},
00444         {"conf", 'c', 0, G_OPTION_ARG_FILENAME, &conffile, "Specify alternate configuration file", "<file>"},
00445         {"status-fd", 's', 0, G_OPTION_ARG_INT, &status_fd, "Specify a filedescriptor to write to when started", "fd"},
00446         {"yes-run-as-root", 0, 0, G_OPTION_ARG_NONE, &runasroot, "Give me enough rope to shoot myself in the foot", NULL},
00447         {"show-help", 'h', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &showhelp, "Use --help or -? instead", NULL},
00448         {NULL}
00449     };
00450 
00451     /** Check that we are running against the correct glib version */
00452     if (glib_major_version != GLIB_MAJOR_VERSION ||
00453         glib_minor_version < GLIB_MINOR_VERSION) {
00454         g_print ("xmms2d is build against version %d.%d,\n"
00455                  "but is (runtime) linked against %d.%d.\n"
00456                  "Refusing to start.\n",
00457                  GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION,
00458                  glib_major_version, glib_minor_version);
00459         exit (EXIT_FAILURE);
00460     }
00461 
00462     xmms_signal_block ();
00463 
00464     context = g_option_context_new ("- XMMS2 Daemon");
00465     g_option_context_add_main_entries (context, opts, NULL);
00466     if (!g_option_context_parse (context, &argc, &argv, &error) || error) {
00467         g_print ("Error parsing options: %s\n", error->message);
00468         g_clear_error (&error);
00469         exit (EXIT_FAILURE);
00470     }
00471     if (showhelp) {
00472 #if GLIB_CHECK_VERSION(2,14,0)
00473         g_print ("%s", g_option_context_get_help (context, TRUE, NULL));
00474         exit (EXIT_SUCCESS);
00475 #else
00476         g_print ("Please use --help or -? for help\n");
00477         exit (EXIT_FAILURE);
00478 #endif
00479     }
00480     g_option_context_free (context);
00481 
00482     if (argc != 1) {
00483         g_print ("There were unknown options, aborting!\n");
00484         exit (EXIT_FAILURE);
00485     }
00486 
00487     if (xmms_checkroot ()) {
00488         if (runasroot) {
00489             g_print ("***************************************\n");
00490             g_print ("Warning! You are running XMMS2D as root, this is a bad idea!\nBut I'll allow it since you asked nicely.\n");
00491             g_print ("***************************************\n\n");
00492         } else {
00493             g_print ("PLEASE DON'T RUN XMMS2D AS ROOT!\n\n(if you really must, read the help)\n");
00494             exit (EXIT_FAILURE);
00495         }
00496     }
00497 
00498     if (verbose) {
00499         loglevel++;
00500     } else if (quiet) {
00501         loglevel--;
00502     }
00503 
00504     if (version) {
00505         print_version ();
00506     }
00507 
00508     g_thread_init (NULL);
00509 
00510     g_random_set_seed (time (NULL));
00511 
00512     xmms_log_init (loglevel);
00513     xmms_ipc_init ();
00514 
00515     load_config ();
00516 
00517     cv = xmms_config_property_register ("core.logtsfmt",
00518                                         "%H:%M:%S ",
00519                                         NULL, NULL);
00520 
00521     xmms_log_set_format (xmms_config_property_get_string (cv));
00522 
00523     xmms_fallback_ipcpath_get (default_path, sizeof (default_path));
00524 
00525     cv = xmms_config_property_register ("core.ipcsocket",
00526                                         default_path,
00527                                         on_config_ipcsocket_change,
00528                                         NULL);
00529 
00530     if (!ipcpath) {
00531         /*
00532          * if not ipcpath is specifed on the cmd line we
00533          * grab it from the config
00534          */
00535         ipcpath = xmms_config_property_get_string (cv);
00536     }
00537 
00538     if (!xmms_ipc_setup_server (ipcpath)) {
00539         xmms_ipc_shutdown ();
00540         xmms_log_fatal ("IPC failed to init!");
00541     }
00542 
00543     if (!xmms_plugin_init (ppath)) {
00544         return 1;
00545     }
00546 
00547     playlist = xmms_playlist_init ();
00548     xform_obj = xmms_xform_object_init ();
00549     bindata_obj = xmms_bindata_init ();
00550 
00551     mainobj = xmms_object_new (xmms_main_t, xmms_main_destroy);
00552 
00553     /* find output plugin. */
00554     cv = xmms_config_property_register ("output.plugin",
00555                                         XMMS_OUTPUT_DEFAULT,
00556                                         change_output, mainobj);
00557 
00558     if (outname) {
00559         xmms_config_property_set_data (cv, outname);
00560     }
00561 
00562     outname = xmms_config_property_get_string (cv);
00563     xmms_log_info ("Using output plugin: %s", outname);
00564     o_plugin = (xmms_output_plugin_t *)xmms_plugin_find (XMMS_PLUGIN_TYPE_OUTPUT, outname);
00565     if (!o_plugin) {
00566         xmms_log_error ("Baaaaad output plugin, try to change the"
00567                         "output.plugin config variable to something usefull");
00568     }
00569 
00570     mainobj->output = xmms_output_new (o_plugin, playlist);
00571     if (!mainobj->output) {
00572         xmms_log_fatal ("Failed to create output object!");
00573     }
00574 
00575     mainobj->vis = xmms_visualization_new (mainobj->output);
00576 
00577     if (status_fd != -1) {
00578         write (status_fd, "+", 1);
00579     }
00580 
00581     xmms_signal_init (XMMS_OBJECT (mainobj));
00582 
00583     xmms_ipc_object_register (XMMS_IPC_OBJECT_MAIN,
00584                               XMMS_OBJECT (mainobj));
00585 
00586     xmms_ipc_broadcast_register (XMMS_OBJECT (mainobj),
00587                                  XMMS_IPC_SIGNAL_QUIT);
00588 
00589     xmms_object_cmd_add (XMMS_OBJECT (mainobj),
00590                          XMMS_IPC_CMD_QUIT,
00591                          XMMS_CMD_FUNC (quit));
00592     xmms_object_cmd_add (XMMS_OBJECT (mainobj),
00593                          XMMS_IPC_CMD_HELLO,
00594                          XMMS_CMD_FUNC (hello));
00595     xmms_object_cmd_add (XMMS_OBJECT (mainobj),
00596                          XMMS_IPC_CMD_PLUGIN_LIST,
00597                          XMMS_CMD_FUNC (plugin_list));
00598     xmms_object_cmd_add (XMMS_OBJECT (mainobj),
00599                          XMMS_IPC_CMD_STATS,
00600                          XMMS_CMD_FUNC (stats));
00601 
00602     /* Save the time we started in order to count uptime */
00603     mainobj->starttime = time (NULL);
00604 
00605     /* Dirty hack to tell XMMS_PATH a valid path */
00606     g_strlcpy (default_path, ipcpath, sizeof (default_path));
00607 
00608     tmp = strchr (default_path, ';');
00609     if (tmp) {
00610         *tmp = '\0';
00611     }
00612 
00613     g_setenv ("XMMS_PATH", default_path, TRUE);
00614 
00615     /* Also put the full path for clients that understands */
00616     g_setenv("XMMS_PATH_FULL", ipcpath, TRUE);
00617 
00618     tmp = XMMS_BUILD_PATH ("shutdown.d");
00619     cv = xmms_config_property_register ("core.shutdownpath",
00620                                         tmp, NULL, NULL);
00621     g_free (tmp);
00622 
00623     tmp = XMMS_BUILD_PATH ("startup.d");
00624     cv = xmms_config_property_register ("core.startuppath",
00625                                         tmp, NULL, NULL);
00626     g_free (tmp);
00627 
00628     /* Startup dir */
00629     do_scriptdir (xmms_config_property_get_string (cv), "start");
00630 
00631     mainloop = g_main_loop_new (NULL, FALSE);
00632 
00633     g_main_loop_run (mainloop);
00634 
00635     return 0;
00636 }
00637 
00638 /** @} */