/* * Amanda, The Advanced Maryland Automatic Network Disk Archiver * Copyright (c) 1991-1998 University of Maryland at College Park * Copyright (c) 2007-2012 Zmanda, Inc. All Rights Reserved. * Copyright (c) 2013-2016 Carbonite, Inc. All Rights Reserved. * All Rights Reserved. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of U.M. not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. U.M. makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M. * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Authors: the Amanda Development Team. Its members are listed in a * file named AUTHORS, in the root directory of this distribution. */ /* * $Id: amfeatures.c,v 1.24 2006/07/19 17:46:07 martinea Exp $ * * Feature test related code. */ #include "amanda.h" #include "amfeatures.h" /* *===================================================================== * Initialize the base feature set for this version of Amanda. * * am_feature_t *am_init_feature_set() * * entry: none * exit: dynamically allocated feature set structure *===================================================================== */ am_feature_t * am_init_feature_set(void) { am_feature_t *f; if ((f = am_allocate_feature_set()) != NULL) { /* * Whenever a new feature is added, a new line usually needs * to be added here to show that we support it. */ am_add_feature(f, have_feature_support); am_add_feature(f, fe_options_auth); am_add_feature(f, fe_selfcheck_req); am_add_feature(f, fe_selfcheck_req_device); am_add_feature(f, fe_selfcheck_rep); am_add_feature(f, fe_sendsize_req_no_options); am_add_feature(f, fe_sendsize_req_options); am_add_feature(f, fe_sendsize_req_device); am_add_feature(f, fe_sendsize_rep); am_add_feature(f, fe_sendbackup_req); am_add_feature(f, fe_sendbackup_req_device); am_add_feature(f, fe_sendbackup_rep); am_add_feature(f, fe_noop_req); am_add_feature(f, fe_noop_rep); am_add_feature(f, fe_program_dump); am_add_feature(f, fe_program_gnutar); am_add_feature(f, fe_program_application_api); am_add_feature(f, fe_options_compress_fast); am_add_feature(f, fe_options_compress_best); am_add_feature(f, fe_options_srvcomp_fast); am_add_feature(f, fe_options_srvcomp_best); am_add_feature(f, fe_options_no_record); am_add_feature(f, fe_options_bsd_auth); am_add_feature(f, fe_options_index); am_add_feature(f, fe_options_exclude_file); am_add_feature(f, fe_options_exclude_list); am_add_feature(f, fe_options_multiple_exclude); am_add_feature(f, fe_options_optional_exclude); am_add_feature(f, fe_options_include_file); am_add_feature(f, fe_options_include_list); am_add_feature(f, fe_options_multiple_include); am_add_feature(f, fe_options_optional_include); am_add_feature(f, fe_options_kencrypt); am_add_feature(f, fe_req_options_maxdumps); am_add_feature(f, fe_req_options_hostname); am_add_feature(f, fe_req_options_features); am_add_feature(f, fe_rep_options_features); am_add_feature(f, fe_amindexd_fileno_in_OLSD); am_add_feature(f, fe_amindexd_fileno_in_ORLD); am_add_feature(f, fe_amidxtaped_fsf); am_add_feature(f, fe_amidxtaped_label); am_add_feature(f, fe_amidxtaped_device); am_add_feature(f, fe_amidxtaped_host); am_add_feature(f, fe_amidxtaped_disk); am_add_feature(f, fe_amidxtaped_datestamp); am_add_feature(f, fe_amidxtaped_header); am_add_feature(f, fe_amidxtaped_config); am_add_feature(f, fe_recover_splits); am_add_feature(f, fe_amidxtaped_exchange_features); am_add_feature(f, fe_partial_estimate); am_add_feature(f, fe_calcsize_estimate); am_add_feature(f, fe_selfcheck_calcsize); am_add_feature(f, fe_options_compress_cust); am_add_feature(f, fe_options_srvcomp_cust); am_add_feature(f, fe_options_encrypt_cust); am_add_feature(f, fe_options_encrypt_serv_cust); am_add_feature(f, fe_options_client_decrypt_option); am_add_feature(f, fe_options_server_decrypt_option); am_add_feature(f, fe_amindexd_marshall_in_OLSD); am_add_feature(f, fe_amindexd_marshall_in_ORLD); am_add_feature(f, fe_amindexd_marshall_in_DHST); am_add_feature(f, fe_amrecover_FEEDME); am_add_feature(f, fe_amrecover_timestamp); am_add_feature(f, fe_interface_quoted_text); am_add_feature(f, fe_program_star); am_add_feature(f, fe_amindexd_options_hostname); am_add_feature(f, fe_amindexd_options_features); am_add_feature(f, fe_amindexd_options_auth); am_add_feature(f, fe_amidxtaped_options_hostname); am_add_feature(f, fe_amidxtaped_options_features); am_add_feature(f, fe_amidxtaped_options_auth); am_add_feature(f, fe_amrecover_message); am_add_feature(f, fe_amrecover_feedme_tape); am_add_feature(f, fe_req_options_config); am_add_feature(f, fe_rep_sendsize_quoted_error); am_add_feature(f, fe_req_xml); am_add_feature(f, fe_pp_script); am_add_feature(f, fe_amindexd_DLE); am_add_feature(f, fe_amrecover_dle_in_header); am_add_feature(f, fe_xml_estimate); am_add_feature(f, fe_xml_property_priority); am_add_feature(f, fe_sendsize_rep_warning); am_add_feature(f, fe_xml_estimatelist); am_add_feature(f, fe_xml_level_server); am_add_feature(f, fe_xml_data_path); am_add_feature(f, fe_xml_directtcp_list); am_add_feature(f, fe_amidxtaped_datapath); am_add_feature(f, fe_sendbackup_noop); am_add_feature(f, fe_amrecover_origsize_in_header); am_add_feature(f, fe_amidxtaped_abort); am_add_feature(f, fe_amrecover_correct_disk_quoting); am_add_feature(f, fe_amindexd_quote_label); am_add_feature(f, fe_amrecover_receive_unfiltered); am_add_feature(f, fe_application_client_name); am_add_feature(f, fe_script_client_name); am_add_feature(f, fe_dumptype_property); am_add_feature(f, fe_sendbackup_crc); am_add_feature(f, fe_amrecover_crc_in_header); am_add_feature(f, fe_amrecover_data_status); am_add_feature(f, fe_amrecover_data_crc); am_add_feature(f, fe_sendbackup_state); am_add_feature(f, fe_amrecover_storage_in_marshall); am_add_feature(f, fe_amidxtaped_storage_in_marshall); am_add_feature(f, fe_amindexd_STORAGE); am_add_feature(f, fe_sendbackup_retry); am_add_feature(f, fe_sendbackup_retry_delay); am_add_feature(f, fe_sendbackup_retry_level); am_add_feature(f, fe_sendbackup_retry_message); am_add_feature(f, fe_selfcheck_message); //am_add_feature(f, fe_sendsize_message); //am_add_feature(f, fe_sendbackup_message); am_add_feature(f, fe_sendbackup_rep_retry); am_add_feature(f, fe_sendbackup_stream_state); am_add_feature(f, fe_amrecover_stream_state); am_add_feature(f, fe_amidxtaped_dar); am_add_feature(f, fe_restore_mesg_json); am_add_feature(f, fe_restore_state_stream); am_add_feature(f, fe_amrecover_header_send_size); am_add_feature(f, fe_amrecover_header_ready); am_add_feature(f, fe_amrecover_header_done); am_add_feature(f, fe_amrecover_state_send); am_add_feature(f, fe_amrecover_state_ready); am_add_feature(f, fe_amrecover_state_done); am_add_feature(f, fe_amrecover_data_send); am_add_feature(f, fe_amrecover_data_ready); //am_add_feature(f, fe_amrecover_data_done); am_add_feature(f, fe_restore_header_send_size); am_add_feature(f, fe_restore_header_ready); am_add_feature(f, fe_restore_header_done); am_add_feature(f, fe_restore_state_send); am_add_feature(f, fe_restore_state_ready); am_add_feature(f, fe_restore_state_done); am_add_feature(f, fe_restore_data_send); am_add_feature(f, fe_restore_data_ready); //am_add_feature(f, fe_amrecover_data_done); am_add_feature(f, fe_restore_dar); am_add_feature(f, fe_restore_datapath); am_add_feature(f, fe_restore_include); am_add_feature(f, fe_restore_include_glob); am_add_feature(f, fe_restore_exclude); am_add_feature(f, fe_restore_exclude_glob); am_add_feature(f, fe_restore_prev_next_level); am_add_feature(f, fe_sendbackup_req_options_data_shm_control_name); am_add_feature(f, fe_req_options_timestamp); } return f; } /* *===================================================================== * Set a default feature set for client that doesn't have noop service. * This is all the features available in 2.4.2p2. * * entry: none * exit: dynamically allocated feature set *===================================================================== */ am_feature_t * am_set_default_feature_set(void) { am_feature_t *f; if ((f = am_allocate_feature_set()) != NULL) { am_add_feature(f, fe_selfcheck_req); am_add_feature(f, fe_selfcheck_rep); am_add_feature(f, fe_sendsize_req_no_options); am_add_feature(f, fe_sendsize_rep); am_add_feature(f, fe_sendbackup_req); am_add_feature(f, fe_sendbackup_rep); am_add_feature(f, fe_program_dump); am_add_feature(f, fe_program_gnutar); am_add_feature(f, fe_options_compress_fast); am_add_feature(f, fe_options_compress_best); am_add_feature(f, fe_options_srvcomp_fast); am_add_feature(f, fe_options_srvcomp_best); am_add_feature(f, fe_options_no_record); am_add_feature(f, fe_options_bsd_auth); am_add_feature(f, fe_options_index); am_add_feature(f, fe_options_exclude_file); am_add_feature(f, fe_options_exclude_list); am_add_feature(f, fe_options_kencrypt); am_add_feature(f, fe_req_options_maxdumps); am_add_feature(f, fe_req_options_hostname); am_add_feature(f, fe_req_options_features); am_add_feature(f, fe_rep_options_sendbackup_options); } return f; } /* *===================================================================== * Allocate space for a feature set. * * am_feature_t *am_allocate_feature_set() * * entry: none * exit: dynamically allocated feature set structure *===================================================================== */ am_feature_t * am_allocate_feature_set(void) { size_t nbytes; am_feature_t *result; result = (am_feature_t *)g_malloc(sizeof(*result)); memset(result, 0, sizeof(*result)); nbytes = (((size_t)last_feature) + 8) >> 3; result->size = nbytes; result->bytes = (unsigned char *)g_malloc(nbytes); memset(result->bytes, 0, nbytes); return result; } /* *===================================================================== * Release space allocated to a feature set. * * void am_release_feature_set(am_feature_t *f) * * entry: f = feature set to release * exit: none *===================================================================== */ void am_release_feature_set( am_feature_t *f) { if (f != NULL) { amfree(f->bytes); f->size = 0; } amfree(f); } /* *===================================================================== * Add a feature to a feature set. * * int am_add_feature(am_feature_t *f, am_feature_e n) * * entry: f = feature set to add to * n = feature to add * exit: non-zero if feature added, else zero (e.g. if the feature * is beyond what is currently supported) *===================================================================== */ int am_add_feature( am_feature_t *f, am_feature_e n) { size_t byte; int bit; int result = 0; if (f != NULL && (int)n >= 0) { byte = ((size_t)n) >> 3; if (byte < f->size) { bit = ((int)n) & 0x7; f->bytes[byte] = (unsigned char)((int)f->bytes[byte] | (unsigned char)(1 << bit)); result = 1; } } return result; } /* *===================================================================== * Remove a feature from a feature set. * * int am_remove_feature(am_feature_t *f, am_feature_e n) * * entry: f = feature set to remove from * n = feature to remove * exit: non-zero if feature removed, else zero (e.g. if the feature * is beyond what is currently supported) *===================================================================== */ int am_remove_feature( am_feature_t *f, am_feature_e n) { size_t byte; int bit; int result = 0; if (f != NULL && (int)n >= 0) { byte = ((size_t)n) >> 3; if (byte < f->size) { bit = ((int)n) & 0x7; f->bytes[byte] = (unsigned char)((int)f->bytes[byte] & (unsigned char)~(1 << bit)); result = 1; } } return result; } /* *===================================================================== * Return true if a given feature is available. * * int am_has_feature(am_feature_t *f, am_feature_e n) * * entry: f = feature set to test * n = feature to test * exit: non-zero if feature is enabled *===================================================================== */ int am_has_feature( am_feature_t *f, am_feature_e n) { size_t byte; int bit; int result = 0; if (f != NULL && (int)n >= 0) { byte = ((size_t)n) >> 3; if (byte < f->size) { bit = ((int)n) & 0x7; result = ((f->bytes[byte] & (1 << bit)) != 0); } } return result; } /* *===================================================================== * Convert a feature set to string. * * char *am_feature_to_string(am_feature_t *f) * * entry: f = feature set to convet * exit: dynamically allocated string *===================================================================== */ char * am_feature_to_string( am_feature_t *f) { char *result; size_t i; if (f == NULL) { result = g_strdup(_("UNKNOWNFEATURE")); } else { result = g_malloc((f->size * 2) + 1); for (i = 0; i < f->size; i++) { g_snprintf(result + (i * 2), 2 + 1, "%02x", f->bytes[i]); } result[i * 2] = '\0'; } return result; } /* *===================================================================== * Convert a sting back to a feature set. * * am_feature_t *am_string_to_feature(char *s) * * entry: s = string to convert * exit: dynamically allocated feature set * * Note: if the string is longer than the list of features we support, * the remaining input features are ignored. If it is shorter, the * missing features are disabled. * * If the string is not formatted properly (not a multiple of two bytes), * NULL is returned. * * Conversion stops at the first non-hex character. *===================================================================== */ am_feature_t * am_string_to_feature( char *s) { am_feature_t *f = NULL; size_t i; int ch1, ch2; char * orig = s; if (s != NULL && !g_str_equal(s, "UNKNOWNFEATURE")) { f = am_allocate_feature_set(); for (i = 0; i < f->size && (ch1 = *s++) != '\0'; i++) { if (isdigit(ch1)) { ch1 -= '0'; } else if (ch1 >= 'a' && ch1 <= 'f') { ch1 -= 'a'; ch1 += 10; } else if (ch1 >= 'A' && ch1 <= 'F') { ch1 -= 'A'; ch1 += 10; } else { goto bad; } ch2 = *s++; if (isdigit(ch2)) { ch2 -= '0'; } else if (ch2 >= 'a' && ch2 <= 'f') { ch2 -= 'a'; ch2 += 10; } else if (ch2 >= 'A' && ch2 <= 'F') { ch2 -= 'A'; ch2 += 10; } else if (ch2 == '\0') { g_warning("odd number of digits in amfeature string; truncating"); break; } else { goto bad; } f->bytes[i] = (unsigned char)((ch1 << 4) | ch2); } } return f; bad: g_warning("Bad feature string '%s'", orig); am_release_feature_set(f); return NULL; } am_feature_t * am_features( am_feature_t *f) { return f; }