5364ae4181204a94483662f893d6d224bc0e79a7
[debian/amanda] / common-src / amfeatures.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 /*
28  * $Id: amfeatures.c,v 1.24 2006/07/19 17:46:07 martinea Exp $
29  *
30  * Feature test related code.
31  */
32
33 #include "amanda.h"
34 #include "amfeatures.h"
35
36 /*
37  *=====================================================================
38  * Initialize the base feature set for this version of Amanda.
39  *
40  * am_feature_t *am_init_feature_set()
41  *
42  * entry:       none
43  * exit:        dynamically allocated feature set structure
44  *=====================================================================
45  */
46
47 am_feature_t *
48 am_init_feature_set(void)
49 {
50     am_feature_t                *f;
51
52     if ((f = am_allocate_feature_set()) != NULL) {
53         /*
54          * Whenever a new feature is added, a new line usually needs
55          * to be added here to show that we support it.
56          */
57         am_add_feature(f, have_feature_support);
58         am_add_feature(f, fe_options_auth);
59
60         am_add_feature(f, fe_selfcheck_req);
61         am_add_feature(f, fe_selfcheck_req_device);
62         am_add_feature(f, fe_selfcheck_rep);
63         am_add_feature(f, fe_sendsize_req_no_options);
64         am_add_feature(f, fe_sendsize_req_options);
65         am_add_feature(f, fe_sendsize_req_device);
66         am_add_feature(f, fe_sendsize_rep);
67         am_add_feature(f, fe_sendbackup_req);
68         am_add_feature(f, fe_sendbackup_req_device);
69         am_add_feature(f, fe_sendbackup_rep);
70         am_add_feature(f, fe_noop_req);
71         am_add_feature(f, fe_noop_rep);
72
73         am_add_feature(f, fe_program_dump);
74         am_add_feature(f, fe_program_gnutar);
75         am_add_feature(f, fe_program_application_api);
76
77         am_add_feature(f, fe_options_compress_fast);
78         am_add_feature(f, fe_options_compress_best);
79         am_add_feature(f, fe_options_srvcomp_fast);
80         am_add_feature(f, fe_options_srvcomp_best);
81         am_add_feature(f, fe_options_no_record);
82         am_add_feature(f, fe_options_bsd_auth);
83         am_add_feature(f, fe_options_index);
84         am_add_feature(f, fe_options_exclude_file);
85         am_add_feature(f, fe_options_exclude_list);
86         am_add_feature(f, fe_options_multiple_exclude);
87         am_add_feature(f, fe_options_optional_exclude);
88         am_add_feature(f, fe_options_include_file);
89         am_add_feature(f, fe_options_include_list);
90         am_add_feature(f, fe_options_multiple_include);
91         am_add_feature(f, fe_options_optional_include);
92         am_add_feature(f, fe_options_krb4_auth);
93         am_add_feature(f, fe_options_kencrypt);
94
95         am_add_feature(f, fe_req_options_maxdumps);
96         am_add_feature(f, fe_req_options_hostname);
97         am_add_feature(f, fe_req_options_features);
98
99         am_add_feature(f, fe_rep_options_features);
100
101         am_add_feature(f, fe_amindexd_fileno_in_OLSD);
102         am_add_feature(f, fe_amindexd_fileno_in_ORLD);
103         am_add_feature(f, fe_amidxtaped_fsf);
104         am_add_feature(f, fe_amidxtaped_label);
105         am_add_feature(f, fe_amidxtaped_device);
106         am_add_feature(f, fe_amidxtaped_host);
107         am_add_feature(f, fe_amidxtaped_disk);
108         am_add_feature(f, fe_amidxtaped_datestamp);
109         am_add_feature(f, fe_amidxtaped_header);
110         am_add_feature(f, fe_amidxtaped_nargs);
111         am_add_feature(f, fe_amidxtaped_config);
112
113         am_add_feature(f, fe_recover_splits);
114         am_add_feature(f, fe_amidxtaped_exchange_features);
115         am_add_feature(f, fe_partial_estimate);
116         am_add_feature(f, fe_calcsize_estimate);
117         am_add_feature(f, fe_selfcheck_calcsize);
118         am_add_feature(f, fe_options_compress_cust);
119         am_add_feature(f, fe_options_srvcomp_cust);
120         am_add_feature(f, fe_options_encrypt_cust);
121         am_add_feature(f, fe_options_encrypt_serv_cust);
122         am_add_feature(f, fe_options_client_decrypt_option);
123         am_add_feature(f, fe_options_server_decrypt_option);
124
125         am_add_feature(f, fe_amindexd_marshall_in_OLSD);
126         am_add_feature(f, fe_amindexd_marshall_in_ORLD);
127         am_add_feature(f, fe_amindexd_marshall_in_DHST);
128
129         am_add_feature(f, fe_amrecover_FEEDME);
130         am_add_feature(f, fe_amrecover_timestamp);
131
132         am_add_feature(f, fe_interface_quoted_text);
133
134         am_add_feature(f, fe_program_star);
135
136         am_add_feature(f, fe_amindexd_options_hostname);
137         am_add_feature(f, fe_amindexd_options_features);
138         am_add_feature(f, fe_amindexd_options_auth);
139
140         am_add_feature(f, fe_amidxtaped_options_hostname);
141         am_add_feature(f, fe_amidxtaped_options_features);
142         am_add_feature(f, fe_amidxtaped_options_auth);
143
144         am_add_feature(f, fe_amrecover_message);
145         am_add_feature(f, fe_amrecover_feedme_tape);
146
147         am_add_feature(f, fe_req_options_config);
148
149         am_add_feature(f, fe_rep_sendsize_quoted_error);
150         am_add_feature(f, fe_req_xml);
151         am_add_feature(f, fe_pp_script);
152         am_add_feature(f, fe_amindexd_DLE);
153         am_add_feature(f, fe_amrecover_dle_in_header);
154         am_add_feature(f, fe_xml_estimate);
155         am_add_feature(f, fe_xml_property_priority);
156         am_add_feature(f, fe_sendsize_rep_warning);
157     }
158     return f;
159 }
160
161 /*
162  *=====================================================================
163  * Set a default feature set for client that doesn't have noop service.
164  * This is all the features available in 2.4.2p2.
165  *
166  * entry:       none
167  * exit: dynamically allocated feature set
168  *=====================================================================
169  */
170  
171 am_feature_t *
172 am_set_default_feature_set(void)
173 {
174     am_feature_t                *f;
175
176     if ((f = am_allocate_feature_set()) != NULL) {
177
178         am_add_feature(f, fe_selfcheck_req);
179         am_add_feature(f, fe_selfcheck_rep);
180         am_add_feature(f, fe_sendsize_req_no_options);
181         am_add_feature(f, fe_sendsize_rep);
182         am_add_feature(f, fe_sendbackup_req);
183         am_add_feature(f, fe_sendbackup_rep);
184
185         am_add_feature(f, fe_program_dump);
186         am_add_feature(f, fe_program_gnutar);
187
188         am_add_feature(f, fe_options_compress_fast);
189         am_add_feature(f, fe_options_compress_best);
190         am_add_feature(f, fe_options_srvcomp_fast);
191         am_add_feature(f, fe_options_srvcomp_best);
192         am_add_feature(f, fe_options_no_record);
193         am_add_feature(f, fe_options_bsd_auth);
194         am_add_feature(f, fe_options_index);
195         am_add_feature(f, fe_options_exclude_file);
196         am_add_feature(f, fe_options_exclude_list);
197         am_add_feature(f, fe_options_krb4_auth);
198         am_add_feature(f, fe_options_kencrypt);
199
200         am_add_feature(f, fe_req_options_maxdumps);
201         am_add_feature(f, fe_req_options_hostname);
202         am_add_feature(f, fe_req_options_features);
203
204         am_add_feature(f, fe_rep_options_sendbackup_options);
205     }
206     return f;
207 }
208
209 /*
210  *=====================================================================
211  * Allocate space for a feature set.
212  *
213  * am_feature_t *am_allocate_feature_set()
214  *
215  * entry:       none
216  * exit:        dynamically allocated feature set structure
217  *=====================================================================
218  */
219
220 am_feature_t *
221 am_allocate_feature_set(void)
222 {
223     size_t                      nbytes;
224     am_feature_t                *result;
225
226     result = (am_feature_t *)alloc(SIZEOF(*result));
227     memset(result, 0, SIZEOF(*result));
228     nbytes = (((size_t)last_feature) + 8) >> 3;
229     result->size = nbytes;
230     result->bytes = (unsigned char *)alloc(nbytes);
231     memset(result->bytes, 0, nbytes);
232     return result;
233 }
234
235 /*
236  *=====================================================================
237  * Release space allocated to a feature set.
238  *
239  * void am_release_feature_set(am_feature_t *f)
240  *
241  * entry:       f = feature set to release
242  * exit:        none
243  *=====================================================================
244  */
245
246 void
247 am_release_feature_set(
248     am_feature_t        *f)
249 {
250     if (f != NULL) {
251         amfree(f->bytes);
252         f->size = 0;
253     }
254     amfree(f);
255 }
256
257 /*
258  *=====================================================================
259  * Add a feature to a feature set.
260  *
261  * int am_add_feature(am_feature_t *f, am_feature_e n)
262  *
263  * entry:       f = feature set to add to
264  *              n = feature to add
265  * exit:        non-zero if feature added, else zero (e.g. if the feature
266  *              is beyond what is currently supported)
267  *=====================================================================
268  */
269
270 int
271 am_add_feature(
272     am_feature_t        *f,
273     am_feature_e        n)
274 {
275     size_t                      byte;
276     int                         bit;
277     int                         result = 0;
278
279     if (f != NULL && (int)n >= 0) {
280         byte = ((size_t)n) >> 3;
281         if (byte < f->size) {
282             bit = ((int)n) & 0x7;
283             f->bytes[byte] = (unsigned char)((int)f->bytes[byte] | (unsigned char)(1 << bit));
284             result = 1;
285         }
286     }
287     return result;
288 }
289
290 /*
291  *=====================================================================
292  * Remove a feature from a feature set.
293  *
294  * int am_remove_feature(am_feature_t *f, am_feature_e n)
295  *
296  * entry:       f = feature set to remove from
297  *              n = feature to remove
298  * exit:        non-zero if feature removed, else zero (e.g. if the feature
299  *              is beyond what is currently supported)
300  *=====================================================================
301  */
302
303 int
304 am_remove_feature(
305     am_feature_t        *f,
306     am_feature_e        n)
307 {
308     size_t                      byte;
309     int                         bit;
310     int                         result = 0;
311
312     if (f != NULL && (int)n >= 0) {
313         byte = ((size_t)n) >> 3;
314         if (byte < f->size) {
315             bit = ((int)n) & 0x7;
316             f->bytes[byte] = (unsigned char)((int)f->bytes[byte] & (unsigned char)~(1 << bit));
317             result = 1;
318         }
319     }
320     return result;
321 }
322
323 /*
324  *=====================================================================
325  * Return true if a given feature is available.
326  *
327  * int am_has_feature(am_feature_t *f, am_feature_e n)
328  *
329  * entry:       f = feature set to test
330  *              n = feature to test
331  * exit:        non-zero if feature is enabled
332  *=====================================================================
333  */
334
335 int
336 am_has_feature(
337     am_feature_t        *f,
338     am_feature_e        n)
339 {
340     size_t                      byte;
341     int                         bit;
342     int                         result = 0;
343
344     if (f != NULL && (int)n >= 0) {
345         byte = ((size_t)n) >> 3;
346         if (byte < f->size) {
347             bit = ((int)n) & 0x7;
348             result = ((f->bytes[byte] & (1 << bit)) != 0);
349         }
350     }
351     return result;
352 }
353
354 /*
355  *=====================================================================
356  * Convert a feature set to string.
357  *
358  * char *am_feature_to_string(am_feature_t *f)
359  *
360  * entry:       f = feature set to convet
361  * exit:        dynamically allocated string
362  *=====================================================================
363  */
364
365 char *
366 am_feature_to_string(
367     am_feature_t        *f)
368 {
369     char                        *result;
370     size_t                      i;
371
372     if (f == NULL) {
373         result = stralloc(_("UNKNOWNFEATURE"));
374     } else {
375         result = alloc((f->size * 2) + 1);
376         for (i = 0; i < f->size; i++) {
377             g_snprintf(result + (i * 2), 2 + 1, "%02x", f->bytes[i]);
378         }
379         result[i * 2] = '\0';
380     }
381     return result;
382 }
383
384 /*
385  *=====================================================================
386  * Convert a sting back to a feature set.
387  *
388  * am_feature_t *am_string_to_feature(char *s)
389  *
390  * entry:       s = string to convert
391  * exit:        dynamically allocated feature set
392  *
393  * Note: if the string is longer than the list of features we support,
394  * the remaining input features are ignored.  If it is shorter, the
395  * missing features are disabled.
396  *
397  * If the string is not formatted properly (not a multiple of two bytes),
398  * NULL is returned.
399  *
400  * Conversion stops at the first non-hex character.
401  *=====================================================================
402  */
403
404 am_feature_t *
405 am_string_to_feature(
406     char                *s)
407 {
408     am_feature_t                *f = NULL;
409     size_t                      i;
410     int                         ch1, ch2;
411     char *                      orig = s;
412
413     if (s != NULL && strcmp(s,"UNKNOWNFEATURE") != 0) {
414         f = am_allocate_feature_set();
415         for (i = 0; i < f->size && (ch1 = *s++) != '\0'; i++) {
416             if (isdigit(ch1)) {
417                 ch1 -= '0';
418             } else if (ch1 >= 'a' && ch1 <= 'f') {
419                 ch1 -= 'a';
420                 ch1 += 10;
421             } else if (ch1 >= 'A' && ch1 <= 'F') {
422                 ch1 -= 'A';
423                 ch1 += 10;
424             } else {
425                 goto bad;
426             }
427             ch2 = *s++;
428             if (isdigit(ch2)) {
429                 ch2 -= '0';
430             } else if (ch2 >= 'a' && ch2 <= 'f') {
431                 ch2 -= 'a';
432                 ch2 += 10;
433             } else if (ch2 >= 'A' && ch2 <= 'F') {
434                 ch2 -= 'A';
435                 ch2 += 10;
436             } else if (ch2 == '\0') {
437                 g_warning("odd number of digits in amfeature string; truncating");
438                 break;
439             } else {
440                 goto bad;
441             }
442             f->bytes[i] = (unsigned char)((ch1 << 4) | ch2);
443         }
444     }
445     return f;
446
447 bad:
448     g_warning("Bad feature string '%s'", orig);
449     am_release_feature_set(f);
450     return NULL;
451 }
452
453 #if defined(TEST)
454 int
455 main(
456     int         argc,
457     char **     argv)
458 {
459     am_feature_t                *f;
460     am_feature_t                *f1;
461     char                        *s;
462     char                        *s1;
463     int                         i;
464     int                         n;
465
466     /*
467      * Configure program for internationalization:
468      *   1) Only set the message locale for now.
469      *   2) Set textdomain for all amanda related programs to "amanda"
470      *      We don't want to be forced to support dozens of message catalogs.
471      */  
472     setlocale(LC_MESSAGES, "C");
473     textdomain("amanda"); 
474
475     f = am_init_feature_set();
476     if (f == NULL) {
477         g_fprintf(stderr, _("cannot initialize feature set\n"));
478         return 1;
479     }
480
481     s = am_feature_to_string(f);
482     g_printf(_("base features=%s\n"), s);
483
484     f1 = am_string_to_feature(s);
485     s1 = am_feature_to_string(f1);
486     if (strcmp(s, s1) != 0) {
487         g_fprintf(stderr, _("base feature -> string -> feature set mismatch\n"));
488         g_fprintf(stderr, _("conv features=%s\n"), s);
489     }
490
491     amfree(s1);
492     amfree(s);
493
494     for (i = 1; i < argc; i++) {
495         if (argv[i][0] == '+') {
496             n = atoi(&argv[i][1]);
497             if (am_add_feature(f, (am_feature_e)n)) {
498                 g_printf(_("added feature number %d\n"), n);
499             } else {
500                 g_printf(_("could not add feature number %d\n"), n);
501             }
502         } else if (argv[i][0] == '-') {
503             n = atoi(&argv[i][1]);
504             if (am_remove_feature(f, (am_feature_e)n)) {
505                 g_printf(_("removed feature number %d\n"), n);
506             } else {
507                 g_printf(_("could not remove feature number %d\n"), n);
508             }
509         } else {
510             n = atoi(argv[i]);
511             if (am_has_feature(f, (am_feature_e)n)) {
512                 g_printf(_("feature %d is set\n"), n);
513             } else {
514                 g_printf(_("feature %d is not set\n"), n);
515             }
516         }
517     }
518
519     s = am_feature_to_string(f);
520     g_printf(_(" new features=%s\n"), s);
521     amfree(s);
522
523     return 0;
524 }
525 #endif