main.c revision 1.14
1/* $NetBSD: main.c,v 1.14 2010/12/13 20:48:44 pooka 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.14 2010/12/13 20:48:44 pooka 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 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 prop_dictionary_set(props, name, prop_bool_create(boolvalue)); 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 prop_dictionary_set(props, name, 219 prop_number_create_integer(intvalue)); 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 prop_dictionary_set(props, name, prop_string_create_cstring(value)); 251} 252 253static void 254usage(void) 255{ 256 257 (void)fprintf(stderr, 258 "Usage: %s [-fP] [-b var=boolean] [-i var=integer] " 259 "[-s var=string] module\n" 260 " %s -p [-b var=boolean] [-d var] [-i var=integer] " 261 "[-m plist]\n [-s var=string]\n", 262 getprogname(), getprogname()); 263 exit(EXIT_FAILURE); 264} 265 266static void 267merge_dicts(prop_dictionary_t existing_dict, const prop_dictionary_t new_dict) 268{ 269 prop_dictionary_keysym_t props_keysym; 270 prop_object_iterator_t props_iter; 271 prop_object_t props_obj; 272 const char *props_key; 273 274 props_iter = prop_dictionary_iterator(new_dict); 275 if (props_iter == NULL) { 276 errx(EXIT_FAILURE, "Failed to iterate new property list"); 277 } 278 279 while ((props_obj = prop_object_iterator_next(props_iter)) != NULL) { 280 props_keysym = (prop_dictionary_keysym_t)props_obj; 281 props_key = prop_dictionary_keysym_cstring_nocopy(props_keysym); 282 props_obj = prop_dictionary_get_keysym(new_dict, props_keysym); 283 if ((props_obj == NULL) || !prop_dictionary_set(existing_dict, 284 props_key, props_obj)) { 285 errx(EXIT_FAILURE, "Failed to copy " 286 "existing property list"); 287 } 288 } 289 prop_object_iterator_release(props_iter); 290 291 return; 292} 293