nfs-ganesha 1.4

nfs_main.c

Go to the documentation of this file.
00001 /*
00002  * vim:expandtab:shiftwidth=8:tabstop=8:
00003  *
00004  * Copyright CEA/DAM/DIF  (2008)
00005  * contributeur : Philippe DENIEL   philippe.deniel@cea.fr
00006  *                Thomas LEIBOVICI  thomas.leibovici@cea.fr
00007  *
00008  *
00009  * This program is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 3 of the License, or (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * Lesser General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU Lesser General Public
00020  * License along with this library; if not, write to the Free Software
00021  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00022  *
00023  * ---------------------------------------
00024  */
00025 
00035 #ifdef HAVE_CONFIG_H
00036 #include "config.h"
00037 #endif
00038 
00039 #ifdef _SOLARIS
00040 #include "solaris_port.h"
00041 #endif
00042 
00043 #include "nfs_init.h"
00044 #include "fsal.h"
00045 #include "log.h"
00046 #include <stdio.h>
00047 #include <string.h>
00048 #include <pthread.h>
00049 #include <signal.h>             /* for sigaction */
00050 #include <errno.h>
00051 #ifdef _PNFS
00052 #include "fsal_pnfs.h"
00053 #endif /* _PNFS */
00054 
00055 /* parameters for NFSd startup and default values */
00056 
00057 nfs_start_info_t my_nfs_start_info = {
00058   .dump_default_config = FALSE,
00059   .lw_mark_trigger = FALSE
00060 };
00061 
00062 char *my_config_path = "/etc/ganesha/ganesha.conf";
00063 char my_pidfile[] = "/var/run/ganesha.pid";
00064 char log_path[MAXPATHLEN] = "";
00065 char exec_name[MAXPATHLEN] = "nfs-ganesha";
00066 char host_name[MAXHOSTNAMELEN] = "localhost";
00067 int debug_level = -1;
00068 int detach_flag = FALSE;
00069 char ganesha_exec_path[MAXPATHLEN];
00070 
00071 /* command line syntax */
00072 
00073 char options[] = "h@RTdS:F:S:P:f:L:N:E:p:";
00074 char usage[] =
00075     "Usage: %s [-hd][-L <logfile>][-N <dbg_lvl>][-f <config_file>]\n"
00076     "\t[-h]                display this help\n"
00077     "\t[-L <logfile>]      set the default logfile for the daemon\n"
00078     "\t[-N <dbg_lvl>]      set the verbosity level\n"
00079     "\t[-f <config_file>]  set the config file to be used\n"
00080     "\t[-p <pid_file>]     set the pid file\n"
00081     "\t[-d]                the daemon starts in background, in a new process group\n"
00082     "\t[-R]                daemon will manage RPCSEC_GSS (default is no RPCSEC_GSS)\n"
00083     "\t[-T]                dump the default configuration on stdout\n"
00084     "\t[-E] <epoch<]       overrides ServerBootTime for ServerEpoch\n"
00085     "----------------- Signals ----------------\n"
00086     "SIGUSR1    : Enable/Disable File Content Cache forced flush\n"
00087     "SIGTERM    : Cleanly terminate the program\n"
00088     "------------- Default Values -------------\n"
00089     "LogFile    : /tmp/nfs-ganesha.log\n"
00090     "PidFile    : /var/run/ganesha.pid\n"
00091     "DebugLevel : NIV_EVENT\n" "ConfigFile : /etc/ganesha/ganesha.conf\n";
00092 
00105 int main(int argc, char *argv[])
00106 {
00107   char *tempo_exec_name = NULL;
00108   char localmachine[MAXHOSTNAMELEN];
00109   int c;
00110   int pidfile;
00111 #ifndef HAVE_DAEMON
00112   pid_t son_pid;
00113 #endif
00114   sigset_t signals_to_block;
00115 
00116   /* Set the server's boot time and epoch */
00117   ServerBootTime = time(NULL);
00118   ServerEpoch    = ServerBootTime;
00119 
00120   /* retrieve executable file's name */
00121   strncpy(ganesha_exec_path, argv[0], MAXPATHLEN);
00122 
00123   if((tempo_exec_name = strrchr(argv[0], '/')) != NULL)
00124     strcpy((char *)exec_name, tempo_exec_name + 1);
00125 
00126   if(*exec_name == '\0')
00127     strcpy((char *)exec_name, argv[0]);
00128 
00129   /* get host name */
00130   if(gethostname(localmachine, sizeof(localmachine)) != 0)
00131     {
00132       fprintf(stderr, "Could not get local host name, exiting...");
00133       exit(1);
00134     }
00135   else
00136     strncpy(host_name, localmachine, MAXHOSTNAMELEN);
00137 
00138   strcpy(config_path, my_config_path);
00139 
00140   strcpy( pidfile_path, my_pidfile ) ;
00141 
00142   /* now parsing options with getopt */
00143   while((c = getopt(argc, argv, options)) != EOF)
00144     {
00145       switch (c)
00146         {
00147         case '@':
00148           /* A litlle backdoor to keep track of binary versions */
00149           printf("%s compiled on %s at %s\n", exec_name, __DATE__, __TIME__);
00150           printf("Release = %s\n", VERSION);
00151           printf("Release comment = %s\n", VERSION_COMMENT);
00152           printf("Git HEAD = %s\n", _GIT_HEAD_COMMIT ) ;
00153           printf("Git Describe = %s\n", _GIT_DESCRIBE ) ;
00154           exit(0);
00155           break;
00156 
00157         case 'L':
00158           /* Default Log */
00159           strncpy(log_path, optarg, MAXPATHLEN);
00160           break;
00161 
00162         case 'N':
00163           /* debug level */
00164           debug_level = ReturnLevelAscii(optarg);
00165           if(debug_level == -1)
00166             {
00167               fprintf(stderr,
00168                       "Invalid value for option 'N': NIV_NULL, NIV_MAJ, NIV_CRIT, NIV_EVENT, NIV_DEBUG, NIV_MID_DEBUG or NIV_FULL_DEBUG expected.\n");
00169               exit(1);
00170             }
00171           break;
00172 
00173         case 'f':
00174           /* config file */
00175           strncpy(config_path, optarg, MAXPATHLEN);
00176           break;
00177 
00178         case 'p':
00179           /* PID file */
00180           strncpy( pidfile_path, optarg, MAXPATHLEN ) ;
00181           break ;
00182 
00183         case 'd':
00184           /* Detach or not detach ? */
00185           detach_flag = TRUE;
00186           break;
00187 
00188         case 'R':
00189           /* Shall we manage  RPCSEC_GSS ? */
00190           fprintf(stderr,
00191                   "\n\nThe -R flag is deprecated, use this syntax in the configuration file instead:\n\n");
00192           fprintf(stderr, "NFS_KRB5\n");
00193           fprintf(stderr, "{\n");
00194           fprintf(stderr, "\tPrincipalName = nfs@<your_host> ;\n");
00195           fprintf(stderr, "\tKeytabPath = /etc/krb5.keytab ;\n");
00196           fprintf(stderr, "\tActive_krb5 = TRUE ;\n");
00197           fprintf(stderr, "}\n\n\n");
00198           exit(1);
00199           break;
00200 
00201         case 'T':
00202           /* Dump the default configuration on stdout */
00203           my_nfs_start_info.dump_default_config = TRUE;
00204           break;
00205 
00206         case 'E':
00207           ServerEpoch = (time_t) atoll(optarg);
00208           break;
00209 
00210         case '?':
00211         case 'h':
00212         default:
00213           /* display the help */
00214           fprintf(stderr, usage, exec_name);
00215           exit(0);
00216           break;
00217         }
00218     }
00219 
00220   /* initialize memory and logging */
00221   nfs_prereq_init(exec_name, host_name, debug_level, log_path);
00222 
00223   /* Start in background, if wanted */
00224   if(detach_flag)
00225     {
00226 #ifdef HAVE_DAEMON
00227         /* daemonize the process (fork, close xterm fds,
00228          * detach from parent process) */
00229         if (daemon(0, 0))
00230           LogFatal(COMPONENT_MAIN,
00231                    "Error detaching process from parent: %s",
00232                    strerror(errno));
00233 #else
00234       /* Step 1: forking a service process */
00235       switch (son_pid = fork())
00236         {
00237         case -1:
00238           /* Fork failed */
00239           LogFatal(COMPONENT_MAIN,
00240                    "Could not start nfs daemon (fork error %d (%s)",
00241                    errno, strerror(errno));
00242           break;
00243 
00244         case 0:
00245           /* This code is within the son (that will actually work)
00246            * Let's make it the leader of its group of process */
00247           if(setsid() == -1)
00248             {
00249               LogFatal(COMPONENT_MAIN,
00250                        "Could not start nfs daemon (setsid error %d (%s)",
00251                        errno, strerror(errno));
00252             }
00253           break;
00254 
00255         default:
00256           /* This code is within the father, it is useless, it must die */
00257           LogFullDebug(COMPONENT_MAIN, "Starting a son of pid %d", son_pid);
00258           exit(0);
00259           break;
00260         }
00261 #endif
00262     }
00263 
00264   /* Make sure Linux file i/o will return with error if file size is exceeded. */
00265 #ifdef _LINUX
00266   signal(SIGXFSZ, SIG_IGN);
00267 #endif
00268 
00269   /* Echo PID into pidfile */
00270   if( ( pidfile = open(pidfile_path, O_CREAT|O_RDWR, 0644)) == -1 )
00271    {
00272      LogFatal( COMPONENT_MAIN, "Can't open pid file %si for writing", pidfile_path ) ;
00273    }
00274   else
00275    {
00276      char linebuf[1024];
00277      struct flock lk;
00278 
00279      /* Try to obtain a lock on the file */
00280      lk.l_type = F_WRLCK;
00281      lk.l_whence = SEEK_SET;
00282      lk.l_start = (off_t)0;
00283      lk.l_len = (off_t)0;
00284      if (fcntl(pidfile, F_SETLK, &lk) == -1)
00285        LogFatal( COMPONENT_MAIN, "Ganesha already started");
00286 
00287      /* Put pid into file, then close it */
00288      (void) snprintf(linebuf, sizeof(linebuf), "%u\n", getpid() ) ;
00289      if (write(pidfile, linebuf, strlen(linebuf)) == -1)
00290        LogCrit( COMPONENT_MAIN, "Couldn't write pid to file %s",
00291            pidfile_path);
00292    }
00293 
00294   /* Set up for the signal handler.
00295    * Blocks the signals the signal handler will handle.
00296    */
00297   sigemptyset(&signals_to_block);
00298   sigaddset(&signals_to_block, SIGTERM);
00299   sigaddset(&signals_to_block, SIGHUP);
00300   sigaddset(&signals_to_block, SIGPIPE);
00301   if(pthread_sigmask(SIG_BLOCK, &signals_to_block, NULL) != 0)
00302     LogFatal(COMPONENT_MAIN,
00303              "Could not start nfs daemon, pthread_sigmask failed");
00304 
00305   /* Set the parameter to 0 before doing anything */
00306   memset((char *)&nfs_param, 0, sizeof(nfs_parameter_t));
00307 
00308   /* Get the FSAL functions */
00309   FSAL_LoadFunctions();
00310 
00311   /* Get the FSAL consts */
00312   FSAL_LoadConsts();
00313 
00314 #ifdef _PNFS_MDS
00315   FSAL_LoadMDSFunctions();
00316 #endif /* _PNFS_MDS */
00317 #ifdef _PNFS_DS
00318   FSAL_LoadDSFunctions();
00319 #endif
00320 
00321   LogEvent(COMPONENT_MAIN,
00322            ">>>>>>>>>>--------------------------------------- <<<<<<<<<<" ) ;
00323 
00324   LogEvent(COMPONENT_MAIN,
00325            ">>>>>>>>>> Starting GANESHA NFS Daemon on FSAL/%s <<<<<<<<<<",
00326            FSAL_GetFSName());
00327 
00328   LogEvent(COMPONENT_MAIN,
00329            ">>>>>>>>>>--------------------------------------- <<<<<<<<<<" ) ;
00330 
00331   /* initialize default parameters */
00332 
00333   nfs_set_param_default();
00334 
00335   /* parse configuration file */
00336 
00337   if(nfs_set_param_from_conf(&my_nfs_start_info))
00338     {
00339       LogFatal(COMPONENT_INIT, "Error parsing configuration file.");
00340     }
00341 
00342   /* check parameters consitency */
00343 
00344   if(nfs_check_param_consistency())
00345     {
00346       LogFatal(COMPONENT_INIT,
00347                "Inconsistent parameters found. Exiting..." ) ;
00348     }
00349 
00350   /* Everything seems to be OK! We can now start service threads */
00351   nfs_start(&my_nfs_start_info);
00352 
00353   return 0;
00354 
00355 }