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