Main Page | Data Structures | File List | Data Fields | Globals

alarmd.c

Go to the documentation of this file.
00001 /**
00002  * This file is part of alarmd
00003  *
00004  * Contact Person: David Weinehall <david.weinehall@nokia.com>
00005  *
00006  * Copyright (C) 2006 Nokia Corporation
00007  * alarmd and libalarm are free software; you can redistribute them
00008  * and/or modify them under the terms of the GNU Lesser General Public
00009  * License version 2.1 as published by the Free Software Foundation.
00010  *
00011  * alarmd and libalarm are distributed in the hope that they 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  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this software; if not, write to the Free
00018  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
00019  * 02110-1301 USA
00020  */
00021 
00022 #include <glib.h>
00023 #include <glib-object.h>
00024 #include <errno.h>
00025 #include <fcntl.h>              /* open */
00026 #include <stdio.h>
00027 #include <getopt.h>
00028 #include <signal.h>             /* signal */
00029 #include <stdlib.h>             /* exit */
00030 #include <string.h>             /* strerror */
00031 #include <unistd.h>             /* close */
00032 #include <sys/stat.h>           /* open */
00033 #include <sys/types.h>          /* open */
00034 #include <osso-log.h>
00035 
00036 #include "alarmd.h"
00037 #include "initialize.h"
00038 #include "queue.h"
00039 #include "rpc-osso.h"
00040 #include "rpc-dbus.h"
00041 #include "osso-log.h"
00042 
00043 #define ALARMD_LOCKFILE         "/var/run/alarmd.pid"
00044 #define PRG_NAME                "alarmd"
00045 
00046 extern int optind;
00047 extern char *optarg;
00048 
00049 static const gchar *progname;
00050 
00051 /*
00052  * Display usage information
00053  */
00054 static void usage(void)
00055 {
00056         fprintf(stdout,
00057                 _("Usage: %s [OPTION]...\n"
00058                   "Alarm daemon\n"
00059                   "\n"
00060                   "  -d, --daemonflag    run alarmd as a daemon\n"
00061                   "      --help          display this help and exit\n"
00062                   "      --version       output version information and exit\n"
00063                   "\n"
00064                   "Report bugs to <david.weinehall@nokia.com>\n"),
00065                 progname);
00066 }
00067 
00068 /*
00069  * Display version information
00070  */
00071 static void version(void)
00072 {
00073         fprintf(stdout, _("%s v%s\n%s"),
00074                 progname,
00075                 VERSION,
00076                 _("Written by Santtu Lakkala.\n"
00077                   "Contact person: David Weinehall "
00078                   "<david.weinehall@nokia.com>\n"
00079                   "\n"
00080                   "Copyright (C) 2006 Nokia Corporation.\n"
00081                   "This is free software; see the source for copying "
00082                   "conditions. There is NO\n"
00083                   "warranty; not even for MERCHANTABILITY or FITNESS FOR A "
00084                   "PARTICULAR PURPOSE.\n"));
00085 }
00086 
00087 /*
00088  * Initialise locale support
00089  *
00090  * @param name The program name to output in usage/version information
00091  * @return 0 on success, non-zero on failure
00092  */
00093 static gint init_locales(const gchar *const name)
00094 {
00095         gint status = 0;
00096 
00097 #ifdef ENABLE_NLS
00098         setlocale(LC_ALL, "");
00099 
00100         if ((bindtextdomain(name, LOCALEDIR) == 0) && (errno == ENOMEM)) {
00101                 status = errno;
00102                 goto EXIT;
00103         }
00104 
00105         if ((textdomain(name) == 0) && (errno == ENOMEM)) {
00106                 status = errno;
00107                 return 0;
00108         }
00109 
00110 EXIT:
00111         /* In this error-message we don't use _(), since we don't
00112          * know where the locales failed, and we probably won't
00113          * get a reasonable result if we try to use them.
00114          */
00115         if (status != 0) {
00116                 fprintf(stderr,
00117                         "%s: `%s' failed; %s. Aborting.\n",
00118                         name, "init_locales", strerror(errno));
00119         } else {
00120                 progname = _(name);
00121                 errno = 0;
00122         }
00123 #else
00124         progname = name;
00125 #endif /* ENABLE_NLS */
00126 
00127         return status;
00128 }
00129 
00130 /*
00131  * Signal handler
00132  *
00133  * @param signr Signal type
00134  */
00135 static void signal_handler(const gint signr)
00136 {
00137         switch (signr) {
00138         case SIGUSR1:
00139                 /* we'll probably want some way to communicate with alarmd */
00140                 break;
00141 
00142         case SIGHUP:
00143                 /* possibly for re-reading configuration? */
00144                 break;
00145 
00146         case SIGTERM:
00147                 DLOG_DEBUG("Stopping alarmd...");
00148                 g_main_loop_quit(mainloop);
00149                 break;
00150 
00151         default:
00152                 /* should never happen */
00153                 break;
00154         }
00155 }
00156 
00157 /*
00158  * Daemonize the program
00159  */
00160 static void daemonize(void)
00161 {
00162         gint i = 0;
00163         gchar str[10];
00164 
00165         if (getppid() == 1)
00166                 return;         /* Already daemonized */
00167 
00168         /* detach from process group */
00169         switch (fork()) {
00170         case -1:
00171                 /* Failure */
00172                 DLOG_CRIT("daemonize: fork failed: %s", strerror(errno));
00173                 LOG_CLOSE();
00174                 exit(EXIT_FAILURE);
00175 
00176         case 0:
00177                 /* Child */
00178                 break;
00179 
00180         default:
00181                 /* Parent -- exit */
00182                 exit(EXIT_SUCCESS);
00183         }
00184 
00185         /* Detach TTY */
00186         setsid();
00187 
00188         /* Close all file descriptors and redirect stdio to /dev/null */
00189         if ((i = getdtablesize()) == -1)
00190                 i = 256;
00191 
00192         while (--i >= 0)
00193                 close(i);
00194 
00195         i = open("/dev/null", O_RDWR);
00196         dup(i);
00197         dup(i);
00198 
00199         /* Set umask */
00200         umask(022);
00201 
00202         /* Set working directory */
00203         chdir("/tmp");
00204 
00205         /* If the file exists, we have crashed / restarted */
00206         if (access(ALARMD_LOCKFILE, F_OK) == 0) {
00207                 /* OK */
00208         } else if (errno != ENOENT) {
00209                 DLOG_CRIT("access() failed: %s. Exiting.", g_strerror(errno));
00210                 LOG_CLOSE();
00211                 exit(EXIT_FAILURE);
00212         }
00213 
00214         /* Single instance */
00215         if ((i = open(ALARMD_LOCKFILE, O_RDWR | O_CREAT, 0640)) < 0) {
00216                 DLOG_CRIT("Cannot open lockfile. Exiting.");
00217                 LOG_CLOSE();
00218                 exit(EXIT_FAILURE);
00219         }
00220 
00221         if (lockf(i, F_TLOCK, 0) < 0) {
00222                 DLOG_CRIT("Already running. Exiting.");
00223                 LOG_CLOSE();
00224                 exit(EXIT_FAILURE);
00225         }
00226 
00227         sprintf(str, "%d\n", getpid());
00228         write(i, str, strlen(str));
00229         close(i);
00230 
00231         /* Ignore TTY signals */
00232         signal(SIGTSTP, SIG_IGN);
00233         signal(SIGTTOU, SIG_IGN);
00234         signal(SIGTTIN, SIG_IGN);
00235 
00236         /* Ignore child terminate signal */
00237         signal(SIGCHLD, SIG_IGN);
00238 }
00239 
00240 /*
00241  * Main
00242  *
00243  * @param argc Number of command line arguments
00244  * @param argv Array with command line arguments
00245  * @return 0 on success, non-zero on failure
00246  */
00247 int main(int argc, char **argv)
00248 {
00249         int optc;
00250         int opt_index;
00251 
00252         gint status = 0;
00253         gboolean daemonflag = FALSE;
00254 
00255         AlarmdQueue *queue = NULL;
00256         osso_context_t *osso = NULL;
00257         gchar *queue_file = NULL;
00258         gchar *next_time_file = NULL;
00259         gchar *next_mode_file = NULL;
00260 
00261         const char optline[] = "d";
00262 
00263         struct option const options[] = {
00264                 { "daemonflag", no_argument, 0, 'd' },
00265                 { "help", no_argument, 0, 'h' },
00266                 { "version", no_argument, 0, 'V' },
00267                 { 0, 0, 0, 0 }
00268         };
00269 
00270         /* NULL the mainloop */
00271         mainloop = NULL;
00272 
00273         /* Initialise support for locales, and set the program-name */
00274         if (init_locales(PRG_NAME) != 0)
00275                 goto EXIT;
00276 
00277         /* Parse the command-line options */
00278         while ((optc = getopt_long(argc, argv, optline,
00279                                    options, &opt_index)) != -1) {
00280                 switch (optc) {
00281                 case 'd':
00282                         daemonflag = TRUE;
00283                         break;
00284 
00285                 case 'h':
00286                         usage();
00287                         goto EXIT;
00288 
00289                 case 'V':
00290                         version();
00291                         goto EXIT;
00292 
00293                 default:
00294                         usage();
00295                         status = EINVAL;
00296                         goto EXIT;
00297                 }
00298         }
00299 
00300         /* We don't take any non-flag arguments */
00301         if ((argc - optind) > 0) {
00302                 fprintf(stderr,
00303                         _("%s: Too many arguments\n"
00304                           "Try: `%s --help' for more information.\n"),
00305                         progname, progname);
00306                 status = EINVAL;
00307                 goto EXIT;
00308         }
00309 
00310         DLOG_OPEN(PRG_NAME);
00311 
00312         /* Daemonize if requested */
00313         if (daemonflag == TRUE)
00314                 daemonize();
00315 
00316         signal(SIGUSR1, signal_handler);
00317         signal(SIGHUP, signal_handler);
00318         signal(SIGTERM, signal_handler);
00319 
00320         /* Initialize GLib type system. */
00321         g_type_init();
00322 
00323         alarmd_type_init();
00324         osso = init_osso();
00325         dbus_set_osso(osso);
00326 
00327         queue_file = g_build_filename(DATADIR, "alarm_queue.xml", NULL);
00328         next_time_file = g_build_filename(DATADIR, "next_alarm_time", NULL);
00329         next_mode_file = g_build_filename(DATADIR, "next_alarm_mode", NULL);
00330 
00331         queue = init_queue(queue_file, next_time_file, next_mode_file);
00332         set_osso_callbacks(osso, queue);
00333         g_free(queue_file);
00334         g_free(next_time_file);
00335         g_free(next_mode_file);
00336 
00337         /* Register a mainloop */
00338         mainloop = g_main_loop_new(NULL, FALSE);
00339 
00340         /* Run the main loop */
00341         g_main_loop_run(mainloop);
00342 
00343 
00344         deinit_osso(osso, queue);
00345         g_object_unref(queue);
00346         /* If we get here, the main loop has terminated;
00347          * either because we requested or because of an error
00348          */
00349 EXIT:
00350         /* If the mainloop is initialised, unreference it */
00351         if (mainloop != NULL)
00352                 g_main_loop_unref(mainloop);
00353 
00354         /* Log a farewell message and close the log */
00355         DLOG_INFO("Exiting...");
00356         LOG_CLOSE();
00357 
00358         return status;
00359 }

Generated on Thu Dec 21 18:23:30 2006 for Alarmd by  doxygen 1.4.2