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