typedvar.c (6622B)
1 /* Copyright (c) 2001 Matej Pfajfar. 2 * Copyright (c) 2001-2004, Roger Dingledine. 3 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. 4 * Copyright (c) 2007-2021, The Tor Project, Inc. */ 5 /* See LICENSE for licensing information */ 6 7 /** 8 * @file typedvar.c 9 * @brief Functions for accessing a pointer as an object of a given type. 10 * 11 * These functions represent a low-level API for accessing a typed variable. 12 * They are used in the configuration system to examine and set fields in 13 * configuration objects used by individual modules. 14 * 15 * Almost no code should call these directly. 16 **/ 17 18 #include "orconfig.h" 19 #include "lib/conf/conftypes.h" 20 #include "lib/confmgt/type_defs.h" 21 #include "lib/confmgt/typedvar.h" 22 #include "lib/encoding/confline.h" 23 #include "lib/log/escape.h" 24 #include "lib/log/log.h" 25 #include "lib/log/util_bug.h" 26 #include "lib/malloc/malloc.h" 27 #include "lib/string/printf.h" 28 #include "lib/string/util_string.h" 29 30 #include "lib/confmgt/var_type_def_st.h" 31 32 #include <stddef.h> 33 #include <string.h> 34 35 /** 36 * Try to parse a string in <b>value</b> that encodes an object of the type 37 * defined by <b>def</b>. 38 * 39 * On success, adjust the lvalue pointed to by <b>target</b> to hold that 40 * value, and return 0. On failure, set *<b>errmsg</b> to a newly allocated 41 * string holding an error message, and return -1. 42 **/ 43 int 44 typed_var_assign(void *target, const char *value, char **errmsg, 45 const var_type_def_t *def) 46 { 47 if (BUG(!def)) 48 return -1; // LCOV_EXCL_LINE 49 // clear old value if needed. 50 typed_var_free(target, def); 51 52 tor_assert(def->fns->parse); 53 return def->fns->parse(target, value, errmsg, def->params); 54 } 55 56 /** 57 * Try to parse a single line from the head of<b>line</b> that encodes an 58 * object of the type defined in <b>def</b>. On success and failure, behave as 59 * typed_var_assign(). 60 * 61 * All types for which keys are significant should use this function. 62 * 63 * Note that although multiple lines may be provided in <b>line</b>, 64 * only the first one is handled by this function. 65 **/ 66 int 67 typed_var_kvassign(void *target, const config_line_t *line, 68 char **errmsg, const var_type_def_t *def) 69 { 70 if (BUG(!def)) 71 return -1; // LCOV_EXCL_LINE 72 73 if (def->fns->kv_parse) { 74 // We do _not_ free the old value here, since linelist options 75 // sometimes have append semantics. 76 return def->fns->kv_parse(target, line, errmsg, def->params); 77 } 78 79 int rv = typed_var_assign(target, line->value, errmsg, def); 80 if (rv < 0 && *errmsg != NULL) { 81 /* typed_var_assign() didn't know the line's keyword, but we do. 82 * Let's add it to the error message. */ 83 char *oldmsg = *errmsg; 84 tor_asprintf(errmsg, "Could not parse %s: %s", line->key, oldmsg); 85 tor_free(oldmsg); 86 } 87 return rv; 88 } 89 90 /** 91 * Release storage held by a variable in <b>target</b> of type defined by 92 * <b>def</b>, and set <b>target</b> to a reasonable default. 93 **/ 94 void 95 typed_var_free(void *target, const var_type_def_t *def) 96 { 97 if (BUG(!def)) 98 return; // LCOV_EXCL_LINE 99 if (def->fns->clear) { 100 def->fns->clear(target, def->params); 101 } 102 } 103 104 /** 105 * Encode a value of type <b>def</b> pointed to by <b>value</b>, and return 106 * its result in a newly allocated string. The string may need to be escaped. 107 * 108 * Returns NULL if this option has a NULL value, or on internal error. 109 **/ 110 char * 111 typed_var_encode(const void *value, const var_type_def_t *def) 112 { 113 if (BUG(!def)) 114 return NULL; // LCOV_EXCL_LINE 115 tor_assert(def->fns->encode); 116 return def->fns->encode(value, def->params); 117 } 118 119 /** 120 * As typed_var_encode(), but returns a newly allocated config_line_t 121 * object. The provided <b>key</b> is used as the key of the lines, unless 122 * the type is one (line a linelist) that encodes its own keys. 123 * 124 * This function may return a list of multiple lines. 125 * 126 * Returns NULL if there are no lines to encode, or on internal error. 127 */ 128 config_line_t * 129 typed_var_kvencode(const char *key, const void *value, 130 const var_type_def_t *def) 131 { 132 if (BUG(!def)) 133 return NULL; // LCOV_EXCL_LINE 134 if (def->fns->kv_encode) { 135 return def->fns->kv_encode(key, value, def->params); 136 } 137 char *encoded_value = typed_var_encode(value, def); 138 if (!encoded_value) 139 return NULL; 140 141 config_line_t *result = tor_malloc_zero(sizeof(config_line_t)); 142 result->key = tor_strdup(key); 143 result->value = encoded_value; 144 return result; 145 } 146 147 /** 148 * Set <b>dest</b> to contain the same value as <b>src</b>. Both types 149 * must be as defined by <b>def</b>. 150 * 151 * Return 0 on success, and -1 on failure. 152 **/ 153 int 154 typed_var_copy(void *dest, const void *src, const var_type_def_t *def) 155 { 156 if (BUG(!def)) 157 return -1; // LCOV_EXCL_LINE 158 if (def->fns->copy) { 159 // If we have been provided a copy function, use it. 160 return def->fns->copy(dest, src, def); 161 } 162 163 // Otherwise, encode 'src' and parse the result into 'def'. 164 char *enc = typed_var_encode(src, def); 165 if (!enc) { 166 typed_var_free(dest, def); 167 return 0; 168 } 169 char *err = NULL; 170 int rv = typed_var_assign(dest, enc, &err, def); 171 if (BUG(rv < 0)) { 172 // LCOV_EXCL_START 173 log_warn(LD_BUG, "Encoded value %s was not parseable as a %s: %s", 174 escaped(enc), def->name, err?err:""); 175 // LCOV_EXCL_STOP 176 } 177 tor_free(err); 178 tor_free(enc); 179 return rv; 180 } 181 182 /** 183 * Return true if <b>a</b> and <b>b</b> are semantically equivalent. 184 * Both types must be as defined by <b>def</b>. 185 **/ 186 bool 187 typed_var_eq(const void *a, const void *b, const var_type_def_t *def) 188 { 189 if (BUG(!def)) 190 return false; // LCOV_EXCL_LINE 191 192 if (def->fns->eq) { 193 // Use a provided eq function if we got one. 194 return def->fns->eq(a, b, def->params); 195 } 196 197 // Otherwise, encode the values and compare them. 198 char *enc_a = typed_var_encode(a, def); 199 char *enc_b = typed_var_encode(b, def); 200 bool eq = !strcmp_opt(enc_a,enc_b); 201 tor_free(enc_a); 202 tor_free(enc_b); 203 return eq; 204 } 205 206 /** 207 * Check whether <b>value</b> encodes a valid value according to the 208 * type definition in <b>def</b>. 209 */ 210 bool 211 typed_var_ok(const void *value, const var_type_def_t *def) 212 { 213 if (BUG(!def)) 214 return false; // LCOV_EXCL_LINE 215 216 if (def->fns->ok) 217 return def->fns->ok(value, def->params); 218 219 return true; 220 } 221 222 /** 223 * Mark <b>value</b> -- a variable that ordinarily would be extended by 224 * assignment -- as "fragile", so that it will get replaced by the next 225 * assignment instead. 226 **/ 227 void 228 typed_var_mark_fragile(void *value, const var_type_def_t *def) 229 { 230 if (BUG(!def)) { 231 return; // LCOV_EXCL_LINE 232 } 233 234 if (def->fns->mark_fragile) 235 def->fns->mark_fragile(value, def->params); 236 }