LCOV - code coverage report
Current view: top level - client - options.c (source / functions) Hit Total Coverage
Test: coverage-client.info Lines: 138 160 86.2 %
Date: 2016-02-03 22:31:46 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
       2             : /*
       3             :  *    options.c
       4             :  *    This file is part of "Sauvegarde" project.
       5             :  *
       6             :  *    (C) Copyright 2014 - 2016 Olivier Delhomme
       7             :  *     e-mail : olivier.delhomme@free.fr
       8             :  *
       9             :  *    "Sauvegarde" is free software: you can redistribute it and/or modify
      10             :  *    it under the terms of the GNU General Public License as published by
      11             :  *    the Free Software Foundation, either version 3 of the License, or
      12             :  *    (at your option) any later version.
      13             :  *
      14             :  *    "Sauvegarde" is distributed in the hope that it will be useful,
      15             :  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :  *    GNU General Public License for more details.
      18             :  *
      19             :  *    You should have received a copy of the GNU General Public License
      20             :  *    along with "Sauvegarde".  If not, see <http://www.gnu.org/licenses/>
      21             :  */
      22             : /**
      23             :  * @file client/options.c
      24             :  *
      25             :  *  This file contains all the functions to manage command line options.
      26             :  * @todo review file configuration sections to make it more consistant
      27             :  *       with actual program.
      28             :  */
      29             : 
      30             : #include "client.h"
      31             : 
      32             : static void print_selected_options(options_t *opt);
      33             : static void read_from_group_client(options_t *opt, GKeyFile *keyfile, gchar *filename);
      34             : static void read_from_group_server(options_t *opt, GKeyFile *keyfile, gchar *filename);
      35             : static void read_from_configuration_file(options_t *opt, gchar *filename);
      36             : static void print_filelist(GSList *filelist, gchar *title);
      37             : 
      38             : 
      39             : /**
      40             :  * Prints filenames contained in the list.
      41             :  * @param filelist is a list containing file list (directories to be
      42             :  *        saved or to be excluded for instance).
      43             :  * @param title is a gchar * string that is printed at the top of the
      44             :  *        list.
      45             :  */
      46           2 : static void print_filelist(GSList *filelist, gchar *title)
      47             : {
      48             : 
      49           2 :     if (filelist != NULL)
      50             :         {
      51           0 :             fprintf(stdout, "%s", title);
      52           0 :             while (filelist != NULL)
      53             :                 {
      54           0 :                     fprintf(stdout, "\t%s\n", (char *) filelist->data);
      55           0 :                     filelist = g_slist_next(filelist);
      56             :                 }
      57             :         }
      58           2 : }
      59             : 
      60             : 
      61             : /**
      62             :  * Prints options as selected when invoking the program with -v option
      63             :  * @param opt the options_t * structure that contains all selected options
      64             :  *        from the command line and that will be used by the program.
      65             :  */
      66           1 : static void print_selected_options(options_t *opt)
      67             : {
      68           1 :     gchar *blocksize = NULL;
      69             : 
      70           1 :     if (opt != NULL)
      71             :         {
      72           1 :             fprintf(stdout, _("\n%s options are:\n"), PROGRAM_NAME);
      73             : 
      74           1 :             print_filelist(opt->dirname_list, _("Directory list:\n"));
      75           1 :             print_filelist(opt->exclude_list, _("Exclude list:\n"));
      76             : 
      77           1 :             if (opt->adaptive == FALSE)
      78             :                 {
      79             :                     /**
      80             :                      * We need to translated this number into a string before
      81             :                      * inserting it into the final string in order to allow
      82             :                      * this final string to be translated in an other language.
      83             :                      */
      84           1 :                     blocksize = g_strdup_printf("%" G_GINT64_FORMAT, opt->blocksize);
      85           1 :                     fprintf(stdout, _("Blocksize: %s\n"), blocksize);
      86           1 :                     free_variable(blocksize);
      87             :                 }
      88             :             else
      89             :                 {
      90           0 :                     fprintf(stdout, _("Blocksize: adaptive mode\n"));
      91             :                 }
      92             : 
      93           1 :             print_string_option(_("Configuration file: %s\n"), opt->configfile);
      94           1 :             print_string_option(_("Cache directory: %s\n"), opt->dircache);
      95           1 :             print_string_option(_("Cache database name: %s\n"), opt->dbname);
      96           1 :             print_string_option(_("Server's IP address: %s\n"), opt->ip);
      97           1 :             fprintf(stdout, _("Server's port number: %d\n"), opt->port);
      98           1 :             fprintf(stdout, _("Buffersize: %d\n"), opt->buffersize);
      99             :         }
     100           1 : }
     101             : 
     102             : 
     103             : /**
     104             :  * Reads keys in keyfile if group GN_CLIENT is in that keyfile and fills
     105             :  * options_t *opt structure accordingly.
     106             :  * @param[in,out] opt : options_t * structure to store options read from the
     107             :  *                configuration file "filename".
     108             :  * @param keyfile is the GKeyFile structure that is used by glib to read
     109             :  *        groups and keys from.
     110             :  * @param filename : the filename of the configuration file to read from
     111             :  */
     112           1 : static void read_from_group_client(options_t *opt, GKeyFile *keyfile, gchar *filename)
     113             : {
     114           1 :     gchar *dircache = NULL;
     115             : 
     116           1 :     if (keyfile != NULL && filename != NULL && g_key_file_has_group(keyfile, GN_CLIENT) == TRUE)
     117             :         {
     118             :             /* Reading the directory list */
     119           1 :             opt->dirname_list = read_list_from_file(keyfile, filename, GN_CLIENT, KN_DIR_LIST, _("Could not load directory list from file"));
     120           1 :             opt->exclude_list = read_list_from_file(keyfile, filename, GN_CLIENT, KN_EXC_LIST, _("Could not load exclude file list from file"));
     121             : 
     122             :             /* Reading blocksize */
     123           1 :             opt->blocksize = read_int64_from_file(keyfile, filename, GN_CLIENT, KN_BLOCK_SIZE, _("Could not load blocksize from file"), CLIENT_BLOCK_SIZE);
     124             : 
     125             :             /* Reading the cache directory if any */
     126           1 :             dircache = read_string_from_file(keyfile, filename, GN_CLIENT, KN_CACHE_DIR, _("Could not load directory name"));
     127           1 :             opt->dircache = normalize_directory(dircache);
     128           1 :             free_variable(dircache);
     129             : 
     130             :             /* Reading filename of the database if any */
     131           1 :             opt->dbname = read_string_from_file(keyfile, filename, GN_CLIENT, KN_DB_NAME, _("Could not load cache database name"));
     132             : 
     133             :             /* Adaptative mode for blocksize ? */
     134           1 :             opt->adaptive = read_boolean_from_file(keyfile, filename, GN_CLIENT, KN_ADAPTIVE, _("Could not load adaptive configuration from file."));
     135             : 
     136             :             /* Buffer size to be used to send data to server */
     137           1 :             opt->buffersize = read_int_from_file(keyfile, filename, GN_CLIENT, KN_BUFFER_SIZE, _("Could not load buffersize from file"), CLIENT_MIN_BUFFER);
     138             :         }
     139             : 
     140           1 :    read_debug_mode_from_file(keyfile, filename);
     141           1 : }
     142             : 
     143             : /**
     144             :  * Reads keys in keyfile if groupname is in that keyfile and fills
     145             :  * options_t *opt structure accordingly.
     146             :  * @param[in,out] opt : options_t * structure to store options read from the
     147             :  *                configuration file "filename".
     148             :  * @param keyfile is the GKeyFile structure that is used by glib to read
     149             :  *        groups and keys from.
     150             :  * @param filename : the filename of the configuration file to read from
     151             :  */
     152           1 : static void read_from_group_server(options_t *opt, GKeyFile *keyfile, gchar *filename)
     153             : {
     154           1 :     gint port = 0;
     155             : 
     156           1 :     if (opt != NULL && keyfile != NULL && filename != NULL && g_key_file_has_group(keyfile, GN_SERVER) == TRUE)
     157             :         {
     158             :             /* Reading the port number if any */
     159           1 :             port = read_int_from_file(keyfile, filename, GN_SERVER, KN_SERVER_PORT, _("Could not load server port number from file."), SERVER_PORT);
     160             : 
     161           1 :             if (port > 1024 && port < 65535)
     162             :                 {
     163           1 :                     opt->port = port;
     164             :                 }
     165             : 
     166             :             /* Reading IP address of server's host if any */
     167           1 :             opt->ip = read_string_from_file(keyfile, filename, GN_SERVER, KN_SERVER_IP, _("Could not load cache database name"));
     168             :         }
     169           1 : }
     170             : 
     171             : 
     172             : /**
     173             :  * Reads from the configuration file "filename" and fills the options_t *
     174             :  * opt structure.
     175             :  * @param[in,out] opt : options_t * structure to store options read from
     176             :  *                the configuration file "filename"
     177             :  * @param filename : the filename of the configuration file to read from
     178             :  */
     179           3 : static void read_from_configuration_file(options_t *opt, gchar *filename)
     180             : {
     181           3 :     GKeyFile *keyfile = NULL;      /** Configuration file parser                          */
     182           3 :     GError *error = NULL;          /** Glib error handling                                */
     183             : 
     184           3 :     if (filename != NULL)
     185             :         {
     186             : 
     187           1 :             if (opt->configfile != NULL)
     188             :                 {
     189           0 :                     free_variable(opt->configfile);
     190             :                 }
     191             : 
     192           1 :             print_debug(_("Reading configuration from file %s\n"), filename);
     193             : 
     194           1 :             keyfile = g_key_file_new();
     195             : 
     196           1 :             if (g_key_file_load_from_file(keyfile, filename, G_KEY_FILE_KEEP_COMMENTS, &error))
     197             :                 {
     198           1 :                     opt->configfile = g_strdup(filename);
     199             : 
     200           1 :                     read_from_group_client(opt, keyfile, filename);
     201           1 :                     read_from_group_server(opt, keyfile, filename);
     202             :                 }
     203           0 :             else if (error != NULL)
     204             :                 {
     205           0 :                     print_error(__FILE__, __LINE__, _("Failed to open %s configuration file: %s\n"), filename, error->message);
     206           0 :                     error = free_error(error);
     207             :                 }
     208             : 
     209           1 :             g_key_file_free(keyfile);
     210             :         }
     211           3 : }
     212             : 
     213             : 
     214             : /**
     215             :  * This function parses command line options. It sets the options in this
     216             :  * order. It means that the value used for an option is the one set in the
     217             :  * lastest step.
     218             :  * 0) default values are set into the options_t * structure
     219             :  * 1) reads the default configuration file if any.
     220             :  * 2) reads the configuration file mentionned on the command line.
     221             :  * 3) sets the command line options (except for the list of directories,
     222             :  *    all other values are replaced by thoses in the command line)
     223             :  * @param argc : number of arguments given on the command line.
     224             :  * @param argv : an array of strings that contains command line arguments.
     225             :  * @returns options_t structure malloc'ed and filled upon choosen command
     226             :  *          line's option
     227             :  */
     228           3 : options_t *manage_command_line_options(int argc, char **argv)
     229             : {
     230           3 :     gboolean version = FALSE;      /** True if -v was selected on the command line           */
     231           3 :     gint debug = -4;               /** 0 == FALSE and other values == TRUE                   */
     232           3 :     gint adaptive = -1;          /** 0 == FALSE and other positive values == TRUE          */
     233           3 :     gchar **dirname_array = NULL;  /** array of dirnames left on the command line            */
     234           3 :     gchar **exclude_array = NULL;  /** array of dirnames and filenames to be excluded        */
     235           3 :     gchar *configfile = NULL;      /** filename for the configuration file if any            */
     236           3 :     gint64 blocksize = 0;          /** computed block size in bytes                          */
     237           3 :     gint buffersize = 0;           /** buffer size used to send data to server               */
     238           3 :     gchar *dircache = NULL;        /** Directory used to store cache files                   */
     239           3 :     gchar *dbname = NULL;          /** Database filename where data and meta data are cached */
     240           3 :     gchar *ip =  NULL;             /** IP address where is located server's program          */
     241           3 :     gint port = 0;                 /** Port number on which to send things to the server     */
     242             : 
     243           3 :     GOptionEntry entries[] =
     244             :     {
     245             :         { "version", 'v', 0, G_OPTION_ARG_NONE, &version, N_("Prints program version"), NULL },
     246             :         { "debug", 'd', 0,  G_OPTION_ARG_INT, &debug, N_("Activates (1) or desactivates (0) debug mode."), N_("BOOLEAN")},
     247             :         { "configuration", 'c', 0, G_OPTION_ARG_STRING, &configfile, N_("Specify an alternative configuration file."), N_("FILENAME")},
     248             :         { "blocksize", 'b', 0, G_OPTION_ARG_INT64, &blocksize, N_("Fixed block SIZE used to compute hashs."), N_("SIZE")},
     249             :         { "adaptive", 'a', 0, G_OPTION_ARG_INT, &adaptive, N_("Adapative block size used to compute hashs."), N_("BOOLEAN")},
     250             :         { "buffersize", 's', 0, G_OPTION_ARG_INT, &buffersize, N_("SIZE of the cache used to send data to server."), N_("SIZE")},
     251             :         { "dircache", 'r', 0, G_OPTION_ARG_STRING, &dircache, N_("Directory DIRNAME where to cache files."), N_("DIRNAME")},
     252             :         { "dbname", 'f', 0, G_OPTION_ARG_STRING, &dbname, N_("Database FILENAME."), N_("FILENAME")},
     253             :         { "ip", 'i', 0, G_OPTION_ARG_STRING, &ip, N_("IP address where server program is."), "IP"},
     254             :         { "port", 'p', 0, G_OPTION_ARG_INT, &port, N_("Port NUMBER on which to listen."), N_("NUMBER")},
     255             :         { "exclude", 'x', 0, G_OPTION_ARG_FILENAME_ARRAY, &exclude_array, N_("Exclude FILENAME from being saved."), N_("FILENAME")},
     256             :         { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &dirname_array, "", NULL},
     257             :         { NULL }
     258             :     };
     259             : 
     260           3 :     GError *error = NULL;
     261             :     GOptionContext *context;
     262           3 :     options_t *opt = NULL;    /** Structure to manage program's options            */
     263           3 :     gchar *bugreport = NULL;  /** Bug Report message                               */
     264           3 :     gchar *summary = NULL;    /** Abstract for the program                         */
     265           3 :     gchar *defaultconfigfilename = NULL;
     266             : 
     267           3 :     bugreport = g_strconcat(_("Please report bugs to: "), PACKAGE_BUGREPORT, NULL);
     268           3 :     summary = g_strdup(_("This program is monitoring file changes in the filesystem and is hashing\nfiles with SHA256 algorithms from Glib."));
     269           3 :     context = g_option_context_new("");
     270             : 
     271           3 :     set_debug_mode(ENABLE_DEBUG);
     272             : 
     273           3 :     set_option_context_options(context, entries, TRUE, bugreport, summary);
     274             : 
     275           3 :     if (!g_option_context_parse(context, &argc, &argv, &error))
     276             :         {
     277           0 :             g_print(_("Option parsing failed: %s\n"), error->message);
     278           0 :             exit(EXIT_FAILURE);
     279             :         }
     280             : 
     281             :     /* 0) Setting default values */
     282             : 
     283           2 :     opt = (options_t *) g_malloc0(sizeof(options_t));
     284             : 
     285           2 :     opt->dirname_list = NULL;
     286           2 :     opt->exclude_list = NULL;
     287           2 :     opt->blocksize = CLIENT_BLOCK_SIZE;
     288           2 :     opt->configfile = NULL;
     289           2 :     opt->dircache = g_strdup("/var/tmp/cdpfgl");
     290           2 :     opt->dbname = g_strdup("filecache.db");
     291           2 :     opt->ip = g_strdup("localhost");
     292           2 :     opt->port = SERVER_PORT;
     293           2 :     opt->buffersize = -1;
     294           2 :     opt->adaptive = FALSE;
     295             : 
     296             :     /* 1) Reading options from default configuration file */
     297           2 :     defaultconfigfilename = get_probable_etc_path(PROGRAM_NAME, "client.conf");
     298           2 :     read_from_configuration_file(opt,  defaultconfigfilename);
     299           2 :     defaultconfigfilename = free_variable(defaultconfigfilename);
     300             : 
     301           2 :     opt->version = version; /* only TRUE if -v or --version was invoked */
     302             : 
     303             : 
     304             :     /* 2) Reading the configuration from the configuration file specified
     305             :      *    on the command line (if any).
     306             :      */
     307           2 :     if (configfile != NULL)
     308             :         {
     309           1 :             read_from_configuration_file(opt, configfile);
     310             :         }
     311             : 
     312             : 
     313             :     /* 3) retrieving other options from the command line. Directories are
     314             :      *    added to the existing directory list and then the array is freed
     315             :      *    as every string has been copied with g_strdup().
     316             :      */
     317           2 :     set_debug_mode_upon_cmdl(debug);
     318             : 
     319           2 :     opt->dirname_list = convert_gchar_array_to_GSList(dirname_array, opt->dirname_list);
     320           2 :     opt->exclude_list = convert_gchar_array_to_GSList(exclude_array, opt->exclude_list);
     321             : 
     322           2 :     g_strfreev(dirname_array);
     323           2 :     g_strfreev(exclude_array);
     324             : 
     325           2 :     if (blocksize > 0)
     326             :         {
     327           0 :             opt->blocksize = blocksize;
     328             :         }
     329             : 
     330           2 :     if (dircache != NULL)
     331             :         {
     332           0 :             free_variable(opt->dircache);
     333           0 :             opt->dircache = g_strdup(dircache);
     334             :         }
     335             : 
     336           2 :     if (dbname != NULL)
     337             :         {
     338           0 :             free_variable(opt->dbname);
     339           0 :             opt->dbname = g_strdup(dbname);
     340             :         }
     341             : 
     342           2 :     if (ip != NULL)
     343             :         {
     344           0 :             free_variable(opt->ip);
     345           0 :             opt->ip = g_strdup(ip);
     346             :         }
     347             : 
     348           2 :     if (port > 1024 && port < 65535)
     349             :         {
     350           0 :             opt->port = port;
     351             :         }
     352             : 
     353           2 :     if (adaptive > 0)
     354             :         {
     355           0 :             opt->adaptive = TRUE;
     356             :         }
     357           2 :     else if (adaptive == 0)
     358             :         {
     359           0 :             opt->adaptive = FALSE;
     360             :         }
     361             : 
     362           2 :     if (buffersize > 0)
     363             :         {
     364           0 :             opt->buffersize = buffersize;
     365             :         }
     366           2 :     else if (opt->buffersize <= 0)
     367             :         {
     368           1 :             opt->buffersize = CLIENT_MIN_BUFFER;
     369             :         }
     370             : 
     371           2 :     g_option_context_free(context);
     372           2 :     free_variable(ip);
     373           2 :     free_variable(dbname);
     374           2 :     free_variable(dircache);
     375           2 :     free_variable(bugreport);
     376           2 :     free_variable(summary);
     377             : 
     378           2 :     return opt;
     379             : }
     380             : 
     381             : 
     382             : /**
     383             :  * Frees the options structure if necessary
     384             :  * @param opt : the malloc'ed options_t structure
     385             :  */
     386           1 : void free_options_t(options_t *opt)
     387             : {
     388           1 :     if (opt != NULL)
     389             :         {
     390           1 :             free_list(opt->dirname_list);
     391           1 :             free_variable(opt->dircache);
     392           1 :             free_variable(opt->configfile);
     393           1 :             free_variable(opt->dbname);
     394           1 :             free_variable(opt->ip);
     395           1 :             free_variable(opt);
     396             :         }
     397             : 
     398           1 : }
     399             : 
     400             : 
     401             : /**
     402             :  * Decides what to do upon command lines options passed to the program
     403             :  * @param argc : number of arguments given on the command line.
     404             :  * @param argv : an array of strings that contains command line arguments.
     405             :  * @returns options_t structure malloc'ed and filled upon choosen command
     406             :  *          line's option (in manage_command_line_options function).
     407             :  */
     408           3 : options_t *do_what_is_needed_from_command_line_options(int argc, char **argv)
     409             : {
     410           3 :     options_t *opt = NULL;  /** Structure to manage options from the command line can be freed when no longer needed */
     411             : 
     412           3 :     opt = manage_command_line_options(argc, argv);
     413             : 
     414           2 :     if (opt != NULL)
     415             :         {
     416           2 :             if (opt->version == TRUE)
     417             :                 {
     418           1 :                     print_program_version(PROGRAM_NAME, CLIENT_DATE, CLIENT_VERSION, CLIENT_AUTHORS, CLIENT_LICENSE);
     419           1 :                     print_libraries_versions(PROGRAM_NAME);
     420           1 :                     print_selected_options(opt);
     421           1 :                     exit(EXIT_SUCCESS);
     422             :                 }
     423             :         }
     424             : 
     425           1 :     return opt;
     426             : }
     427             : 
     428             : 

Generated by: LCOV version 1.11