main.c revision 1.17
1/* $NetBSD: main.c,v 1.17 2016/09/05 01:09:57 sevan 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.17 2016/09/05 01:09:57 sevan 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 prop_object_t po; 188 189 assert(name != NULL); 190 assert(value != NULL); 191 192 if (strcasecmp(value, "1") == 0 || 193 strcasecmp(value, "true") == 0 || 194 strcasecmp(value, "yes") == 0) 195 boolvalue = true; 196 else if (strcasecmp(value, "0") == 0 || 197 strcasecmp(value, "false") == 0 || 198 strcasecmp(value, "no") == 0) 199 boolvalue = false; 200 else 201 errx(EXIT_FAILURE, "Invalid boolean value `%s'", value); 202 203 po = prop_bool_create(boolvalue); 204 if (po == NULL) 205 err(EXIT_FAILURE, "prop_bool_create"); 206 prop_dictionary_set(props, name, po); 207} 208 209static void 210parse_int_param(prop_dictionary_t props, const char *name, 211 const char *value) 212{ 213 int64_t intvalue; 214 prop_object_t po; 215 216 assert(name != NULL); 217 assert(value != NULL); 218 219 if (dehumanize_number(value, &intvalue) != 0) 220 err(EXIT_FAILURE, "Invalid integer value `%s'", value); 221 222 po = prop_number_create_integer(intvalue); 223 if (po == NULL) 224 err(EXIT_FAILURE, "prop_number_create_integer"); 225 prop_dictionary_set(props, name, po); 226} 227 228static void 229parse_param(prop_dictionary_t props, const char *origstr, 230 void (*fmt_handler)(prop_dictionary_t, const char *, const char *)) 231{ 232 char *name, *value; 233 234 name = strdup(origstr); 235 236 value = strchr(name, '='); 237 if (value == NULL) { 238 free(name); 239 errx(EXIT_FAILURE, "Invalid parameter `%s'", origstr); 240 } 241 *value++ = '\0'; 242 243 fmt_handler(props, name, value); 244 245 free(name); 246} 247 248static void 249parse_string_param(prop_dictionary_t props, const char *name, 250 const char *value) 251{ 252 prop_object_t po; 253 254 assert(name != NULL); 255 assert(value != NULL); 256 257 po = prop_string_create_cstring(value); 258 if (po == NULL) 259 err(EXIT_FAILURE, "prop_string_create_cstring"); 260 prop_dictionary_set(props, name, po); 261} 262 263static void 264usage(void) 265{ 266 267 (void)fprintf(stderr, 268 "Usage: %s [-fP] [-b var=boolean] [-i var=integer] " 269 "[-s var=string] module\n" 270 " %s -p [-b var=boolean] [-d var] [-i var=integer] " 271 "[-m plist]\n [-s var=string]\n", 272 getprogname(), getprogname()); 273 exit(EXIT_FAILURE); 274} 275 276static void 277merge_dicts(prop_dictionary_t existing_dict, const prop_dictionary_t new_dict) 278{ 279 prop_dictionary_keysym_t props_keysym; 280 prop_object_iterator_t props_iter; 281 prop_object_t props_obj; 282 const char *props_key; 283 284 props_iter = prop_dictionary_iterator(new_dict); 285 if (props_iter == NULL) { 286 errx(EXIT_FAILURE, "Failed to iterate new property list"); 287 } 288 289 while ((props_obj = prop_object_iterator_next(props_iter)) != NULL) { 290 props_keysym = (prop_dictionary_keysym_t)props_obj; 291 props_key = prop_dictionary_keysym_cstring_nocopy(props_keysym); 292 props_obj = prop_dictionary_get_keysym(new_dict, props_keysym); 293 if ((props_obj == NULL) || !prop_dictionary_set(existing_dict, 294 props_key, props_obj)) { 295 errx(EXIT_FAILURE, "Failed to copy " 296 "existing property list"); 297 } 298 } 299 prop_object_iterator_release(props_iter); 300 301 return; 302} 303