main.c revision 1.18
1/* $NetBSD: main.c,v 1.18 2020/06/07 05:49:05 thorpej Exp $ */ 2 3/*- 4 * Copyright (c) 2008 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> 30#ifndef lint 31__RCSID("$NetBSD: main.c,v 1.18 2020/06/07 05:49:05 thorpej Exp $"); 32#endif /* !lint */ 33 34#include <sys/module.h> 35#include <sys/queue.h> 36 37#include <assert.h> 38#include <stdbool.h> 39#include <stdio.h> 40#include <stdlib.h> 41#include <string.h> 42#include <unistd.h> 43#include <err.h> 44 45#include <prop/proplib.h> 46 47#include "prog_ops.h" 48 49static void parse_bool_param(prop_dictionary_t, const char *, 50 const char *); 51static void parse_int_param(prop_dictionary_t, const char *, 52 const char *); 53static void parse_param(prop_dictionary_t, const char *, 54 void (*)(prop_dictionary_t, const char *, 55 const char *)); 56static void parse_string_param(prop_dictionary_t, const char *, 57 const char *); 58static void usage(void) __dead; 59static void merge_dicts(prop_dictionary_t, const prop_dictionary_t); 60 61int 62main(int argc, char **argv) 63{ 64 SIMPLEQ_HEAD(del_head, del_item) del_head; 65 modctl_load_t cmdargs; 66 prop_dictionary_t ext_props, props; 67 bool del_props, merge_props, output_props; 68 const char *ext_file; 69 char *propsstr; 70 int ch; 71 int flags; 72 73 struct del_item { 74 SIMPLEQ_ENTRY(del_item) del_items; 75 const char *del_key; 76 } *delp; 77 78 SIMPLEQ_INIT(&del_head); 79 ext_file = NULL; 80 ext_props = NULL; 81 props = prop_dictionary_create(); 82 del_props = merge_props = output_props = false; 83 flags = 0; 84 85 while ((ch = getopt(argc, argv, "Pb:d:fi:m:ps:")) != -1) { 86 switch (ch) { 87 case 'P': 88 flags |= MODCTL_NO_PROP; 89 break; 90 case 'b': 91 parse_param(props, optarg, parse_bool_param); 92 break; 93 94 case 'd': 95 del_props = true; 96 delp = malloc(sizeof(struct del_item)); 97 if (delp == NULL) 98 errx(EXIT_FAILURE, "Out of memory"); 99 delp->del_key = optarg; 100 SIMPLEQ_INSERT_TAIL(&del_head, delp, del_items); 101 break; 102 103 case 'f': 104 flags |= MODCTL_LOAD_FORCE; 105 break; 106 107 case 'i': 108 parse_param(props, optarg, parse_int_param); 109 break; 110 111 case 'm': 112 merge_props = true; 113 ext_file = optarg; 114 break; 115 116 case 'p': 117 output_props = true; 118 break; 119 120 case 's': 121 parse_param(props, optarg, parse_string_param); 122 break; 123 124 default: 125 usage(); 126 /* NOTREACHED */ 127 } 128 } 129 130 argc -= optind; 131 argv += optind; 132 133 propsstr = prop_dictionary_externalize(props); 134 if (propsstr == NULL) 135 errx(EXIT_FAILURE, "Failed to process properties"); 136 137 if (output_props) { 138 if (merge_props) { 139 ext_props = 140 prop_dictionary_internalize_from_file(ext_file); 141 if (ext_props == NULL) { 142 errx(EXIT_FAILURE, "Failed to read existing " 143 "property list"); 144 } 145 146 free(propsstr); 147 merge_dicts(ext_props, props); 148 149 if (del_props) 150 SIMPLEQ_FOREACH(delp, &del_head, del_items) 151 prop_dictionary_remove(ext_props, 152 delp->del_key); 153 154 propsstr = prop_dictionary_externalize(ext_props); 155 if (propsstr == NULL) 156 errx(EXIT_FAILURE, "Failed to process " 157 "properties"); 158 } 159 160 fputs(propsstr, stdout); 161 } else { 162 if (argc != 1) 163 usage(); 164 if (prog_init && prog_init() == -1) 165 err(1, "prog init failed"); 166 cmdargs.ml_filename = argv[0]; 167 cmdargs.ml_flags = flags; 168 cmdargs.ml_props = propsstr; 169 cmdargs.ml_propslen = strlen(propsstr); 170 171 if (prog_modctl(MODCTL_LOAD, &cmdargs)) { 172 err(EXIT_FAILURE, "%s", cmdargs.ml_filename); 173 } 174 } 175 176 free(propsstr); 177 prop_object_release(props); 178 179 exit(EXIT_SUCCESS); 180} 181 182static void 183parse_bool_param(prop_dictionary_t props, const char *name, 184 const char *value) 185{ 186 bool boolvalue; 187 188 assert(name != NULL); 189 assert(value != NULL); 190 191 if (strcasecmp(value, "1") == 0 || 192 strcasecmp(value, "true") == 0 || 193 strcasecmp(value, "yes") == 0) 194 boolvalue = true; 195 else if (strcasecmp(value, "0") == 0 || 196 strcasecmp(value, "false") == 0 || 197 strcasecmp(value, "no") == 0) 198 boolvalue = false; 199 else 200 errx(EXIT_FAILURE, "Invalid boolean value `%s'", value); 201 202 if (!prop_dictionary_set_bool(props, name, boolvalue)) 203 err(EXIT_FAILURE, "prop_dictionary_set_bool"); 204} 205 206static void 207parse_int_param(prop_dictionary_t props, const char *name, 208 const char *value) 209{ 210 int64_t intvalue; 211 212 assert(name != NULL); 213 assert(value != NULL); 214 215 if (dehumanize_number(value, &intvalue) != 0) 216 err(EXIT_FAILURE, "Invalid integer value `%s'", value); 217 218 if (!prop_dictionary_set_int64(props, name, intvalue)) 219 err(EXIT_FAILURE, "prop_dictionary_set_int64"); 220} 221 222static void 223parse_param(prop_dictionary_t props, const char *origstr, 224 void (*fmt_handler)(prop_dictionary_t, const char *, const char *)) 225{ 226 char *name, *value; 227 228 name = strdup(origstr); 229 230 value = strchr(name, '='); 231 if (value == NULL) { 232 free(name); 233 errx(EXIT_FAILURE, "Invalid parameter `%s'", origstr); 234 } 235 *value++ = '\0'; 236 237 fmt_handler(props, name, value); 238 239 free(name); 240} 241 242static void 243parse_string_param(prop_dictionary_t props, const char *name, 244 const char *value) 245{ 246 247 assert(name != NULL); 248 assert(value != NULL); 249 250 if (!prop_dictionary_set_string(props, name, value)) 251 err(EXIT_FAILURE, "prop_dictionary_set_string"); 252} 253 254static void 255usage(void) 256{ 257 258 (void)fprintf(stderr, 259 "Usage: %s [-fP] [-b var=boolean] [-i var=integer] " 260 "[-s var=string] module\n" 261 " %s -p [-b var=boolean] [-d var] [-i var=integer] " 262 "[-m plist]\n [-s var=string]\n", 263 getprogname(), getprogname()); 264 exit(EXIT_FAILURE); 265} 266 267static void 268merge_dicts(prop_dictionary_t existing_dict, const prop_dictionary_t new_dict) 269{ 270 prop_dictionary_keysym_t props_keysym; 271 prop_object_iterator_t props_iter; 272 prop_object_t props_obj; 273 const char *props_key; 274 275 props_iter = prop_dictionary_iterator(new_dict); 276 if (props_iter == NULL) { 277 errx(EXIT_FAILURE, "Failed to iterate new property list"); 278 } 279 280 while ((props_obj = prop_object_iterator_next(props_iter)) != NULL) { 281 props_keysym = (prop_dictionary_keysym_t)props_obj; 282 props_key = prop_dictionary_keysym_value(props_keysym); 283 props_obj = prop_dictionary_get_keysym(new_dict, props_keysym); 284 if ((props_obj == NULL) || !prop_dictionary_set(existing_dict, 285 props_key, props_obj)) { 286 errx(EXIT_FAILURE, "Failed to copy " 287 "existing property list"); 288 } 289 } 290 prop_object_iterator_release(props_iter); 291 292 return; 293} 294