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