Imported Upstream version 2.5.1
[debian/amanda] / client-src / client_util.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1991-1998 University of Maryland at College Park
4  * All Rights Reserved.
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation, and that the name of U.M. not be used in advertising or
11  * publicity pertaining to distribution of the software without specific,
12  * written prior permission.  U.M. makes no representations about the
13  * suitability of this software for any purpose.  It is provided "as is"
14  * without express or implied warranty.
15  *
16  * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  * Authors: the Amanda Development Team.  Its members are listed in a
24  * file named AUTHORS, in the root directory of this distribution.
25  */
26 /* 
27  * $Id: client_util.c,v 1.34 2006/05/25 01:47:11 johnfranks Exp $
28  *
29  */
30
31 #include "amanda.h"
32 #include "client_util.h"
33 #include "getfsent.h"
34 #include "util.h"
35
36 #define MAXMAXDUMPS 16
37
38 static int add_exclude(FILE *file_exclude, char *aexc, int verbose);
39 static int add_include(char *disk, char *device, FILE *file_include, char *ainc, int verbose);
40 static char *build_name(char *disk, char *exin, int verbose);
41 static char *get_name(char *diskname, char *exin, time_t t, int n);
42
43
44 char *
45 fixup_relative(
46     char *      name,
47     char *      device)
48 {
49     char *newname;
50     if(*name != '/') {
51         char *dirname = amname_to_dirname(device);
52         newname = vstralloc(dirname, "/", name , NULL);
53         amfree(dirname);
54     }
55     else {
56         newname = stralloc(name);
57     }
58     return newname;
59 }
60
61
62 static char *
63 get_name(
64     char *      diskname,
65     char *      exin,
66     time_t      t,
67     int         n)
68 {
69     char number[NUM_STR_SIZE];
70     char *filename;
71     char *ts;
72
73     ts = construct_timestamp(&t);
74     if(n == 0)
75         number[0] = '\0';
76     else
77         snprintf(number, SIZEOF(number), "%03d", n - 1);
78         
79     filename = vstralloc(get_pname(), ".", diskname, ".", ts, number, ".",
80                          exin, NULL);
81     amfree(ts);
82     return filename;
83 }
84
85
86 static char *
87 build_name(
88     char *      disk,
89     char *      exin,
90     int         verbose)
91 {
92     int n;
93     int fd;
94     char *filename = NULL;
95     char *afilename = NULL;
96     char *diskname;
97     time_t curtime;
98     char *dbgdir;
99     char *e = NULL;
100     DIR *d;
101     struct dirent *entry;
102     char *test_name;
103     size_t match_len, d_name_len;
104     char *quoted;
105
106     time(&curtime);
107     diskname = sanitise_filename(disk);
108
109     dbgdir = stralloc2(AMANDA_TMPDIR, "/");
110     if((d = opendir(AMANDA_TMPDIR)) == NULL) {
111         error("open debug directory \"%s\": %s",
112                 AMANDA_TMPDIR, strerror(errno));
113         /*NOTREACHED*/
114     }
115     test_name = get_name(diskname, exin,
116                          curtime - (AMANDA_DEBUG_DAYS * 24 * 60 * 60), 0);
117     match_len = strlen(get_pname()) + strlen(diskname) + 2;
118     while((entry = readdir(d)) != NULL) {
119         if(is_dot_or_dotdot(entry->d_name)) {
120             continue;
121         }
122         d_name_len = strlen(entry->d_name);
123         if(strncmp(test_name, entry->d_name, match_len) != 0
124            || d_name_len < match_len + 14 + 8
125            || strcmp(entry->d_name+ d_name_len - 7, exin) != 0) {
126             continue;                           /* not one of our files */
127         }
128         if(strcmp(entry->d_name, test_name) < 0) {
129             e = newvstralloc(e, dbgdir, entry->d_name, NULL);
130             (void) unlink(e);                   /* get rid of old file */
131         }
132     }
133     amfree(test_name);
134     amfree(e);
135     closedir(d);
136
137     n=0;
138     do {
139         filename = get_name(diskname, exin, curtime, n);
140         afilename = newvstralloc(afilename, dbgdir, filename, NULL);
141         if((fd=open(afilename, O_WRONLY|O_CREAT|O_APPEND, 0600)) < 0){
142             amfree(afilename);
143             n++;
144         }
145         else {
146             close(fd);
147         }
148         amfree(filename);
149     } while(!afilename && n < 1000);
150
151     if(afilename == NULL) {
152         filename = get_name(diskname, exin, curtime, 0);
153         afilename = newvstralloc(afilename, dbgdir, filename, NULL);
154         quoted = quote_string(afilename);
155         dbprintf(("%s: Cannot create %s (%s)\n",
156                         debug_prefix(NULL), quoted, strerror(errno)));
157         if(verbose) {
158             printf("ERROR [cannot create %s (%s)]\n",
159                         quoted, strerror(errno));
160         }
161         amfree(quoted);
162         amfree(afilename);
163         amfree(filename);
164     }
165
166     amfree(dbgdir);
167     amfree(diskname);
168
169     return afilename;
170 }
171
172
173 static int
174 add_exclude(
175     FILE *      file_exclude,
176     char *      aexc,
177     int         verbose)
178 {
179     size_t l;
180     char *quoted, *file;
181
182     (void)verbose;      /* Quiet unused parameter warning */
183
184     l = strlen(aexc);
185     if(aexc[l-1] == '\n') {
186         aexc[l-1] = '\0';
187         l--;
188     }
189     file = quoted = quote_string(aexc);
190     if (*file == '"') {
191         file[strlen(file) - 1] = '\0';
192         file++;
193     }
194     fprintf(file_exclude, "%s\n", file);
195     amfree(quoted);
196     return 1;
197 }
198
199 static int
200 add_include(
201     char *      disk,
202     char *      device,
203     FILE *      file_include,
204     char *      ainc,
205     int         verbose)
206 {
207     size_t l;
208     int nb_exp=0;
209     char *quoted, *file;
210
211     (void)disk; /* Quiet unused parameter warning */
212
213     l = strlen(ainc);
214     if(ainc[l-1] == '\n') {
215         ainc[l-1] = '\0';
216         l--;
217     }
218     if (strncmp(ainc, "./", 2) != 0) {
219         quoted = quote_string(ainc);
220         dbprintf(("%s: include must start with './' (%s)\n",
221                   debug_prefix(NULL), quoted));
222         if(verbose) {
223             printf("ERROR [include must start with './' (%s)]\n", quoted);
224         }
225         amfree(quoted);
226     }
227     else {
228         char *incname = ainc+2;
229
230         if(strchr(incname, '/')) {
231             file = quoted = quote_string(ainc);
232             if (*file == '"') {
233                 file[strlen(file) - 1] = '\0';
234                 file++;
235             }
236             fprintf(file_include, "%s\n", file);
237             amfree(quoted);
238             nb_exp++;
239         }
240         else {
241             char *regex;
242             DIR *d;
243             struct dirent *entry;
244
245             regex = glob_to_regex(incname);
246             if((d = opendir(device)) == NULL) {
247                 quoted = quote_string(device);
248                 dbprintf(("%s: Can't open disk %s\n",
249                       debug_prefix(NULL), quoted));
250                 if(verbose) {
251                     printf("ERROR [Can't open disk %s]\n", quoted);
252                 }
253                 amfree(quoted);
254             }
255             else {
256                 while((entry = readdir(d)) != NULL) {
257                     if(is_dot_or_dotdot(entry->d_name)) {
258                         continue;
259                     }
260                     if(match(regex, entry->d_name)) {
261                         incname = vstralloc("./", entry->d_name, NULL);
262                         file = quoted = quote_string(incname);
263                         if (*file == '"') {
264                             file[strlen(file) - 1] = '\0';
265                             file++;
266                         }
267                         fprintf(file_include, "%s\n", file);
268                         amfree(quoted);
269                         amfree(incname);
270                         nb_exp++;
271                     }
272                 }
273                 closedir(d);
274             }
275             amfree(regex);
276         }
277     }
278     return nb_exp;
279 }
280
281 char *
282 build_exclude(
283     char *      disk,
284     char *      device,
285     option_t *  options,
286     int         verbose)
287 {
288     char *filename;
289     FILE *file_exclude;
290     FILE *exclude;
291     char *aexc;
292     sle_t *excl;
293     int nb_exclude = 0;
294     char *quoted;
295
296     if(options->exclude_file) nb_exclude += options->exclude_file->nb_element;
297     if(options->exclude_list) nb_exclude += options->exclude_list->nb_element;
298
299     if(nb_exclude == 0) return NULL;
300
301     if((filename = build_name(disk, "exclude", verbose)) != NULL) {
302         if((file_exclude = fopen(filename,"w")) != NULL) {
303
304             if(options->exclude_file) {
305                 for(excl = options->exclude_file->first; excl != NULL;
306                     excl = excl->next) {
307                     add_exclude(file_exclude, excl->name,
308                                 verbose && options->exclude_optional == 0);
309                 }
310             }
311
312             if(options->exclude_list) {
313                 for(excl = options->exclude_list->first; excl != NULL;
314                     excl = excl->next) {
315                     char *exclname = fixup_relative(excl->name, device);
316                     if((exclude = fopen(exclname, "r")) != NULL) {
317                         while ((aexc = agets(exclude)) != NULL) {
318                             if (aexc[0] == '\0') {
319                                 amfree(aexc);
320                                 continue;
321                             }
322                             add_exclude(file_exclude, aexc,
323                                         verbose && options->exclude_optional == 0);
324                             amfree(aexc);
325                         }
326                         fclose(exclude);
327                     }
328                     else {
329                         quoted = quote_string(exclname);
330                         dbprintf(("%s: Can't open exclude file %s (%s)\n",
331                                   debug_prefix(NULL),
332                                   quoted, strerror(errno)));
333                         if(verbose && (options->exclude_optional == 0 ||
334                                        errno != ENOENT)) {
335                             printf("ERROR [Can't open exclude file %s (%s)]\n",
336                                    quoted, strerror(errno));
337                         }
338                         amfree(quoted);
339                     }
340                     amfree(exclname);
341                 }
342             }
343             fclose(file_exclude);
344         }
345         else {
346             quoted = quote_string(filename);
347             dbprintf(("%s: Can't create exclude file %s (%s)\n",
348                       debug_prefix(NULL),
349                       quoted, strerror(errno)));
350             if(verbose) {
351                 printf("ERROR [Can't create exclude file %s (%s)]\n",
352                         quoted, strerror(errno));
353             }
354             amfree(quoted);
355         }
356     }
357
358     return filename;
359 }
360
361 char *
362 build_include(
363     char *      disk,
364     char *      device,
365     option_t *  options,
366     int         verbose)
367 {
368     char *filename;
369     FILE *file_include;
370     FILE *include;
371     char *ainc = NULL;
372     sle_t *incl;
373     int nb_include = 0;
374     int nb_exp = 0;
375     char *quoted;
376
377     if(options->include_file) nb_include += options->include_file->nb_element;
378     if(options->include_list) nb_include += options->include_list->nb_element;
379
380     if(nb_include == 0) return NULL;
381
382     if((filename = build_name(disk, "include", verbose)) != NULL) {
383         if((file_include = fopen(filename,"w")) != NULL) {
384
385             if(options->include_file) {
386                 for(incl = options->include_file->first; incl != NULL;
387                     incl = incl->next) {
388                     nb_exp += add_include(disk, device, file_include,
389                                   incl->name,
390                                   verbose && options->include_optional == 0);
391                 }
392             }
393
394             if(options->include_list) {
395                 for(incl = options->include_list->first; incl != NULL;
396                     incl = incl->next) {
397                     char *inclname = fixup_relative(incl->name, device);
398                     if((include = fopen(inclname, "r")) != NULL) {
399                         while ((ainc = agets(include)) != NULL) {
400                             if (ainc[0] == '\0') {
401                                 amfree(ainc);
402                                 continue;
403                             }
404                             nb_exp += add_include(disk, device,
405                                                   file_include, ainc,
406                                                   verbose && options->include_optional == 0);
407                             amfree(ainc);
408                         }
409                         fclose(include);
410                     }
411                     else {
412                         quoted = quote_string(inclname);
413                         dbprintf(("%s: Can't open include file %s (%s)\n",
414                                   debug_prefix(NULL), quoted, strerror(errno)));
415                         if(verbose && (options->include_optional == 0 ||
416                                        errno != ENOENT)) {
417                             printf("ERROR [Can't open include file %s (%s)]\n",
418                                    quoted, strerror(errno));
419                         }
420                         amfree(quoted);
421                    }
422                    amfree(inclname);
423                 }
424             }
425             fclose(file_include);
426         }
427         else {
428             quoted = quote_string(filename);
429             dbprintf(("%s: Can't create include file %s (%s)\n",
430                       debug_prefix(NULL), quoted, strerror(errno)));
431             if(verbose) {
432                 printf("ERROR [Can't create include file %s (%s)]\n",
433                         quoted, strerror(errno));
434             }
435             amfree(quoted);
436         }
437     }
438         
439     if(nb_exp == 0) {
440         quoted = quote_string(disk);
441         dbprintf(("%s: No include for %s\n", debug_prefix(NULL), quoted));
442         if(verbose && options->include_optional == 0) {
443             printf("ERROR [No include for %s]\n", quoted);
444         }
445         amfree(quoted);
446     }
447
448     return filename;
449 }
450
451
452 void
453 init_options(
454     option_t *options)
455 {
456     options->str = NULL;
457     options->compress = NO_COMPR;
458     options->srvcompprog = NULL;
459     options->clntcompprog = NULL;
460     options->encrypt = ENCRYPT_NONE;
461     options->srv_encrypt = NULL;
462     options->clnt_encrypt = NULL;
463     options->srv_decrypt_opt = NULL;
464     options->clnt_decrypt_opt = NULL;
465     options->no_record = 0;
466     options->createindex = 0;
467     options->auth = NULL;
468     options->exclude_file = NULL;
469     options->exclude_list = NULL;
470     options->include_file = NULL;
471     options->include_list = NULL;
472     options->exclude_optional = 0;
473     options->include_optional = 0;
474 }
475
476
477 option_t *
478 parse_options(
479     char *str,
480     char *disk,
481     char *device,
482     am_feature_t *fs,
483     int verbose)
484 {
485     char *exc;
486     char *inc;
487     option_t *options;
488     char *p, *tok;
489     char *quoted;
490
491     (void)disk;         /* Quiet unused parameter warning */
492     (void)device;       /* Quiet unused parameter warning */
493
494     options = alloc(SIZEOF(option_t));
495     init_options(options);
496     options->str = stralloc(str);
497
498     p = stralloc(str);
499     tok = strtok(p,";");
500
501     while (tok != NULL) {
502         if(am_has_feature(fs, fe_options_auth)
503            && BSTRNCMP(tok,"auth=") == 0) {
504             if(options->auth != NULL) {
505                 quoted = quote_string(tok + 5);
506                 dbprintf(("%s: multiple auth option %s\n",
507                           debug_prefix(NULL), quoted));
508                 if(verbose) {
509                     printf("ERROR [multiple auth option %s]\n", quoted);
510                 }
511                 amfree(quoted);
512             }
513             options->auth = stralloc(&tok[5]);
514         }
515         else if(am_has_feature(fs, fe_options_bsd_auth)
516            && BSTRNCMP(tok, "bsd-auth") == 0) {
517             if(options->auth != NULL) {
518                 dbprintf(("%s: multiple auth option\n",
519                           debug_prefix(NULL)));
520                 if(verbose) {
521                     printf("ERROR [multiple auth option]\n");
522                 }
523             }
524             options->auth = stralloc("bsd");
525         }
526         else if(am_has_feature(fs, fe_options_krb4_auth)
527            && BSTRNCMP(tok, "krb4-auth") == 0) {
528             if(options->auth != NULL) {
529                 dbprintf(("%s: multiple auth option\n",
530                           debug_prefix(NULL)));
531                 if(verbose) {
532                     printf("ERROR [multiple auth option]\n");
533                 }
534             }
535             options->auth = stralloc("krb4");
536         }
537         else if(BSTRNCMP(tok, "compress-fast") == 0) {
538             if(options->compress != NO_COMPR) {
539                 dbprintf(("%s: multiple compress option\n",
540                           debug_prefix(NULL)));
541                 if(verbose) {
542                     printf("ERROR [multiple compress option]\n");
543                 }
544             }
545             options->compress = COMPR_FAST;
546         }
547         else if(BSTRNCMP(tok, "compress-best") == 0) {
548             if(options->compress != NO_COMPR) {
549                 dbprintf(("%s: multiple compress option\n",
550                           debug_prefix(NULL)));
551                 if(verbose) {
552                     printf("ERROR [multiple compress option]\n");
553                 }
554             }
555             options->compress = COMPR_BEST;
556         }
557         else if(BSTRNCMP(tok, "srvcomp-fast") == 0) {
558             if(options->compress != NO_COMPR) {
559                 dbprintf(("%s: multiple compress option\n",
560                           debug_prefix(NULL)));
561                 if(verbose) {
562                     printf("ERROR [multiple compress option]\n");
563                 }
564             }
565             options->compress = COMPR_SERVER_FAST;
566         }
567         else if(BSTRNCMP(tok, "srvcomp-best") == 0) {
568             if(options->compress != NO_COMPR) {
569                 dbprintf(("%s: multiple compress option\n",
570                           debug_prefix(NULL)));
571                 if(verbose) {
572                     printf("ERROR [multiple compress option]\n");
573                 }
574             }
575             options->compress = COMPR_SERVER_BEST;
576         }
577         else if(BSTRNCMP(tok, "srvcomp-cust=") == 0) {
578             if(options->compress != NO_COMPR) {
579                 dbprintf(("%s: multiple compress option\n", 
580                           debug_prefix(NULL)));
581                 if(verbose) {
582                     printf("ERROR [multiple compress option]\n");
583                 }
584             }
585             options->srvcompprog = stralloc(tok + SIZEOF("srvcomp-cust=") -1);
586             options->compress = COMPR_SERVER_CUST;
587         }
588         else if(BSTRNCMP(tok, "comp-cust=") == 0) {
589             if(options->compress != NO_COMPR) {
590                 dbprintf(("%s: multiple compress option\n", 
591                           debug_prefix(NULL)));
592                 if(verbose) {
593                     printf("ERROR [multiple compress option]\n");
594                 }
595             }
596             options->clntcompprog = stralloc(tok + SIZEOF("comp-cust=") -1);
597             options->compress = COMPR_CUST;
598             /* parse encryption options */
599         } 
600         else if(BSTRNCMP(tok, "encrypt-serv-cust=") == 0) {
601             if(options->encrypt != ENCRYPT_NONE) {
602                 dbprintf(("%s: multiple encrypt option\n", 
603                           debug_prefix(NULL)));
604                 if(verbose) {
605                     printf("ERROR [multiple encrypt option]\n");
606                 }
607             }
608             options->srv_encrypt = stralloc(tok + SIZEOF("encrypt-serv-cust=") -1);
609             options->encrypt = ENCRYPT_SERV_CUST;
610         } 
611         else if(BSTRNCMP(tok, "encrypt-cust=") == 0) {
612             if(options->encrypt != ENCRYPT_NONE) {
613                 dbprintf(("%s: multiple encrypt option\n", 
614                           debug_prefix(NULL)));
615                 if(verbose) {
616                     printf("ERROR [multiple encrypt option]\n");
617                 }
618             }
619             options->clnt_encrypt= stralloc(tok + SIZEOF("encrypt-cust=") -1);
620             options->encrypt = ENCRYPT_CUST;
621         } 
622         else if(BSTRNCMP(tok, "server-decrypt-option=") == 0) {
623           options->srv_decrypt_opt = stralloc(tok + SIZEOF("server-decrypt-option=") -1);
624         }
625         else if(BSTRNCMP(tok, "client-decrypt-option=") == 0) {
626           options->clnt_decrypt_opt = stralloc(tok + SIZEOF("client-decrypt-option=") -1);
627         }
628         else if(BSTRNCMP(tok, "no-record") == 0) {
629             if(options->no_record != 0) {
630                 dbprintf(("%s: multiple no-record option\n",
631                           debug_prefix(NULL)));
632                 if(verbose) {
633                     printf("ERROR [multiple no-record option]\n");
634                 }
635             }
636             options->no_record = 1;
637         }
638         else if(BSTRNCMP(tok, "index") == 0) {
639             if(options->createindex != 0) {
640                 dbprintf(("%s: multiple index option\n",
641                           debug_prefix(NULL)));
642                 if(verbose) {
643                     printf("ERROR [multiple index option]\n");
644                 }
645             }
646             options->createindex = 1;
647         }
648         else if(BSTRNCMP(tok, "exclude-optional") == 0) {
649             if(options->exclude_optional != 0) {
650                 dbprintf(("%s: multiple exclude-optional option\n",
651                           debug_prefix(NULL)));
652                 if(verbose) {
653                     printf("ERROR [multiple exclude-optional option]\n");
654                 }
655             }
656             options->exclude_optional = 1;
657         }
658         else if(strcmp(tok, "include-optional") == 0) {
659             if(options->include_optional != 0) {
660                 dbprintf(("%s: multiple include-optional option\n",
661                           debug_prefix(NULL)));
662                 if(verbose) {
663                     printf("ERROR [multiple include-optional option]\n");
664                 }
665             }
666             options->include_optional = 1;
667         }
668         else if(BSTRNCMP(tok,"exclude-file=") == 0) {
669             exc = unquote_string(&tok[13]);
670             options->exclude_file = append_sl(options->exclude_file, exc);
671             amfree(exc);
672         }
673         else if(BSTRNCMP(tok,"exclude-list=") == 0) {
674             exc = unquote_string(&tok[13]);
675             options->exclude_list = append_sl(options->exclude_list, exc);
676             amfree(exc);
677         }
678         else if(BSTRNCMP(tok,"include-file=") == 0) {
679             inc = unquote_string(&tok[13]);
680             options->include_file = append_sl(options->include_file, inc);
681             amfree(inc);
682         }
683         else if(BSTRNCMP(tok,"include-list=") == 0) {
684             inc = unquote_string(&tok[13]);
685             options->include_list = append_sl(options->include_list, inc);
686             amfree(inc);
687         }
688         else if(strcmp(tok,"|") != 0) {
689             quoted = quote_string(tok);
690             dbprintf(("%s: unknown option %s\n",
691                         debug_prefix(NULL), quoted));
692             if(verbose) {
693                 printf("ERROR [unknown option: %s]\n", quoted);
694             }
695             amfree(quoted);
696         }
697         tok = strtok(NULL, ";");
698     }
699     amfree(p);
700     return options;
701 }