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