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