Main Page | Modules | Data Structures | File List | Data Fields | Related Pages

main.c

00001 /***************************************************************************
00002  * CVSID: $Id: main.c,v 1.61 2004/12/18 23:38:53 stefanb Exp $
00003  *
00004  * main.c : main() for MNT daemon
00005  *
00006  * Copyright (C) 2004 Stefan Bambach, <sbambach@gmx.net>
00007  *
00008  * Licensed under the GNU General Public License 2.0
00009  *
00010  * This program is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023  *
00024  **************************************************************************/
00025  
00026 #ifdef HAVE_CONFIG_H
00027 #  include <config.h>
00028 #endif
00029 
00030 #include <stdio.h>
00031 #include <stdlib.h>
00032 #include <string.h>
00033 #include <sys/types.h>
00034 #include <pwd.h>
00035 #include <grp.h>
00036 
00037 #include <libmnt/libmnt.h>   /* for common defines etc. */
00038 
00039 #define _GNU_SOURCE
00040 #include <getopt.h>
00041 
00042 #include "errmanager.h"
00043 #include "file.h"
00044 #include "mntd_dbus_manager.h"
00045 #include "mntd_volume_manager.h"
00046 #include "mntd_volume_config.h"
00047 #include "daemonize.h"
00048 #include "main.h"
00049 #include "sig.h"
00050 #include "dbug_mem.h"
00051 
00052 
00054 PMNTDDATA pmd = NULL;
00055 
00056 
00057 void usage(void);
00058 void sig_quit(int signum);
00059 void sig_reload(int signum);
00060 
00061 
00072 void 
00073 usage(void)
00074 {
00075     printf("Mount Daemon " PACKAGE_VERSION "\n");
00076     printf("Mounts devices automatically and unmount it again. It's meant\n");
00077     printf("to handle hotplug devices like USB storage or similar stuff.\n");
00078     printf("\n");
00079     printf("usage: mntd [-h] [-d] [-f configfile]\n");
00080     printf("\n");
00081     printf("    -h              Help (this text)\n");
00082     printf("    -d              Daemonize it\n");
00083     printf("    -r,--reload     Reload daemons configuration\n");
00084     printf("    -q,--quit       Quit daemon\n");
00085     printf("    -f,--file       Use given configfile\n");
00086     printf("    -p,--pidfile    Use given pidfile\n");
00087     printf("\n");
00088 }
00089 
00090 
00095 void sig_quit(int signum)
00096 {
00097     sb_signal_handler_t old = signal(signum, SIG_IGN);
00098     
00099     // set quit flag
00100     pmd->quit_reason = QUIT_NORMAL;
00101     
00102     // quit main loop
00103     g_main_loop_quit(pmd->loop);
00104     
00105     signal(signum, old);
00106 }
00107 
00108 
00113 void sig_reload(int signum)
00114 {
00115     sb_signal_handler_t old = signal(signum, SIG_IGN);
00116     
00117     // set reload flag
00118     pmd->quit_reason = QUIT_RELOAD;
00119     
00120     // quit main loop
00121     g_main_loop_quit(pmd->loop);
00122     
00123     signal(signum, old);
00124 }
00125 
00126 
00131 void mntd_cb_disconnect(void *user_data);
00132 void mntd_cb_disconnect(void *user_data)
00133 {
00134     PMNTDDATA pmntddata = (PMNTDDATA) user_data;
00135     
00136     // set disconnected flag
00137     pmntddata->quit_reason = QUIT_DISCONNECTED;
00138     
00139     // quit main loop
00140     g_main_loop_quit(pmntddata->loop);
00141 }
00142 
00143 
00150 int main(int argc, char* argv[])
00151 {
00152     char *config = NULL;
00153     char *pidfile = DEFAULT_PIDFILE;
00154     int i=0;
00155     char *configfile = NULL;
00156     char *configfiles[] = {
00157 #ifdef DEBUG
00158         "./mntd.conf",
00159         "../mntd.conf",
00160 #endif
00161         MNTD_CONF_DIR "/mntd.conf",
00162         "/etc/mntd/mntd.conf",
00163         "/etc/mntd.conf",
00164         NULL
00165     };
00166     int daemonize = FALSE;
00167     int reload = FALSE;
00168     int quit = FALSE;
00169     //ConfigData c;
00170     struct passwd *pwd;
00171     struct group *grp;
00172         
00173     // parse commandline options
00174     while(1) {
00175         int c;
00176         int option_index = 0;
00177         static struct option long_options[] = {
00178             {"help", no_argument, 0, 'h'},
00179             {"daemonize", no_argument, 0, 'd'},
00180             {"reload", no_argument, 0, 'r'},
00181             {"quit", no_argument, 0, 'q'},
00182             {"file", required_argument, 0, 'f'},
00183             {"pidfile", required_argument, 0, 'p'},
00184             {0, 0, 0, 0}
00185         };
00186         c = getopt_long (argc, argv, "hf:dqrp:", long_options, &option_index);
00187         if (c == -1) {
00188             break;
00189         }
00190         switch (c) {
00191         case 'h':
00192             usage();
00193             exit(EXIT_SUCCESS);
00194             break;
00195         
00196         case 'd':
00197             daemonize = TRUE;
00198             break;
00199         
00200         case 'r':
00201             reload = TRUE;
00202             break;
00203         
00204         case 'q':
00205             quit = TRUE;
00206             break;
00207         
00208         case 'f':
00209             config = optarg;
00210             break;
00211         
00212         case 'p':
00213             pidfile = optarg;
00214             break;
00215         
00216         default:
00217             usage();
00218             exit(EXIT_FAILURE);
00219             break;
00220         }
00221     }
00222     
00223     // initialize error manager
00224 #ifdef DEBUG
00225     emInit(LOG_DEBUG, EM_TYPE_SYSLOG, NULL, NULL, NULL, PACKAGE);
00226 #else
00227     emInit(LOG_NOTICE, EM_TYPE_SYSLOG, NULL, NULL, NULL, PACKAGE);
00228 #endif
00229     
00230     // activate memory debugging
00231     DBUG_MEM_INIT();
00232     
00233     // show version
00234     MSG_NOTICE("MNT daemon version " PACKAGE_VERSION " starting up");
00235     
00236     // get mem for mntd data structure
00237     pmd = (PMNTDDATA) malloc(sizeof(MNTDDATA));
00238     if (pmd==NULL) {
00239         MSG_ERR("No memory for mntd data structure left -> exiting ...");
00240         exit(EXIT_FAILURE);
00241     }
00242     
00243     // clear main structure
00244     memset(pmd, 0, sizeof(MNTDDATA));
00245     
00246     // initialize disconnect callback
00247     pmd->disconnect = mntd_cb_disconnect;
00248     
00249     // try to load config file
00250     if (config == NULL) {
00251         MSG_DEBUG("No config file specified. trying to find it.");
00252         i=0;
00253         while (configfiles[i]!=NULL) {
00254             configfile = configfiles[i];
00255             MSG_DEBUG("trying '%s' ...", configfile);
00256             if (sb_file_is_file(configfile)) {
00257                 MSG_DEBUG("found '%s'", configfile);
00258                 config = configfile;
00259                 break;
00260             }
00261             i++;
00262         }
00263     }
00264     
00265     if (config == NULL) {
00266         MSG_EMERG("No config file given and nothing found. exiting.");
00267         exit(EXIT_FAILURE);
00268     }
00269     if (!sb_file_is_file(config)) {
00270         MSG_EMERG("Config file '%s' cannot be accessed.", config);
00271         exit(EXIT_FAILURE);
00272     }
00273     
00274     // read in config file
00275     pmd->configdata = mntd_volume_config_parse(config, pidfile);
00276     if (pmd->configdata==NULL) {
00277         MSG_ERR("Error reading configfile '%s'.", config);
00278         exit(EXIT_FAILURE);
00279     }
00280     
00281     // reinit with new loglevel
00282 #ifndef DEBUG
00283     emInit(pmd->configdata->loglevel, EM_TYPE_SYSLOG, NULL, NULL, NULL, PACKAGE);
00284 #endif
00285 
00286     // handle quit daemon
00287     if (quit == TRUE) {
00288         // check for running daemon, and send SIGTERM
00289         if (sb_daemon_is_running(pmd->configdata->pidfile) == 1) {
00290             pid_t pid = sb_daemon_pidfile_read(pmd->configdata->pidfile);
00291             if (pid != -1) {
00292                 MSG_DEBUG("running daemon has pid %d -> sending SIGTERM", pid);
00293                 kill(pid, SIGTERM);
00294             }
00295         } else {
00296             MSG_ERR("No daemon to shutdown found! (If running with another pidfile than '%s', shutdown it manually by sending SIGTERM to it)", pmd->configdata->pidfile);
00297             exit(EXIT_FAILURE);
00298         }
00299         mntd_volume_config_free(&(pmd->configdata));
00300         exit(EXIT_SUCCESS);
00301     }
00302     
00303     // handle reload daemon
00304     if (reload == TRUE) {
00305         // check for running daemon, and send SIGHUP
00306         if (sb_daemon_is_running(pmd->configdata->pidfile) == 1) {
00307             pid_t pid = sb_daemon_pidfile_read(pmd->configdata->pidfile);
00308             if (pid != -1) {
00309                 MSG_DEBUG("running daemon has pid %d -> sending SIGHUP", pid);
00310                 kill(pid, SIGHUP);
00311             }
00312         } else {
00313             MSG_ERR("No daemon to reload found! (If running with another pidfile than '%s', reload it manually by sending SIGHUP to it)", pmd->configdata->pidfile);
00314             exit(EXIT_FAILURE);
00315         }
00316         mntd_volume_config_free(&(pmd->configdata));
00317         exit(EXIT_SUCCESS);
00318     }
00319     
00320     // handle daemon mode
00321     if (daemonize == TRUE) {
00322         // is started by root ?
00323         if (sb_daemon_is_started_by_root() == 0) {
00324             MSG_ERR("You have to be root to start this daemon!");
00325             exit(EXIT_FAILURE);
00326         }
00327         // is started suid ?
00328         if (sb_daemon_is_started_suid() == 1) {
00329             MSG_ERR("Do not start this daemon with suid bits set!");
00330             exit(EXIT_FAILURE);
00331         }
00332         // drop privileges
00333         sb_daemon_drop_privileges();
00334         // create no core files
00335         sb_daemon_no_corefile();
00336         // check for running daemon
00337         if (sb_daemon_is_running(pmd->configdata->pidfile) == 1) {
00338             pid_t pid = sb_daemon_pidfile_read(pmd->configdata->pidfile);
00339             MSG_ERR("Daemon (pid=%d) already running. exiting.", pid);
00340             exit(EXIT_FAILURE);
00341         }
00342         // detach daemon
00343         if (sb_daemon_init(PACKAGE, pmd->configdata->wdir, 
00344                 pmd->configdata->pidfile) != 0) {
00345             MSG_EMERG("Couldn't daemonize.");
00346             exit(EXIT_FAILURE);
00347         }
00348     } else {
00349         // generate pidfile
00350         int fd = -1;
00351         if (pmd->configdata->pidfile != NULL) {
00352             if ((fd = sb_daemon_pidfile_create_and_lock(pmd->configdata->pidfile)) == -1) {
00353                 return -1;
00354             }
00355             if (sb_daemon_pidfile_write(fd) == -1) {
00356                 return -1;
00357             }
00358         }
00359     }
00360     
00361     // get users data
00362     pwd = getpwuid(getuid());
00363     if (pwd == NULL) {
00364         MSG_ERR("Couldn't get user entry.");
00365         exit(EXIT_FAILURE);
00366     }
00367     grp = getgrgid(pwd->pw_gid);
00368     if (grp == NULL) {
00369         MSG_ERR("Couldn't get group entry.");
00370         exit(EXIT_FAILURE);
00371     }
00372 
00373     // print some daemon information
00374     MSG_INF("running as user '%s' (%d) and group '%s' (%d)", 
00375                 pwd->pw_name, pwd->pw_uid, grp->gr_name, pwd->pw_gid);
00376     
00377     // installing signal handler
00378     sb_signal_set_handler(SIGTERM, sig_quit);
00379     sb_signal_set_handler(SIGINT, sig_quit);
00380     sb_signal_set_handler(SIGQUIT, sig_quit);
00381     sb_signal_set_handler(SIGABRT, sig_quit);
00382     sb_signal_set_handler(SIGHUP, sig_reload);
00383     
00384     // start volume manager
00385     pmd->vols = new_VolumeManager(pmd->configdata->mountpath, 
00386                                             pmd->configdata->mountprefix);
00387     if (pmd->vols == NULL) {
00388         MSG_EMERG("Couldn't not initialize system.");
00389         exit(EXIT_FAILURE);
00390     }
00391     
00392     pmd->loop = g_main_loop_new(NULL, FALSE);
00393     
00394     // reconnect loop
00395     int retries = 0;
00396     while(1) {
00397         int isconnected = -1;
00398         
00399         // initialize my dbus stuff
00400         isconnected = mntd_dbus_init(pmd);
00401         if (isconnected == 0) {
00402             
00403             // reset retries counter
00404             retries = 0;
00405             
00406             // Scan for Volumes
00407             pmd->vols->rescan(pmd->vols);
00408         
00409             // run the main loop
00410             g_main_loop_run(pmd->loop);
00411             
00412         } else {
00413             
00414             pmd->quit_reason = QUIT_NOT_CONNECTED;
00415             
00416         }
00417         
00418         // check first (sleep can be interrupted by signals (quit/reload) )
00419         if (pmd->quit_reason == QUIT_DISCONNECTED) {
00420             
00421             MSG_WARNING("Disconnected from DBUS (Retrying if configured).");
00422             
00423             // quit dbus connection
00424             mntd_dbus_quit();
00425             
00426             // increment retry counter
00427             retries++;
00428             
00429             // wait a little bit
00430             if (pmd->configdata->dbus_reconnect != -1) {
00431                 usleep((pmd->configdata->sleep_millis)*1000);   // wait some second
00432             }
00433             
00434         } else if (pmd->quit_reason == QUIT_NOT_CONNECTED) {
00435             
00436             MSG_WARNING("Not connected to DBUS (Retrying if configured).");
00437             
00438             // increment retry counter
00439             retries++;
00440             
00441             // wait a little bit
00442             if (pmd->configdata->dbus_reconnect != -1) {
00443                 usleep((pmd->configdata->sleep_millis)*1000);   // wait some second
00444             }
00445             
00446         }
00447         
00448         // show quit reason
00449         if (pmd->quit_reason == QUIT_NORMAL) {
00450             
00451             MSG_INF("QUIT requested -> shutting down daemon ...");
00452             
00453             // exit
00454             break;
00455             
00456         } else if (pmd->quit_reason == QUIT_RELOAD) {
00457             
00458             MSG_INF("RELOAD requested -> reloading configuration ...");
00459             
00460             // reload config
00461             mntd_volume_config_reload(&(pmd->configdata), pidfile);
00462             
00463             // goon
00464             continue;
00465             
00466         }
00467 
00468         // check for retry config
00469         if (pmd->configdata->dbus_reconnect == -1) {
00470             break;
00471         } else if (pmd->configdata->dbus_reconnect == 0) {
00472             continue;
00473         }
00474         
00475         MSG_DEBUG("trying to connect... %d", retries);
00476 
00477         // check for maximum retries
00478         if (retries >= pmd->configdata->dbus_reconnect) {
00479             MSG_INF("maximum retries reached -> exit");
00480             break;
00481         }
00482         
00483     }
00484     
00485     // restore all signal handler to default values
00486     sb_signal_restore_all_handlers();
00487     
00488     // destroy dbus handler
00489     mntd_dbus_quit();
00490     
00491     // free volume storage
00492     g_assert(pmd->vols!=NULL);
00493     pmd->vols->destroy(pmd->vols);
00494     
00495     // remove pidfile
00496     g_assert(pmd->configdata!=NULL);
00497     sb_daemon_destroy(pmd->configdata->pidfile);
00498     
00499     // free config
00500     mntd_volume_config_free(&(pmd->configdata));
00501     
00502     // free mntd data structure
00503     if (pmd != NULL) {
00504         memset(pmd, 0, sizeof(MNTDDATA));
00505         free(pmd);
00506         pmd = NULL;
00507     }
00508     
00509     // MNT daemon exists
00510     MSG_NOTICE("MNT daemon version " PACKAGE_VERSION " exited.");
00511     
00512     // deactivate memory debugging
00513     DBUG_MEM_QUIT();
00514     
00515     return 0;
00516 }
00517 

Generated on Wed Mar 30 13:43:26 2005 for Mntd by  doxygen 1.3.9.1