first version upgrade
[devspec.git] / devspec.en_US / project / recutils / utils / recfix.c
blob599e97b5a3ae31e70dff21695156214cf492adca
1 /* -*- mode: C -*-
3 * File: recfix.c
4 * Date: Tue Apr 27 12:21:48 2010
6 * GNU recutils - recfix
8 */
10 /* Copyright (C) 2010-2019 Jose E. Marchesi */
12 /* This program is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation, either version 3 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include <config.h>
28 #include <getopt.h>
29 #include <stdlib.h>
30 #include <xalloc.h>
31 #include <gettext.h>
32 #define _(str) gettext (str)
34 #include <rec.h>
35 #include <recutl.h>
37 /* Forward prototypes. */
38 static void recfix_parse_args (int argc, char **argv);
39 static bool recfix_check_database (rec_db_t db);
41 static int recfix_do_check (void);
42 static int recfix_do_sort (void);
43 #if defined REC_CRYPT_SUPPORT
44 static int recfix_do_crypt (void);
45 #endif
46 static int recfix_do_auto (void);
49 * Data types.
52 /* recfix supports several operations, enumerated in the following
53 type. */
55 enum recfix_op
57 RECFIX_OP_INVALID,
58 RECFIX_OP_CHECK,
59 #if defined REC_CRYPT_SUPPORT
60 RECFIX_OP_ENCRYPT,
61 RECFIX_OP_DECRYPT,
62 #endif
63 RECFIX_OP_SORT,
64 RECFIX_OP_AUTO
68 * Global variables.
71 bool recfix_external = true;
72 char *recfix_file = NULL;
73 int recfix_op = RECFIX_OP_INVALID;
74 char *recfix_password = NULL;
75 bool recfix_force = false;
78 * Command line options management.
81 enum
83 COMMON_ARGS,
84 NO_EXTERNAL_ARG,
85 FORCE_ARG,
86 OP_SORT_ARG,
87 #if defined REC_CRYPT_SUPPORT
88 PASSWORD_ARG,
89 OP_ENCRYPT_ARG,
90 OP_DECRYPT_ARG,
91 #endif
92 OP_CHECK_ARG,
93 OP_AUTO_ARG
96 static const struct option GNU_longOptions[] =
98 COMMON_LONG_ARGS,
99 {"no-external", no_argument, NULL, NO_EXTERNAL_ARG},
100 {"force", no_argument, NULL, FORCE_ARG},
101 {"check", no_argument, NULL, OP_CHECK_ARG},
102 {"sort", no_argument, NULL, OP_SORT_ARG},
103 #if defined REC_CRYPT_SUPPORT
104 {"password", required_argument, NULL, PASSWORD_ARG},
105 {"encrypt", no_argument, NULL, OP_ENCRYPT_ARG},
106 {"decrypt", no_argument, NULL, OP_DECRYPT_ARG},
107 #endif
108 {"auto", no_argument, NULL, OP_AUTO_ARG},
109 {NULL, 0, NULL, 0}
112 void
113 recutl_print_help (void)
115 /* TRANSLATORS: --help output, recfix synopsis.
116 no-wrap */
117 printf (_("\
118 Usage: recfix [OPTION]... [OPERATION] [OP_OPTION]... [FILE]\n"));
120 /* TRANSLATORS: --help output, recfix short description.
121 no-wrap */
122 fputs (_("\
123 Check and fix rec files.\n"),
124 stdout);
126 puts ("");
127 /* TRANSLATORS: --help output, recfix global arguments.
128 no-wrap */
129 fputs (_("\
130 --no-external don't use external descriptors.\n\
131 --force force the requested operation.\n"),
132 stdout);
134 recutl_print_help_common ();
136 puts("");
137 /* TRANSLATORS: --help output, recfix operations.
138 no-wrap */
139 fputs (_("\
140 Operations:\n\
141 --check check integrity of the specified file. Default.\n\
142 --sort sort the records in the specified file.\n\
143 --auto insert auto-generated fields in records missing them.\n"),
144 stdout);
146 #if defined REC_CRYPT_SUPPORT
147 /* TRANSLATORS: --help output, recfix operations related with encryption.
148 no-wrap */
149 fputs (_("\
150 --encrypt encrypt confidential fields in the specified file.\n\
151 --decrypt decrypt confidential fields in the specified file.\n"),
152 stdout);
154 puts("");
155 /* TRANSLATORS: --help output, recfix encryption and decryption
156 options.
157 no-wrap */
158 fputs (_("\
159 De/Encryption options:\n\
160 -s, --password=PASSWORD encrypt/decrypt with this password.\n"),
161 stdout);
162 #endif /* REC_CRYPT_SUPPORT */
164 puts("");
165 /* TRANSLATORS: --help output, notes on recfix.
166 no-wrap */
167 fputs (_("\
168 If no FILE is specified then the command acts like a filter, getting\n\
169 the data from standard input and writing the result to standard output.\n"), stdout);
171 puts("");
172 recutl_print_help_footer ();
175 static void
176 recfix_parse_args (int argc,
177 char **argv)
179 char c;
180 int ret;
182 while ((ret = getopt_long (argc,
183 argv,
184 ENCRYPTION_SHORT_ARGS,
185 GNU_longOptions,
186 NULL)) != -1)
188 c = ret;
189 switch (c)
191 COMMON_ARGS_CASES
192 case NO_EXTERNAL_ARG:
194 recfix_external = false;
195 break;
197 case FORCE_ARG:
199 recfix_force = true;
200 break;
202 #if defined REC_CRYPT_SUPPORT
203 case 's':
204 case PASSWORD_ARG:
206 if (recfix_op == RECFIX_OP_INVALID)
208 recutl_fatal (_("--password|-s must be used as an operation argument.\n"));
211 if ((recfix_op != RECFIX_OP_ENCRYPT)
212 && (recfix_op != RECFIX_OP_DECRYPT))
214 recutl_fatal (_("the specified operation does not require a password.\n"));
217 if (recfix_password != NULL)
219 recutl_fatal (_("please specify just one password.\n"));
222 recfix_password = xstrdup (optarg);
223 break;
225 #endif /* REC_CRYPT_SUPPORT */
226 case OP_CHECK_ARG:
228 if (recfix_op != RECFIX_OP_INVALID)
230 recutl_fatal (_("please specify just one operation.\n"));
233 recfix_op = RECFIX_OP_CHECK;
234 break;
236 case OP_SORT_ARG:
238 if (recfix_op != RECFIX_OP_INVALID)
240 recutl_fatal (_("please specify just one operation.\n"));
243 recfix_op = RECFIX_OP_SORT;
244 break;
246 case OP_AUTO_ARG:
248 if (recfix_op != RECFIX_OP_INVALID)
250 recutl_fatal (_("please specify just one operation.\n"));
253 recfix_op = RECFIX_OP_AUTO;
254 break;
256 #if defined REC_CRYPT_SUPPORT
257 case OP_ENCRYPT_ARG:
259 if (recfix_op != RECFIX_OP_INVALID)
261 recutl_fatal (_("please specify just one operation.\n"));
264 recfix_op = RECFIX_OP_ENCRYPT;
265 break;
267 case OP_DECRYPT_ARG:
269 if (recfix_op != RECFIX_OP_INVALID)
271 recutl_fatal (_("please specify just one operation.\n"));
274 recfix_op = RECFIX_OP_DECRYPT;
275 break;
277 #endif /* REC_CRYPT_SUPPORT */
278 default:
280 exit (EXIT_FAILURE);
285 /* The default operation is check, in case the user did not specify
286 any in the command line. */
288 if (recfix_op == RECFIX_OP_INVALID)
290 recfix_op = RECFIX_OP_CHECK;
293 #if defined REC_CRYPT_SUPPORT
294 /* The encrypt and decrypt operations require the user to specify a
295 password. If no password was specified with -s and the program
296 is running in a terminal, prompt the user to provide the
297 password. */
299 if (((recfix_op == RECFIX_OP_ENCRYPT)
300 || (recfix_op == RECFIX_OP_DECRYPT))
301 && (recfix_password == NULL))
303 if (recutl_interactive ())
305 if (recfix_op == RECFIX_OP_ENCRYPT)
307 recfix_password = recutl_getpass (true);
309 else
311 recfix_password = recutl_getpass (false);
315 if (!recfix_password || (strlen (recfix_password) == 0))
317 recutl_fatal ("please specify a password.\n");
320 #endif /* REC_CRYPT_SUPPORT */
322 /* Read the name of the file to work on. */
323 if (optind < argc)
325 if ((argc - optind) != 1)
327 recutl_print_help ();
328 exit (EXIT_FAILURE);
331 recfix_file = argv[optind++];
335 static bool
336 recfix_check_database (rec_db_t db)
338 bool ret;
339 char *errors;
340 size_t errors_size;
341 rec_buf_t buf;
343 buf = rec_buf_new (&errors, &errors_size);
344 ret = (rec_int_check_db (db,
345 true, /* Check descriptors. */
346 recfix_external, /* Use external descriptors. */
347 buf) == 0);
348 rec_buf_close (buf);
349 fprintf (stderr, "%s", errors);
351 return ret;
354 static int
355 recfix_do_check ()
357 rec_db_t db;
359 /* Read the database from the specified file and check its
360 integrity. */
362 db = recutl_read_db_from_file (recfix_file);
363 if (!db)
365 return EXIT_FAILURE;
368 if (!recfix_check_database (db))
370 return EXIT_FAILURE;
373 return EXIT_SUCCESS;
376 static int
377 recfix_do_sort ()
379 rec_db_t db = NULL;
380 size_t n_rset = 0;
381 rec_rset_t rset = NULL;
383 /* Read the database from the specified file. */
385 db = recutl_read_db_from_file (recfix_file);
386 if (!db)
388 return EXIT_FAILURE;
391 /* Sort all the record sets contained in the database. */
393 for (n_rset = 0; n_rset < rec_db_size (db); n_rset++)
395 rset = rec_db_get_rset (db, n_rset);
396 if (!rec_rset_sort (rset, NULL))
397 recutl_out_of_memory ();
400 if (!recfix_check_database (db))
402 return EXIT_FAILURE;
405 if (!recutl_file_is_writable (recfix_file))
407 recutl_error (_("file %s is not writable.\n"), recfix_file);
408 return EXIT_FAILURE;
411 recutl_write_db_to_file (db, recfix_file);
412 return EXIT_SUCCESS;
415 #if defined REC_CRYPT_SUPPORT
417 static int
418 recfix_do_crypt ()
420 rec_db_t db;
421 size_t n_rset;
423 /* Read the database from the specified file. */
425 db = recutl_read_db_from_file (recfix_file);
426 if (!db)
428 return EXIT_FAILURE;
431 /* Encrypt/decrypt any unencrypted/encrypted field marked as
432 "confidential" using the given password. */
434 for (n_rset = 0; n_rset < rec_db_size (db); n_rset++)
436 rec_mset_iterator_t iter;
437 rec_fex_t confidential_fields;
438 rec_record_t record;
439 rec_rset_t rset =
440 rec_db_get_rset (db, n_rset);
442 /* Skip record sets not having any confidential fields. */
444 confidential_fields = rec_rset_confidential (rset);
445 if (confidential_fields == NULL)
447 continue;
450 /* Process every record of the record set. */
452 iter = rec_mset_iterator (rec_rset_mset (rset));
453 while (rec_mset_iterator_next (&iter, MSET_RECORD, (const void **) &record, NULL))
455 if (recfix_op == RECFIX_OP_ENCRYPT)
457 /* Encrypt any unencrypted confidential field in this
458 record. */
460 if (!rec_encrypt_record (rset, record, recfix_password)
461 && !recfix_force)
463 recutl_error (_("the database contains already encrypted fields\n"));
464 recutl_fatal (_("please use --force or --decrypt\n"));
467 else
469 /* Decrypt any encrypted confidential field in this
470 record. */
472 rec_decrypt_record (rset, record, recfix_password);
476 rec_mset_iterator_free (&iter);
479 /* Write the modified database back to the file. */
481 recutl_write_db_to_file (db, recfix_file);
483 return EXIT_SUCCESS;
486 #endif /* REC_CRYPT_SUPPORT */
488 static int
489 recfix_do_auto ()
491 rec_db_t db = NULL;
492 size_t n_rset = 0;
494 /* Read the database from the especified file. */
496 db = recutl_read_db_from_file (recfix_file);
497 if (!db)
499 return EXIT_FAILURE;
502 /* Add auto fields to any record in the database not having it, in
503 record sets featuring auto fields. */
505 for (n_rset = 0; n_rset < rec_db_size (db); n_rset++)
507 rec_mset_iterator_t iter;
508 rec_record_t record;
509 rec_rset_t rset = rec_db_get_rset (db, n_rset);
511 iter = rec_mset_iterator (rec_rset_mset (rset));
512 while (rec_mset_iterator_next (&iter, MSET_RECORD, (const void**) &record, NULL))
514 if (!rec_rset_add_auto_fields (rset, record))
515 recutl_out_of_memory ();
518 rec_mset_iterator_free (&iter);
521 if (!recfix_check_database (db))
523 return EXIT_FAILURE;
526 recutl_write_db_to_file (db, recfix_file);
527 return EXIT_SUCCESS;
531 main (int argc, char *argv[])
533 int res = EXIT_SUCCESS;
535 recutl_init ("recfix");
537 /* Parse arguments. */
539 recfix_parse_args (argc, argv);
541 /* Execute the proper operation as specified in the recfix_op
542 variable. */
544 switch (recfix_op)
546 case RECFIX_OP_CHECK:
548 res = recfix_do_check ();
549 break;
551 case RECFIX_OP_SORT:
553 res = recfix_do_sort ();
554 break;
556 case RECFIX_OP_AUTO:
558 res = recfix_do_auto ();
559 break;
561 #if defined REC_CRYPT_SUPPORT
562 case RECFIX_OP_ENCRYPT:
563 case RECFIX_OP_DECRYPT:
565 res = recfix_do_crypt ();
566 break;
568 #endif /* REC_CRYPT_SUPPORT */
569 default:
571 /* This point shall not be reached. */
573 res = EXIT_FAILURE;
574 recutl_fatal (_("unknown operation in recfix: please report this as a bug.\n"));
578 return res;
581 /* End of recfix.c */