main.c revision 1.15
1/* $NetBSD: main.c,v 1.15 2013/02/07 12:04:01 apb 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.15 2013/02/07 12:04:01 apb 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 49int main(int, char **); 50static void parse_bool_param(prop_dictionary_t, const char *, 51 const char *); 52static void parse_int_param(prop_dictionary_t, const char *, 53 const char *); 54static void parse_param(prop_dictionary_t, const char *, 55 void (*)(prop_dictionary_t, const char *, 56 const char *)); 57static void parse_string_param(prop_dictionary_t, const char *, 58 const char *); 59static void usage(void) __dead; 60static void merge_dicts(prop_dictionary_t, const prop_dictionary_t); 61 62int 63main(int argc, char **argv) 64{ 65 SIMPLEQ_HEAD(del_head, del_item) del_head; 66 modctl_load_t cmdargs; 67 prop_dictionary_t ext_props, props; 68 bool del_props, merge_props, output_props; 69 const char *ext_file; 70 char *propsstr; 71 int ch; 72 int flags; 73 74 struct del_item { 75 SIMPLEQ_ENTRY(del_item) del_items; 76 const char *del_key; 77 } *delp; 78 79 SIMPLEQ_INIT(&del_head); 80 ext_file = NULL; 81 ext_props = NULL; 82 props = prop_dictionary_create(); 83 del_props = merge_props = output_props = false; 84 flags = 0; 85 86 while ((ch = getopt(argc, argv, "Pb:d:fi:m:ps:")) != -1) { 87 switch (ch) { 88 case 'P': 89 flags |= MODCTL_NO_PROP; 90 break; 91 case 'b': 92 parse_param(props, optarg, parse_bool_param); 93 break; 94 95 case 'd': 96 del_props = true; 97 delp = malloc(sizeof(struct del_item)); 98 if (delp == NULL) 99 errx(EXIT_FAILURE, "Out of memory"); 100 delp->del_key = optarg; 101 SIMPLEQ_INSERT_TAIL(&del_head, delp, del_items); 102 break; 103 104 case 'f': 105 flags |= MODCTL_LOAD_FORCE; 106 break; 107 108 case 'i': 109 parse_param(props, optarg, parse_int_param); 110 break; 111 112 case 'm': 113 merge_props = true; 114 ext_file = optarg; 115 break; 116 117 case 'p': 118 output_props = true; 119 break; 120 121 case 's': 122 parse_param(props, optarg, parse_string_param); 123 break; 124 125 default: 126 usage(); 127 /* NOTREACHED */ 128 } 129 } 130 131 argc -= optind; 132 argv += optind; 133 134 propsstr = prop_dictionary_externalize(props); 135 if (propsstr == NULL) 136 errx(EXIT_FAILURE, "Failed to process properties"); 137 138 if (output_props) { 139 if (merge_props) { 140 ext_props = 141 prop_dictionary_internalize_from_file(ext_file); 142 if (ext_props == NULL) { 143 errx(EXIT_FAILURE, "Failed to read existing " 144 "property list"); 145 } 146 147 free(propsstr); 148 merge_dicts(ext_props, props); 149 150 if (del_props) 151 SIMPLEQ_FOREACH(delp, &del_head, del_items) 152 prop_dictionary_remove(ext_props, 153 delp->del_key); 154 155 propsstr = prop_dictionary_externalize(ext_props); 156 if (propsstr == NULL) 157 errx(EXIT_FAILURE, "Failed to process " 158 "properties"); 159 } 160 161 fputs(propsstr, stdout); 162 } else { 163 if (argc != 1) 164 usage(); 165 if (prog_init && prog_init() == -1) 166 err(1, "prog init failed"); 167 cmdargs.ml_filename = argv[0]; 168 cmdargs.ml_flags = flags; 169 cmdargs.ml_props = propsstr; 170 cmdargs.ml_propslen = strlen(propsstr); 171 172 if (prog_modctl(MODCTL_LOAD, &cmdargs)) { 173 err(EXIT_FAILURE, NULL); 174 } 175 } 176 177 free(propsstr); 178 prop_object_release(props); 179 180 exit(EXIT_SUCCESS); 181} 182 183static void 184parse_bool_param(prop_dictionary_t props, const char *name, 185 const char *value) 186{ 187 bool boolvalue; 188 prop_object_t po; 189 190 assert(name != NULL); 191 assert(value != NULL); 192 193 if (strcasecmp(value, "1") == 0 || 194 strcasecmp(value, "true") == 0 || 195 strcasecmp(value, "yes") == 0) 196 boolvalue = true; 197 else if (strcasecmp(value, "0") == 0 || 198 strcasecmp(value, "false") == 0 || 199 strcasecmp(value, "no") == 0) 200 boolvalue = false; 201 else 202 errx(EXIT_FAILURE, "Invalid boolean value `%s'", value); 203 204 po = prop_bool_create(boolvalue); 205 if (po == NULL) 206 err(EXIT_FAILURE, "prop_bool_create"); 207 prop_dictionary_set(props, name, po); 208} 209 210static void 211parse_int_param(prop_dictionary_t props, const char *name, 212 const char *value) 213{ 214 int64_t intvalue; 215 prop_object_t po; 216 217 assert(name != NULL); 218 assert(value != NULL); 219 220 if (dehumanize_number(value, &intvalue) != 0) 221 err(EXIT_FAILURE, "Invalid integer value `%s'", value); 222 223 po = prop_number_create_integer(intvalue); 224 if (po == NULL) 225 err(EXIT_FAILURE, "prop_number_create_integer"); 226 prop_dictionary_set(props, name, po); 227} 228 229static void 230parse_param(prop_dictionary_t props, const char *origstr, 231 void (*fmt_handler)(prop_dictionary_t, const char *, const char *)) 232{ 233 char *name, *value; 234 235 name = strdup(origstr); 236 237 value = strchr(name, '='); 238 if (value == NULL) { 239 free(name); 240 errx(EXIT_FAILURE, "Invalid parameter `%s'", origstr); 241 } 242 *value++ = '\0'; 243 244 fmt_handler(props, name, value); 245 246 free(name); 247} 248 249static void 250parse_string_param(prop_dictionary_t props, const char *name, 251 const char *value) 252{ 253 prop_object_t po; 254 255 assert(name != NULL); 256 assert(value != NULL); 257 258 po = prop_string_create_cstring(value); 259 if (po == NULL) 260 err(EXIT_FAILURE, "prop_string_create_cstring"); 261 prop_dictionary_set(props, name, po); 262} 263 264static void 265usage(void) 266{ 267 268 (void)fprintf(stderr, 269 "Usage: %s [-fP] [-b var=boolean] [-i var=integer] " 270 "[-s var=string] module\n" 271 " %s -p [-b var=boolean] [-d var] [-i var=integer] " 272 "[-m plist]\n [-s var=string]\n", 273 getprogname(), getprogname()); 274 exit(EXIT_FAILURE); 275} 276 277static void 278merge_dicts(prop_dictionary_t existing_dict, const prop_dictionary_t new_dict) 279{ 280 prop_dictionary_keysym_t props_keysym; 281 prop_object_iterator_t props_iter; 282 prop_object_t props_obj; 283 const char *props_key; 284 285 props_iter = prop_dictionary_iterator(new_dict); 286 if (props_iter == NULL) { 287 errx(EXIT_FAILURE, "Failed to iterate new property list"); 288 } 289 290 while ((props_obj = prop_object_iterator_next(props_iter)) != NULL) { 291 props_keysym = (prop_dictionary_keysym_t)props_obj; 292 props_key = prop_dictionary_keysym_cstring_nocopy(props_keysym); 293 props_obj = prop_dictionary_get_keysym(new_dict, props_keysym); 294 if ((props_obj == NULL) || !prop_dictionary_set(existing_dict, 295 props_key, props_obj)) { 296 errx(EXIT_FAILURE, "Failed to copy " 297 "existing property list"); 298 } 299 } 300 prop_object_iterator_release(props_iter); 301 302 return; 303} 304