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 :
|