1 /**
2 * This file is part of the Detox package.
3 *
4 * Copyright (c) Doug Harple <detox.dharple@gmail.com>
5 *
6 * For the full copyright and license information, please view the LICENSE
7 * file that was distributed with this source code.
8 */
9
10 #include "config.h"
11
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <errno.h>
18 #include <unistd.h>
19
20 #include "detox.h"
21 #include "clean_string.h"
22
23 #include "file.h"
24
25 #include "config_file.h"
26 #include "config_file_spoof.h"
27 #include "config_file_dump.h"
28 #include "parse_table.h"
29 #include "parse_options.h"
30
31 #define MAX_PATH_LEN 256
32
main(int argc,char ** argv)33 int main(int argc, char **argv)
34 {
35 struct stat stat_info;
36 int err;
37
38 struct detox_parse_results *parse_results = NULL;
39 struct detox_sequence_list *list_work = NULL;
40 struct detox_sequence_entry *which_sequence = NULL;
41 struct detox_sequence_entry *work = NULL;
42 struct detox_options *main_options;
43
44 char *check_config_file = NULL;
45 char *file_work = NULL;
46 char **file_walk;
47
48 main_options = parse_options_getopt(argc, argv);
49
50 if (main_options == NULL) {
51 fprintf(stderr, "detox: an error occurred while parsing command line arguments\n");
52 exit(EXIT_FAILURE);
53 }
54
55 if (main_options->check_config_file) {
56 check_config_file = strdup(main_options->check_config_file);
57 }
58
59 if (check_config_file != NULL) {
60 parse_results = parse_config_file(check_config_file, NULL, main_options);
61 if (parse_results == NULL) {
62 fprintf(stderr, "detox: unable to open: %s\n", check_config_file);
63 exit(EXIT_FAILURE);
64 }
65 }
66 else {
67 check_config_file = malloc(MAX_PATH_LEN);
68 if (check_config_file == NULL) {
69 fprintf(stderr, "out of memory: %s\n", strerror(errno));
70 exit(EXIT_FAILURE);
71 }
72
73 #ifdef SYSCONFDIR
74 err = snprintf(check_config_file, MAX_PATH_LEN, "%s/detoxrc", SYSCONFDIR);
75 if (err < MAX_PATH_LEN)
76 parse_results = parse_config_file(check_config_file, NULL, main_options);
77 #endif
78
79 if (parse_results == NULL) {
80 parse_results = parse_config_file("/etc/detoxrc", NULL, main_options);
81 }
82
83 if (parse_results == NULL) {
84 parse_results = parse_config_file("/usr/local/etc/detoxrc", NULL, main_options);
85 }
86
87 file_work = getenv("HOME");
88 if (file_work != NULL) {
89 err = snprintf(check_config_file, MAX_PATH_LEN, "%s/.detoxrc", file_work);
90 if (err < MAX_PATH_LEN)
91 parse_results = parse_config_file(check_config_file, parse_results, main_options);
92
93 file_work = NULL;
94 }
95
96 if (parse_results == NULL) {
97 parse_results = spoof_config_file(main_options);
98 }
99
100 free(check_config_file);
101 }
102
103 if (parse_results == NULL) {
104 fprintf(stderr, "detox: no config file to work with\n");
105 exit(EXIT_FAILURE);
106 }
107
108 /*
109 * Store the files_to_ignore array in the main_options struct for use in
110 * parse_dir/file/special
111 */
112
113 main_options->files_to_ignore = parse_results->files_to_ignore;
114
115 /*
116 * Determine which sequence to use
117 */
118
119 which_sequence = NULL;
120
121 list_work = parse_results->sequences;
122
123 while (list_work != NULL) {
124 if (strcmp(list_work->name, (main_options->sequence_name == NULL) ? "default" : main_options->sequence_name) == 0) {
125 which_sequence = list_work->head;
126 break;
127 }
128
129 list_work = list_work->next;
130 }
131
132 /*
133 * If no sequence was found, and the user didn't specify a sequence
134 * to use, just use the first sequence.
135 */
136
137 if (which_sequence == NULL && main_options->sequence_name == NULL) {
138 if (parse_results->sequences != NULL) {
139 which_sequence = parse_results->sequences->head;
140 }
141 }
142
143 main_options->sequence_to_use = which_sequence;
144
145 /*
146 * List sequences
147 */
148 if (main_options->list_sequences) {
149 dump_config_file(parse_results, main_options);
150 exit(EXIT_SUCCESS);
151 }
152
153 /*
154 * Fail if no sequence is available
155 */
156 if (main_options->sequence_to_use == NULL) {
157 /*
158 * XXX - Explain this better
159 */
160 fprintf(stderr, "detox: no sequence to work with\n");
161 exit(EXIT_FAILURE);
162 }
163
164 /*
165 * Check translation tables
166 */
167
168 work = main_options->sequence_to_use;
169 while (work != NULL) {
170 char *check_filename = NULL;
171 int do_search = 0;
172
173 struct translation_table *table = NULL;
174 struct clean_string_options *opts;
175
176 if (work->cleaner == &clean_iso8859_1) {
177 if (work->options != NULL) {
178 opts = work->options;
179 if (opts->filename != NULL) {
180 check_filename = opts->filename;
181 }
182 }
183
184 if (!check_filename) {
185 check_filename = "iso8859_1.tbl";
186 do_search = 1;
187 }
188 }
189 else if (work->cleaner == &clean_utf_8) {
190 if (work->options != NULL) {
191 opts = work->options;
192 if (opts->filename != NULL) {
193 check_filename = opts->filename;
194 }
195 }
196
197 if (!check_filename) {
198 check_filename = "unicode.tbl";
199 do_search = 1;
200 }
201 }
202 else if (work->cleaner == &clean_safe) {
203 if (work->options != NULL) {
204 opts = work->options;
205 if (opts->filename != NULL) {
206 check_filename = opts->filename;
207 }
208 }
209
210 if (!check_filename) {
211 check_filename = "safe.tbl";
212 do_search = 1;
213 }
214 }
215
216 if (check_filename || do_search) {
217
218 table = NULL;
219
220 if (do_search) {
221 check_config_file = malloc(MAX_PATH_LEN);
222 if (check_config_file == NULL) {
223 fprintf(stderr, "out of memory: %s\n", strerror(errno));
224 exit(EXIT_FAILURE);
225 }
226
227 #ifdef DATADIR
228 err = snprintf(check_config_file, MAX_PATH_LEN, "%s/detox/%s", DATADIR, check_filename);
229 if (err < MAX_PATH_LEN)
230 table = parse_table(check_config_file);
231 #endif
232
233 if (table == NULL) {
234 err = snprintf(check_config_file, MAX_PATH_LEN, "/usr/share/detox/%s", check_filename);
235 if (err < MAX_PATH_LEN)
236 table = parse_table(check_config_file);
237 }
238
239 if (table == NULL) {
240 err = snprintf(check_config_file, MAX_PATH_LEN, "/usr/local/share/detox/%s", check_filename);
241 if (err < MAX_PATH_LEN)
242 table = parse_table(check_config_file);
243 }
244
245 if (table == NULL) {
246
247 /*
248 * Fall back to the non-file based
249 * cleaner
250 */
251 if (work->cleaner == &clean_iso8859_1) {
252 work->cleaner = &clean_iso8859_1_basic;
253 }
254 else if (work->cleaner == &clean_utf_8) {
255 work->cleaner = &clean_utf_8_basic;
256 }
257 else if (work->cleaner == &clean_safe) {
258 work->cleaner = &clean_safe_basic;
259 }
260 else {
261 fprintf(stderr, "detox: unable to locate translation table or fall back\n");
262 exit(EXIT_FAILURE);
263 }
264 }
265 else {
266
267 /*
268 * Allocate an options
269 */
270 opts = malloc(sizeof(struct clean_string_options));
271 if (opts == NULL) {
272 fprintf(stderr, "out of memory: %s\n", strerror(errno));
273 exit(EXIT_FAILURE);
274 }
275 memset(opts, 0, sizeof(struct clean_string_options));
276
277 opts->translation_table = table;
278 work->options = opts;
279 }
280
281 free(check_config_file);
282 }
283 else {
284 table = parse_table(check_filename);
285 if (table == NULL) {
286 fprintf(stderr, "detox: unable to parse file: %s\n", check_filename);
287 exit(EXIT_FAILURE);
288 }
289
290 opts = work->options;
291 opts->translation_table = table;
292 }
293 }
294
295
296 work = work->next;
297 }
298
299 /*
300 * Do some actual work
301 */
302
303 if (!main_options->is_inline_mode) {
304 file_walk = main_options->files;
305 while (*file_walk) {
306 if (main_options->verbose) {
307 printf("Scanning: %s\n", *file_walk);
308 }
309
310 err = lstat(*file_walk, &stat_info);
311 if (err == -1) {
312 fprintf(stderr, "%s: %s\n", *file_walk, strerror(errno));
313 }
314 else {
315 if (S_ISDIR(stat_info.st_mode)) {
316 file_work = parse_file(*file_walk, main_options);
317 parse_dir(file_work, main_options);
318 free(file_work);
319 }
320 else if (S_ISREG(stat_info.st_mode)) {
321 parse_file(*file_walk, main_options);
322 }
323 else if (main_options->special) {
324 parse_special(*file_walk, main_options);
325 }
326 }
327
328 file_walk++;
329 }
330 } else {
331 if (main_options->files[0] != NULL) {
332 file_walk = main_options->files;
333 while (*file_walk) {
334 err = lstat(*file_walk, &stat_info);
335 if (err == -1) {
336 fprintf(stderr, "%s: %s\n", *file_walk, strerror(errno));
337 }
338 else {
339 if (S_ISDIR(stat_info.st_mode)) {
340 fprintf(stderr, "%s: is a directory\n", *file_walk);
341 }
342 else {
343 parse_inline(*file_walk, main_options);
344 }
345 }
346
347 file_walk++;
348 }
349 }
350 else {
351 parse_inline(NULL, main_options);
352 }
353 }
354
355 return 0;
356 }
357