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