4 * Date: Tue Apr 27 12:21:48 2010
6 * GNU recutils - recfix
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/>.
32 #define _(str) gettext (str)
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);
46 static int recfix_do_auto (void);
52 /* recfix supports several operations, enumerated in the following
59 #if defined REC_CRYPT_SUPPORT
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.
87 #if defined REC_CRYPT_SUPPORT
96 static const struct option GNU_longOptions
[] =
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
},
108 {"auto", no_argument
, NULL
, OP_AUTO_ARG
},
113 recutl_print_help (void)
115 /* TRANSLATORS: --help output, recfix synopsis.
118 Usage: recfix [OPTION]... [OPERATION] [OP_OPTION]... [FILE]\n"));
120 /* TRANSLATORS: --help output, recfix short description.
123 Check and fix rec files.\n"),
127 /* TRANSLATORS: --help output, recfix global arguments.
130 --no-external don't use external descriptors.\n\
131 --force force the requested operation.\n"),
134 recutl_print_help_common ();
137 /* TRANSLATORS: --help output, recfix operations.
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"),
146 #if defined REC_CRYPT_SUPPORT
147 /* TRANSLATORS: --help output, recfix operations related with encryption.
150 --encrypt encrypt confidential fields in the specified file.\n\
151 --decrypt decrypt confidential fields in the specified file.\n"),
155 /* TRANSLATORS: --help output, recfix encryption and decryption
159 De/Encryption options:\n\
160 -s, --password=PASSWORD encrypt/decrypt with this password.\n"),
162 #endif /* REC_CRYPT_SUPPORT */
165 /* TRANSLATORS: --help output, notes on recfix.
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
);
172 recutl_print_help_footer ();
176 recfix_parse_args (int argc
,
182 while ((ret
= getopt_long (argc
,
184 ENCRYPTION_SHORT_ARGS
,
192 case NO_EXTERNAL_ARG
:
194 recfix_external
= false;
202 #if defined REC_CRYPT_SUPPORT
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
);
225 #endif /* REC_CRYPT_SUPPORT */
228 if (recfix_op
!= RECFIX_OP_INVALID
)
230 recutl_fatal (_("please specify just one operation.\n"));
233 recfix_op
= RECFIX_OP_CHECK
;
238 if (recfix_op
!= RECFIX_OP_INVALID
)
240 recutl_fatal (_("please specify just one operation.\n"));
243 recfix_op
= RECFIX_OP_SORT
;
248 if (recfix_op
!= RECFIX_OP_INVALID
)
250 recutl_fatal (_("please specify just one operation.\n"));
253 recfix_op
= RECFIX_OP_AUTO
;
256 #if defined REC_CRYPT_SUPPORT
259 if (recfix_op
!= RECFIX_OP_INVALID
)
261 recutl_fatal (_("please specify just one operation.\n"));
264 recfix_op
= RECFIX_OP_ENCRYPT
;
269 if (recfix_op
!= RECFIX_OP_INVALID
)
271 recutl_fatal (_("please specify just one operation.\n"));
274 recfix_op
= RECFIX_OP_DECRYPT
;
277 #endif /* REC_CRYPT_SUPPORT */
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
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);
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. */
325 if ((argc
- optind
) != 1)
327 recutl_print_help ();
331 recfix_file
= argv
[optind
++];
336 recfix_check_database (rec_db_t db
)
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. */
349 fprintf (stderr
, "%s", errors
);
359 /* Read the database from the specified file and check its
362 db
= recutl_read_db_from_file (recfix_file
);
368 if (!recfix_check_database (db
))
381 rec_rset_t rset
= NULL
;
383 /* Read the database from the specified file. */
385 db
= recutl_read_db_from_file (recfix_file
);
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
))
405 if (!recutl_file_is_writable (recfix_file
))
407 recutl_error (_("file %s is not writable.\n"), recfix_file
);
411 recutl_write_db_to_file (db
, recfix_file
);
415 #if defined REC_CRYPT_SUPPORT
423 /* Read the database from the specified file. */
425 db
= recutl_read_db_from_file (recfix_file
);
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
;
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
)
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
460 if (!rec_encrypt_record (rset
, record
, recfix_password
)
463 recutl_error (_("the database contains already encrypted fields\n"));
464 recutl_fatal (_("please use --force or --decrypt\n"));
469 /* Decrypt any encrypted confidential field in this
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
);
486 #endif /* REC_CRYPT_SUPPORT */
494 /* Read the database from the especified file. */
496 db
= recutl_read_db_from_file (recfix_file
);
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
;
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
))
526 recutl_write_db_to_file (db
, recfix_file
);
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
546 case RECFIX_OP_CHECK
:
548 res
= recfix_do_check ();
553 res
= recfix_do_sort ();
558 res
= recfix_do_auto ();
561 #if defined REC_CRYPT_SUPPORT
562 case RECFIX_OP_ENCRYPT
:
563 case RECFIX_OP_DECRYPT
:
565 res
= recfix_do_crypt ();
568 #endif /* REC_CRYPT_SUPPORT */
571 /* This point shall not be reached. */
574 recutl_fatal (_("unknown operation in recfix: please report this as a bug.\n"));
581 /* End of recfix.c */