/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Gypsy * * A simple to use and understand GPSD replacement * that uses D-Bus, GLib and memory allocations * * Author: Iain Holmes <iain@gnome.org> * Copyright (C) 2007 * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include <stdio.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <glib.h> #include <dbus/dbus-protocol.h> #include <dbus/dbus-glib.h> #include <dbus/dbus-glib-bindings.h> #include "gypsy-debug.h" #include "gypsy-discovery.h" #include "gypsy-server.h" #define GYPSY_NAME "org.freedesktop.Gypsy" #define DEFAULT_PID_FILE LOCALSTATEDIR"/run/Gypsy.pid" static GMainLoop *mainloop; /* This is a bit ugly, but it works */ char* nmea_log = NULL; guint gypsy_debug_flags = 0; /* global gypsy debug flag */ static const GDebugKey gypsy_debug_keys[] = { { "nmea", GYPSY_DEBUG_NMEA }, { "server", GYPSY_DEBUG_SERVER }, { "client", GYPSY_DEBUG_CLIENT }, { "discovery", GYPSY_DEBUG_DISCOVERY }, }; static void gypsy_terminate (GObject *object, gpointer userdata) { g_main_loop_quit (mainloop); } static void write_pidfile (const char *pidfile) { FILE *f; if ((f = fopen (pidfile, "w")) == NULL) { g_printerr ("Opening %s failed: %s\n", pidfile, strerror (errno)); return; } if (fprintf (f, "%d", getpid ()) < 0) { g_printerr ("Writing to %s failed: %s\n", pidfile, strerror (errno)); } if (fclose (f)) { g_printerr ("Closing %s failed: %s\n", pidfile, strerror (errno)); } } static void name_owner_changed (DBusGProxy *proxy, const char *name, const char *prev_owner, const char *new_owner, GypsyServer *server) { if (strcmp (new_owner, "") == 0 && strcmp (name, prev_owner) == 0) { gypsy_server_remove_clients (server, prev_owner); } } static gboolean gypsy_arg_debug_cb (const char *key, const char *value, gpointer userdata) { gypsy_debug_flags |= g_parse_debug_string (value, gypsy_debug_keys, G_N_ELEMENTS (gypsy_debug_keys)); return TRUE; } void _gypsy_message (const char *format, ...) { va_list ap; va_start (ap, format); g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, format, ap); va_end (ap); } int main (int argc, char **argv) { GOptionContext *context; DBusGConnection *conn; DBusGProxy *proxy; GError *error = NULL; guint32 request_name_ret; GypsyServer *gypsy; GypsyDiscovery *discovery; gboolean become_daemon = FALSE; gboolean auto_terminate = TRUE; char *pidfile = NULL; char *user_pidfile = NULL; const char *env_string; GOptionEntry entries[] = { { "nmea-log", 0, 0, G_OPTION_ARG_FILENAME, &nmea_log, "Log NMEA data to FILE.[device]", "FILE" }, { "no-daemon", 0, 0, G_OPTION_ARG_NONE, &become_daemon, "Don't become a daemon", NULL }, { "pid-file", 0, 0, G_OPTION_ARG_FILENAME, &user_pidfile, "Specify the location of a PID file", "FILE" }, { "gypsy-debug", 0, 0, G_OPTION_ARG_CALLBACK, gypsy_arg_debug_cb, "Gypsy debugging flags to set", "FLAGS" }, { "no-auto-terminate", 0, 0, G_OPTION_ARG_NONE, &auto_terminate, "Don't terminate after last connection closes", NULL }, { NULL } }; env_string = g_getenv ("GYPSY_DEBUG"); if (env_string != NULL) { gypsy_debug_flags = g_parse_debug_string (env_string, gypsy_debug_keys, G_N_ELEMENTS (gypsy_debug_keys)); env_string = NULL; } context = g_option_context_new ("- GPS daemon"); g_option_context_add_main_entries (context, entries, NULL); if (!g_option_context_parse (context, &argc, &argv, &error)) { #if GLIB_CHECK_VERSION(2, 14, 0) char *help; help = g_option_context_get_help (context, TRUE, NULL); g_print (help); g_free (help); #else g_printerr ("Cannot parse arguments: %s\n", error->message); #endif g_error_free (error); return 1; } pidfile = g_strdup (user_pidfile ? user_pidfile : DEFAULT_PID_FILE); /* Tricky: become_daemon is FALSE by default, so unless it's TRUE because of a CLI option, it'll become TRUE after this */ become_daemon = !become_daemon; if (become_daemon) { if (daemon (0, 0) < 0) { int saved_errno; saved_errno = errno; g_printerr ("Could not daemonize: %s [error %u]\n", g_strerror (saved_errno), saved_errno); return 1; } write_pidfile (pidfile); } g_free (pidfile); g_option_context_free (context); umask (022); #if !GLIB_CHECK_VERSION(2,35,0) g_type_init (); #endif mainloop = g_main_loop_new (NULL, FALSE); conn = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); if (!conn) { g_error ("Error getting bus: %s", error->message); return 1; } proxy = dbus_g_proxy_new_for_name (conn, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS); if (!org_freedesktop_DBus_request_name (proxy, GYPSY_NAME, 0, &request_name_ret, &error)) { g_error ("Error registering D-Bus service %s: %s", GYPSY_NAME, error->message); return 1; } /* Just quit if GPS is already running */ if (request_name_ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { return 1; } gypsy = gypsy_server_new (auto_terminate); g_signal_connect (G_OBJECT (gypsy), "terminate", G_CALLBACK (gypsy_terminate), NULL); dbus_g_proxy_add_signal (proxy, "NameOwnerChanged", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID); dbus_g_proxy_connect_signal (proxy, "NameOwnerChanged", G_CALLBACK (name_owner_changed), gypsy, NULL); dbus_g_connection_register_g_object (conn, "/org/freedesktop/Gypsy", G_OBJECT (gypsy)); discovery = g_object_new (GYPSY_TYPE_DISCOVERY, NULL); dbus_g_connection_register_g_object (conn, "/org/freedesktop/Gypsy/Discovery", G_OBJECT (discovery)); g_main_loop_run (mainloop); return 0; }