/***************************************************************************
 * CVSID: $Id: main.c,v 1.2 2006-03-16 23:28:47 david Exp $
 *
 * main.c : Main for polkitd
 *
 * Copyright (C) 2006 David Zeuthen, <david@fubar.dk>
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 **************************************************************************/

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <dbus/dbus-glib.h>

#include "polkit-session.h"
#include "polkit-manager.h"

#include "polkit-interface-session-glue.h"
#include "polkit-interface-manager-glue.h"

/** Print out program usage.
 *
 */
static void
usage (int argc, char *argv[])
{
	fprintf (stderr, "\n" "usage : polkitd [--no-daemon] [--verbose]\n");
	fprintf (stderr,
		 "\n"
		 "        -n, --no-daemon      Do not daemonize\n"
		 "        -v, --verbose        Print out debug\n"
		 "        -h, --help           Show this information and exit\n"
		 "        -V, --version        Output version information and exit"
		 "\n"
		 "The PolicyKit daemon maintains a list of privileges and\n"
		 "provides interfaces for changing it.\n"
		 "\n"
		 "For more information visit http://freedesktop.org/Software/hal\n"
		 "\n");
}

static void 
delete_pid (void)
{
	unlink (POLKITD_PID_FILE);
}

int
main (int argc, char *argv[])
{
	DBusGConnection *bus;
	DBusGProxy *bus_proxy;
	GError *error = NULL;
	PolicyKitManager *manager;
	GMainLoop *mainloop;
	guint request_name_result;
	int ret;
	gboolean no_daemon = FALSE;
	gboolean is_verbose = FALSE;
	static const struct option long_options[] = {
		{"help", no_argument, NULL, 'h'},
		{"no-daemon", no_argument, NULL, 'n'},
		{"verbose", no_argument, NULL, 'v'},
		{"version", no_argument, NULL, 'V'},
		{NULL, 0, NULL, 0}
	};


	ret = 1;

	g_type_init ();

	while (TRUE) {
		int c;
		
		c = getopt_long (argc, argv, "nhVv", long_options, NULL);

		if (c == -1)
			break;
		
		switch (c) {
		case 'n':
			no_daemon = TRUE;
			break;

		case 'v':
			is_verbose = TRUE;
			break;

		case 'h':
			usage (argc, argv);
			ret = 0;
			goto out;

		case 'V':
			printf (PACKAGE_NAME " version " PACKAGE_VERSION "\n");
			ret = 0;
			goto out;
			
		default:
			usage (argc, argv);
			goto out;
		}
	}


	if (!no_daemon) {
		int child_pid;
		int dev_null_fd;
		int pf;
		ssize_t written;
		char pid[9];
		

		if (chdir ("/") < 0) {
			g_warning ("Could not chdir to /: %s", strerror (errno));
			goto out;
		}

		child_pid = fork ();
		switch (child_pid) {
		case -1:
			g_warning ("Cannot fork(): %s", strerror (errno));
			goto out;

		case 0:
			/* child */
			dev_null_fd = open ("/dev/null", O_RDWR);
			/* ignore if we can't open /dev/null */
			if (dev_null_fd >= 0) {
				/* attach /dev/null to stdout, stdin, stderr */
				dup2 (dev_null_fd, 0);
				dup2 (dev_null_fd, 1);
				dup2 (dev_null_fd, 2);
				close (dev_null_fd);
			}

			umask (022);
			break;

		default:
			/* parent exits */
			exit (0);
			break;
		}

		/* create session */
		setsid ();

		/* remove old pid file */
		unlink (POLKITD_PID_FILE);

		/* make a new pid file */
		if ((pf = open (POLKITD_PID_FILE, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644)) > 0) {
			snprintf (pid, sizeof(pid), "%lu\n", (long unsigned) getpid ());
			written = write (pf, pid, strlen(pid));
			close (pf);
			g_atexit (delete_pid);
		}
	} else {
		g_debug (("not becoming a daemon"));
	}

	g_type_init ();

	dbus_g_object_type_install_info (POLKIT_TYPE_MANAGER, &dbus_glib_polkit_manager_object_info);
	dbus_g_object_type_install_info (POLKIT_TYPE_SESSION, &dbus_glib_polkit_session_object_info);
	dbus_g_error_domain_register (POLKIT_MANAGER_ERROR, NULL, POLKIT_MANAGER_TYPE_ERROR);
	dbus_g_error_domain_register (POLKIT_SESSION_ERROR, NULL, POLKIT_SESSION_TYPE_ERROR);

	mainloop = g_main_loop_new (NULL, FALSE);

	bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
	if (bus == NULL) {
		g_warning ("Couldn't connect to system bus: %s", error->message);
		g_error_free (error);
		goto out;
	}

	bus_proxy = dbus_g_proxy_new_for_name (bus, "org.freedesktop.DBus",
					       "/org/freedesktop/DBus",
					       "org.freedesktop.DBus");
	if (!dbus_g_proxy_call (bus_proxy, "RequestName", &error,
				G_TYPE_STRING, "org.freedesktop.PolicyKit",
				G_TYPE_UINT, 0,
				G_TYPE_INVALID,
				G_TYPE_UINT, &request_name_result,
				G_TYPE_INVALID)) {
		g_warning ("Failed to acquire org.freedesktop.PolicyKit: %s", error->message);
		g_error_free (error);
		goto out;
	}

	if (request_name_result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
		g_warning ("There is already a primary owner of the name org.freedesktop.PolicyKit");
		goto out;
	}
	

	manager = polkit_manager_new (bus, bus_proxy);

	g_debug ("service running");

	g_main_loop_run (mainloop);

	ret = 0;
out:
	return ret;
}


syntax highlighted by Code2HTML, v. 0.9.1