[23095] | 1 | /* |
---|
| 2 | * Command line oriented Moira host tool. |
---|
| 3 | * |
---|
| 4 | * kolya@MIT.EDU, January 2000 |
---|
| 5 | * |
---|
| 6 | * Somewhat based on blanche |
---|
| 7 | * |
---|
| 8 | * Copyright (C) 2000, 2001 by the Massachusetts Institute of Technology. |
---|
| 9 | * For copying and distribution information, please see the file |
---|
| 10 | * <mit-copyright.h>. |
---|
| 11 | */ |
---|
| 12 | |
---|
| 13 | #include <mit-copyright.h> |
---|
| 14 | #include <moira.h> |
---|
| 15 | #include <moira_site.h> |
---|
| 16 | #include <mrclient.h> |
---|
| 17 | |
---|
| 18 | #include <ctype.h> |
---|
| 19 | #include <errno.h> |
---|
| 20 | #include <stdio.h> |
---|
| 21 | #include <stdlib.h> |
---|
| 22 | #include <string.h> |
---|
| 23 | |
---|
| 24 | #ifdef _WIN32 |
---|
| 25 | typedef unsigned long in_addr_t; |
---|
| 26 | #else |
---|
| 27 | #include <sys/types.h> |
---|
| 28 | #include <sys/socket.h> |
---|
| 29 | |
---|
| 30 | #include <netinet/in.h> |
---|
| 31 | #include <arpa/inet.h> |
---|
| 32 | #endif |
---|
| 33 | |
---|
[23740] | 34 | RCSID("$Header: /afs/athena.mit.edu/astaff/project/moiradev/repository/moira/clients/stella/stella.c,v 1.20 2003-12-20 02:55:49 zacheiss Exp $"); |
---|
[23095] | 35 | |
---|
| 36 | struct owner_type { |
---|
| 37 | int type; |
---|
| 38 | char *name; |
---|
| 39 | }; |
---|
| 40 | |
---|
| 41 | struct mqelem { |
---|
| 42 | struct mqelem *q_forw; |
---|
| 43 | struct mqelem *q_back; |
---|
| 44 | void *q_data; |
---|
| 45 | }; |
---|
| 46 | |
---|
| 47 | struct string_list { |
---|
| 48 | char *string; |
---|
| 49 | struct string_list *next; |
---|
| 50 | }; |
---|
| 51 | |
---|
| 52 | #define M_ANY 0 |
---|
| 53 | #define M_USER 1 |
---|
| 54 | #define M_LIST 2 |
---|
| 55 | #define M_KERBEROS 3 |
---|
| 56 | #define M_NONE 4 |
---|
| 57 | |
---|
| 58 | /* argument parsing macro */ |
---|
| 59 | #define argis(a, b) (!strcmp(*arg + 1, a) || !strcmp(*arg + 1, b)) |
---|
| 60 | |
---|
| 61 | /* flags from command line */ |
---|
| 62 | int info_flag, update_flag, create_flag, delete_flag, list_map_flag; |
---|
| 63 | int update_alias_flag, update_map_flag, verbose, noauth; |
---|
| 64 | int list_container_flag, update_container_flag, unformatted_flag; |
---|
| 65 | |
---|
| 66 | struct string_list *alias_add_queue, *alias_remove_queue; |
---|
| 67 | struct string_list *map_add_queue, *map_remove_queue; |
---|
| 68 | struct string_list *container_add_queue, *container_remove_queue; |
---|
| 69 | |
---|
| 70 | char *hostname, *whoami; |
---|
| 71 | |
---|
| 72 | char *newname, *address, *network, *h_status, *vendor, *model; |
---|
| 73 | char *os, *location, *contact, *billing_contact, *account_number; |
---|
| 74 | char *adm_cmt, *op_cmt; |
---|
| 75 | |
---|
| 76 | in_addr_t ipaddress; |
---|
| 77 | struct owner_type *owner; |
---|
| 78 | |
---|
| 79 | void usage(char **argv); |
---|
| 80 | int store_host_info(int argc, char **argv, void *hint); |
---|
| 81 | void show_host_info(char **argv); |
---|
| 82 | void show_host_info_unformatted(char **argv); |
---|
| 83 | int show_machine_in_cluster(int argc, char **argv, void *hint); |
---|
| 84 | int show_machine_in_container(int argc, char **argv, void *hint); |
---|
| 85 | struct owner_type *parse_member(char *s); |
---|
| 86 | struct string_list *add_to_string_list(struct string_list *old_list, char *s); |
---|
| 87 | int wrap_mr_query(char *handle, int argc, char **argv, |
---|
| 88 | int (*callback)(int, char **, void *), void *callarg); |
---|
| 89 | void print_query(char *query_name, int argc, char **argv); |
---|
| 90 | |
---|
| 91 | int main(int argc, char **argv) |
---|
| 92 | { |
---|
| 93 | int status, success; |
---|
| 94 | char **arg = argv; |
---|
| 95 | char *server = NULL; |
---|
| 96 | |
---|
| 97 | /* clear all flags & lists */ |
---|
| 98 | info_flag = update_flag = create_flag = list_map_flag = update_map_flag = 0; |
---|
| 99 | update_alias_flag = verbose = noauth = 0; |
---|
| 100 | list_container_flag = update_container_flag = 0; |
---|
| 101 | newname = address = network = h_status = vendor = model = NULL; |
---|
| 102 | os = location = contact = billing_contact = account_number = adm_cmt = NULL; |
---|
| 103 | op_cmt = NULL; |
---|
| 104 | owner = NULL; |
---|
| 105 | alias_add_queue = alias_remove_queue = NULL; |
---|
| 106 | map_add_queue = map_remove_queue = NULL; |
---|
| 107 | container_add_queue = container_remove_queue = NULL; |
---|
| 108 | whoami = argv[0]; |
---|
| 109 | |
---|
| 110 | success = 1; |
---|
| 111 | |
---|
| 112 | /* parse args, building addlist, dellist, & synclist */ |
---|
| 113 | while (++arg - argv < argc) |
---|
| 114 | { |
---|
| 115 | if (**arg == '-') |
---|
| 116 | { |
---|
| 117 | if (argis("i", "info")) |
---|
| 118 | info_flag++; |
---|
| 119 | else if (argis("C", "create")) |
---|
| 120 | create_flag++; |
---|
| 121 | else if (argis("D", "delete")) |
---|
| 122 | delete_flag++; |
---|
| 123 | else if (argis("R", "rename")) { |
---|
| 124 | if (arg - argv < argc - 1) { |
---|
| 125 | arg++; |
---|
| 126 | update_flag++; |
---|
| 127 | newname = *arg; |
---|
| 128 | } else |
---|
| 129 | usage(argv); |
---|
| 130 | } |
---|
| 131 | else if (argis("A", "address")) { |
---|
| 132 | if (arg - argv < argc - 1) { |
---|
| 133 | arg++; |
---|
| 134 | update_flag++; |
---|
| 135 | address = *arg; |
---|
| 136 | } else |
---|
| 137 | usage(argv); |
---|
| 138 | } |
---|
| 139 | else if (argis("O", "owner")) { |
---|
| 140 | if (arg - argv < argc - 1) { |
---|
| 141 | arg++; |
---|
| 142 | update_flag++; |
---|
| 143 | owner = parse_member(*arg); |
---|
| 144 | } else |
---|
| 145 | usage(argv); |
---|
| 146 | } |
---|
| 147 | else if (argis("N", "network")) { |
---|
| 148 | if (arg - argv < argc - 1) { |
---|
| 149 | arg++; |
---|
| 150 | update_flag++; |
---|
| 151 | network = *arg; |
---|
| 152 | } else |
---|
| 153 | usage(argv); |
---|
| 154 | } |
---|
| 155 | else if (argis("S", "status")) { |
---|
| 156 | if (arg - argv < argc - 1) { |
---|
| 157 | int i; |
---|
| 158 | int len; |
---|
| 159 | |
---|
| 160 | arg++; |
---|
| 161 | update_flag++; |
---|
| 162 | h_status = *arg; |
---|
| 163 | |
---|
| 164 | len = strlen(h_status); |
---|
| 165 | for(i = 0; i < len; i++) { |
---|
| 166 | if(!isdigit(h_status[i])) { |
---|
| 167 | printf("Error: status code %s is not numeric.\n", h_status); |
---|
| 168 | exit(1); |
---|
| 169 | } |
---|
| 170 | } |
---|
| 171 | } else |
---|
| 172 | usage(argv); |
---|
| 173 | } |
---|
| 174 | else if (argis("V", "vendor")) { |
---|
| 175 | if (arg - argv < argc - 1) { |
---|
| 176 | arg++; |
---|
| 177 | update_flag++; |
---|
| 178 | vendor = *arg; |
---|
| 179 | } else |
---|
| 180 | usage(argv); |
---|
| 181 | } |
---|
| 182 | else if (argis("M", "model")) { |
---|
| 183 | if (arg - argv < argc - 1) { |
---|
| 184 | arg++; |
---|
| 185 | update_flag++; |
---|
| 186 | model = *arg; |
---|
| 187 | } else |
---|
| 188 | usage(argv); |
---|
| 189 | } |
---|
| 190 | else if (argis("o", "os")) { |
---|
| 191 | if (arg - argv < argc - 1) { |
---|
| 192 | arg++; |
---|
| 193 | update_flag++; |
---|
| 194 | os = *arg; |
---|
| 195 | } else |
---|
| 196 | usage(argv); |
---|
| 197 | } |
---|
| 198 | else if (argis("L", "location")) { |
---|
| 199 | if (arg - argv < argc - 1) { |
---|
| 200 | arg++; |
---|
| 201 | update_flag++; |
---|
| 202 | location = *arg; |
---|
| 203 | } else |
---|
| 204 | usage(argv); |
---|
| 205 | } |
---|
| 206 | else if (argis("c", "contact")) { |
---|
| 207 | if (arg - argv < argc - 1) { |
---|
| 208 | arg++; |
---|
| 209 | update_flag++; |
---|
| 210 | contact = *arg; |
---|
| 211 | } else |
---|
| 212 | usage(argv); |
---|
| 213 | } |
---|
| 214 | else if (argis("bc", "billingcontact")) { |
---|
| 215 | if (arg - argv < argc - 1) { |
---|
| 216 | arg++; |
---|
| 217 | update_flag++; |
---|
| 218 | billing_contact = *arg; |
---|
| 219 | } else |
---|
| 220 | usage(argv); |
---|
| 221 | } |
---|
| 222 | else if (argis("an", "accountnumber")) { |
---|
| 223 | if (arg - argv < argc - 1) { |
---|
| 224 | arg++; |
---|
| 225 | update_flag++; |
---|
| 226 | account_number = *arg; |
---|
| 227 | } else |
---|
| 228 | usage(argv); |
---|
| 229 | } |
---|
| 230 | else if (argis("ac", "admcmt")) { |
---|
| 231 | if (arg - argv < argc - 1) { |
---|
| 232 | arg++; |
---|
| 233 | update_flag++; |
---|
| 234 | adm_cmt = *arg; |
---|
| 235 | } else |
---|
| 236 | usage(argv); |
---|
| 237 | } |
---|
| 238 | else if (argis("oc", "opcmt")) { |
---|
| 239 | if (arg - argv < argc - 1) { |
---|
| 240 | arg++; |
---|
| 241 | update_flag++; |
---|
| 242 | op_cmt = *arg; |
---|
| 243 | } else |
---|
| 244 | usage(argv); |
---|
| 245 | } |
---|
| 246 | else if (argis("a", "addalias")) { |
---|
| 247 | if (arg - argv < argc - 1) { |
---|
| 248 | arg++; |
---|
| 249 | alias_add_queue=add_to_string_list(alias_add_queue, *arg); |
---|
| 250 | } else |
---|
| 251 | usage(argv); |
---|
| 252 | update_alias_flag++; |
---|
| 253 | } |
---|
| 254 | else if (argis("d", "deletealias")) { |
---|
| 255 | if (arg - argv < argc - 1) { |
---|
| 256 | arg++; |
---|
| 257 | alias_remove_queue=add_to_string_list(alias_remove_queue, *arg); |
---|
| 258 | } else |
---|
| 259 | usage(argv); |
---|
| 260 | update_alias_flag++; |
---|
| 261 | } |
---|
| 262 | else if (argis("am", "addmap")) { |
---|
| 263 | if (arg - argv < argc - 1) { |
---|
| 264 | arg++; |
---|
| 265 | map_add_queue=add_to_string_list(map_add_queue, *arg); |
---|
| 266 | } else |
---|
| 267 | usage(argv); |
---|
| 268 | update_map_flag++; |
---|
| 269 | } |
---|
| 270 | else if (argis("dm", "deletemap")) { |
---|
| 271 | if (arg - argv < argc - 1) { |
---|
| 272 | arg++; |
---|
| 273 | map_remove_queue=add_to_string_list(map_remove_queue, *arg); |
---|
| 274 | } else |
---|
| 275 | usage(argv); |
---|
| 276 | update_map_flag++; |
---|
| 277 | } |
---|
| 278 | else if (argis("lm", "listmap")) |
---|
| 279 | list_map_flag++; |
---|
| 280 | else if (argis("acn", "addcontainer")) { |
---|
| 281 | if (arg - argv < argc - 1) { |
---|
| 282 | arg++; |
---|
| 283 | container_add_queue = |
---|
| 284 | add_to_string_list(container_add_queue, *arg); |
---|
| 285 | } else |
---|
| 286 | usage(argv); |
---|
| 287 | update_container_flag++; |
---|
| 288 | } |
---|
| 289 | else if (argis("dcn", "deletecontainer")) { |
---|
| 290 | if (arg - argv < argc - 1) { |
---|
| 291 | arg++; |
---|
| 292 | container_remove_queue = |
---|
| 293 | add_to_string_list(container_remove_queue, *arg); |
---|
| 294 | } else |
---|
| 295 | usage(argv); |
---|
| 296 | update_container_flag++; |
---|
| 297 | } |
---|
| 298 | else if (argis("lcn", "listcontainer")) |
---|
| 299 | list_container_flag++; |
---|
| 300 | else if (argis("u", "unformatted")) |
---|
| 301 | unformatted_flag++; |
---|
| 302 | else if (argis("n", "noauth")) |
---|
| 303 | noauth++; |
---|
| 304 | else if (argis("v", "verbose")) |
---|
| 305 | verbose++; |
---|
| 306 | else if (argis("db", "database")) |
---|
| 307 | { |
---|
| 308 | if (arg - argv < argc - 1) |
---|
| 309 | { |
---|
| 310 | ++arg; |
---|
| 311 | server = *arg; |
---|
| 312 | } |
---|
| 313 | else |
---|
| 314 | usage(argv); |
---|
| 315 | } |
---|
| 316 | else |
---|
| 317 | usage(argv); |
---|
| 318 | } |
---|
| 319 | else if (hostname == NULL) |
---|
| 320 | hostname = *arg; |
---|
| 321 | else |
---|
| 322 | usage(argv); |
---|
| 323 | } |
---|
| 324 | if (hostname == NULL) |
---|
| 325 | usage(argv); |
---|
| 326 | |
---|
| 327 | /* default to info_flag if nothing else was specified */ |
---|
| 328 | if(!(info_flag || update_flag || create_flag || \ |
---|
| 329 | delete_flag || list_map_flag || update_map_flag || \ |
---|
| 330 | update_alias_flag || update_container_flag || \ |
---|
| 331 | list_container_flag)) { |
---|
| 332 | info_flag++; |
---|
| 333 | } |
---|
| 334 | |
---|
| 335 | /* fire up Moira */ |
---|
| 336 | status = mrcl_connect(server, "stella", 8, !noauth); |
---|
| 337 | if (status == MRCL_AUTH_ERROR) |
---|
| 338 | { |
---|
| 339 | com_err(whoami, 0, "Try the -noauth flag if you don't " |
---|
| 340 | "need authentication."); |
---|
| 341 | } |
---|
| 342 | if (status) |
---|
| 343 | exit(2); |
---|
| 344 | |
---|
| 345 | /* Perform the lookup by IP address if that's what we've been handed */ |
---|
| 346 | if ((ipaddress=inet_addr(hostname)) != -1) { |
---|
| 347 | char *args[5]; |
---|
| 348 | char *argv[30]; |
---|
| 349 | |
---|
| 350 | args[1] = strdup(hostname); |
---|
| 351 | args[0] = args[2] = args[3] = "*"; |
---|
| 352 | status = wrap_mr_query("get_host", 4, args, store_host_info, argv); |
---|
| 353 | |
---|
| 354 | if (status) { |
---|
| 355 | com_err(whoami, status, "while looking up IP address."); |
---|
| 356 | } else { |
---|
| 357 | hostname = argv[0]; |
---|
| 358 | } |
---|
| 359 | } |
---|
| 360 | |
---|
| 361 | /* create if needed */ |
---|
| 362 | if (create_flag) |
---|
| 363 | { |
---|
| 364 | char *argv[30]; |
---|
| 365 | int cnt; |
---|
| 366 | |
---|
| 367 | for (cnt = 0; cnt < 17; cnt++) { |
---|
| 368 | argv[cnt] = ""; |
---|
| 369 | } |
---|
| 370 | |
---|
| 371 | argv[0] = canonicalize_hostname(strdup(hostname)); |
---|
| 372 | |
---|
| 373 | if (vendor) |
---|
| 374 | argv[1] = vendor; |
---|
| 375 | if (model) |
---|
| 376 | argv[2] = model; |
---|
| 377 | if (os) |
---|
| 378 | argv[3] = os; |
---|
| 379 | if (location) |
---|
| 380 | argv[4] = location; |
---|
| 381 | if (contact) |
---|
| 382 | argv[5] = contact; |
---|
| 383 | if (billing_contact) |
---|
| 384 | argv[6] = billing_contact; |
---|
| 385 | if (account_number) |
---|
| 386 | argv[7] = account_number; |
---|
| 387 | /* The use field always gets set to "0" */ |
---|
| 388 | argv[8] = "0"; |
---|
| 389 | if (h_status) |
---|
| 390 | argv[9] = h_status; |
---|
| 391 | else |
---|
| 392 | argv[9] = "1"; |
---|
| 393 | if (network) |
---|
| 394 | argv[10] = network; |
---|
| 395 | if (address) |
---|
| 396 | argv[11] = address; |
---|
| 397 | else |
---|
| 398 | argv[11] = "unique"; |
---|
| 399 | if (adm_cmt) |
---|
| 400 | argv[14] = adm_cmt; |
---|
| 401 | if (op_cmt) |
---|
| 402 | argv[15] = op_cmt; |
---|
| 403 | |
---|
| 404 | if (owner) |
---|
| 405 | { |
---|
| 406 | argv[13] = owner->name; |
---|
| 407 | switch (owner->type) |
---|
| 408 | { |
---|
| 409 | case M_ANY: |
---|
| 410 | case M_USER: |
---|
| 411 | argv[12] = "USER"; |
---|
| 412 | status = wrap_mr_query("add_host", 16, argv, NULL, NULL); |
---|
| 413 | if (owner->type != M_ANY || status != MR_USER) |
---|
| 414 | break; |
---|
| 415 | |
---|
| 416 | case M_LIST: |
---|
| 417 | argv[12] = "LIST"; |
---|
| 418 | status = wrap_mr_query("add_host", 16, argv, NULL, NULL); |
---|
| 419 | break; |
---|
| 420 | |
---|
| 421 | case M_KERBEROS: |
---|
| 422 | argv[12] = "KERBEROS"; |
---|
| 423 | status = mrcl_validate_kerberos_member(argv[13], &argv[13]); |
---|
| 424 | if (mrcl_get_message()) |
---|
| 425 | mrcl_com_err(whoami); |
---|
| 426 | if (status == MRCL_REJECT) |
---|
| 427 | exit(1); |
---|
| 428 | status = wrap_mr_query("add_host", 16, argv, NULL, NULL); |
---|
| 429 | break; |
---|
| 430 | |
---|
| 431 | case M_NONE: |
---|
| 432 | argv[12] = "NONE"; |
---|
| 433 | status = wrap_mr_query("add_host", 16, argv, NULL, NULL); |
---|
| 434 | break; |
---|
| 435 | } |
---|
| 436 | } |
---|
| 437 | else |
---|
| 438 | { |
---|
| 439 | argv[12] = "NONE"; |
---|
| 440 | argv[13] = "NONE"; |
---|
| 441 | |
---|
| 442 | status = wrap_mr_query("add_host", 16, argv, NULL, NULL); |
---|
| 443 | } |
---|
| 444 | |
---|
| 445 | if (status) |
---|
| 446 | { |
---|
| 447 | com_err(whoami, status, "while creating host."); |
---|
| 448 | exit(1); |
---|
| 449 | } |
---|
| 450 | |
---|
| 451 | } |
---|
| 452 | else if (update_flag) |
---|
| 453 | { |
---|
| 454 | char *old_argv[30]; |
---|
| 455 | char *argv[17]; |
---|
| 456 | char *args[5]; |
---|
| 457 | |
---|
| 458 | args[0] = canonicalize_hostname(strdup(hostname)); |
---|
| 459 | args[1] = args[2] = args[3] = "*"; |
---|
| 460 | |
---|
| 461 | status = wrap_mr_query("get_host", 4, args, store_host_info, old_argv); |
---|
| 462 | if (status) |
---|
| 463 | { |
---|
| 464 | com_err(whoami, status, "while getting list information"); |
---|
| 465 | exit(1); |
---|
| 466 | } |
---|
| 467 | |
---|
| 468 | argv[1] = old_argv[0]; |
---|
| 469 | argv[2] = old_argv[1]; |
---|
| 470 | argv[3] = old_argv[2]; |
---|
| 471 | argv[4] = old_argv[3]; |
---|
| 472 | argv[5] = old_argv[4]; |
---|
| 473 | argv[6] = old_argv[5]; |
---|
| 474 | argv[7] = old_argv[6]; |
---|
| 475 | argv[8] = old_argv[7]; |
---|
| 476 | argv[9] = old_argv[8]; |
---|
| 477 | argv[10] = old_argv[9]; |
---|
| 478 | argv[11] = old_argv[11]; |
---|
| 479 | argv[12] = old_argv[12]; |
---|
| 480 | argv[13] = old_argv[13]; |
---|
| 481 | argv[14] = old_argv[14]; |
---|
| 482 | argv[15] = old_argv[15]; |
---|
| 483 | argv[16] = old_argv[16]; |
---|
| 484 | |
---|
| 485 | argv[0] = canonicalize_hostname(strdup(hostname)); |
---|
| 486 | if (newname) |
---|
| 487 | argv[1] = canonicalize_hostname(strdup(newname)); |
---|
| 488 | if (vendor) |
---|
| 489 | argv[2] = vendor; |
---|
| 490 | if (model) |
---|
| 491 | argv[3] = model; |
---|
| 492 | if (os) |
---|
| 493 | argv[4] = os; |
---|
| 494 | if (location) |
---|
| 495 | argv[5] = location; |
---|
| 496 | if (contact) |
---|
| 497 | argv[6] = contact; |
---|
| 498 | if (billing_contact) |
---|
| 499 | argv[7] = billing_contact; |
---|
| 500 | if (account_number) |
---|
| 501 | argv[8] = account_number; |
---|
| 502 | if (h_status) |
---|
| 503 | argv[10] = h_status; |
---|
| 504 | if (network) |
---|
| 505 | argv[11] = network; |
---|
| 506 | if (address) |
---|
| 507 | argv[12] = address; |
---|
| 508 | if (adm_cmt) |
---|
| 509 | argv[15] = adm_cmt; |
---|
| 510 | if (op_cmt) |
---|
| 511 | argv[16] = op_cmt; |
---|
| 512 | |
---|
| 513 | if (owner) |
---|
| 514 | { |
---|
| 515 | argv[14] = owner->name; |
---|
| 516 | switch (owner->type) |
---|
| 517 | { |
---|
| 518 | case M_ANY: |
---|
| 519 | case M_USER: |
---|
| 520 | argv[13] = "USER"; |
---|
| 521 | status = wrap_mr_query("update_host", 17, argv, NULL, NULL); |
---|
| 522 | if (owner->type != M_ANY || status != MR_USER) |
---|
| 523 | break; |
---|
| 524 | |
---|
| 525 | case M_LIST: |
---|
| 526 | argv[13] = "LIST"; |
---|
| 527 | status = wrap_mr_query("update_host", 17, argv, NULL, NULL); |
---|
| 528 | break; |
---|
| 529 | |
---|
| 530 | case M_KERBEROS: |
---|
| 531 | argv[13] = "KERBEROS"; |
---|
| 532 | status = mrcl_validate_kerberos_member(argv[14], &argv[14]); |
---|
| 533 | if (mrcl_get_message()) |
---|
| 534 | mrcl_com_err(whoami); |
---|
| 535 | if (status == MRCL_REJECT) |
---|
| 536 | exit(1); |
---|
| 537 | status = wrap_mr_query("update_host", 17, argv, NULL, NULL); |
---|
| 538 | break; |
---|
| 539 | |
---|
| 540 | case M_NONE: |
---|
| 541 | argv[13] = "NONE"; |
---|
| 542 | status = wrap_mr_query("update_host", 17, argv, NULL, NULL); |
---|
| 543 | break; |
---|
| 544 | } |
---|
| 545 | } |
---|
| 546 | else |
---|
| 547 | status = wrap_mr_query("update_host", 17, argv, NULL, NULL); |
---|
| 548 | |
---|
| 549 | if (status) |
---|
| 550 | com_err(whoami, status, "while updating host."); |
---|
| 551 | else if (newname) |
---|
| 552 | hostname = newname; |
---|
| 553 | } |
---|
| 554 | |
---|
| 555 | /* create aliases if necessary */ |
---|
| 556 | if (alias_add_queue) { |
---|
| 557 | struct string_list *q = alias_add_queue; |
---|
| 558 | |
---|
| 559 | while(q) { |
---|
| 560 | char *alias = q->string; |
---|
| 561 | char *args[2]; |
---|
| 562 | |
---|
| 563 | args[0] = partial_canonicalize_hostname(strdup(alias)); |
---|
| 564 | args[1] = canonicalize_hostname(strdup(hostname)); |
---|
| 565 | status = wrap_mr_query("add_hostalias", 2, args, NULL, NULL); |
---|
| 566 | if (status) { |
---|
| 567 | com_err(whoami, status, "while adding host alias"); |
---|
| 568 | exit(1); |
---|
| 569 | } |
---|
| 570 | |
---|
| 571 | q = q->next; |
---|
| 572 | } |
---|
| 573 | } |
---|
| 574 | |
---|
| 575 | /* delete aliases if necessary */ |
---|
| 576 | if (alias_remove_queue) { |
---|
| 577 | struct string_list *q = alias_remove_queue; |
---|
| 578 | |
---|
| 579 | while(q) { |
---|
| 580 | char *alias = q->string; |
---|
| 581 | char *args[2]; |
---|
| 582 | |
---|
| 583 | args[0] = partial_canonicalize_hostname(strdup(alias)); |
---|
| 584 | args[1] = canonicalize_hostname(strdup(hostname)); |
---|
| 585 | status = wrap_mr_query("delete_hostalias", 2, args, NULL, NULL); |
---|
| 586 | if (status) { |
---|
| 587 | com_err(whoami, status, "while deleting host alias"); |
---|
| 588 | exit(1); |
---|
| 589 | } |
---|
| 590 | |
---|
| 591 | q = q->next; |
---|
| 592 | } |
---|
| 593 | } |
---|
| 594 | |
---|
| 595 | /* create cluster mappings */ |
---|
| 596 | if (map_add_queue) { |
---|
| 597 | struct string_list *q = map_add_queue; |
---|
| 598 | |
---|
| 599 | while(q) { |
---|
| 600 | char *clustername = q->string; |
---|
| 601 | char *args[2]; |
---|
| 602 | |
---|
| 603 | args[0] = canonicalize_hostname(strdup(hostname)); |
---|
| 604 | args[1] = clustername; |
---|
| 605 | status = wrap_mr_query("add_machine_to_cluster", 2, args, NULL, NULL); |
---|
| 606 | if (status) { |
---|
| 607 | com_err(whoami, status, "while adding cluster mapping"); |
---|
| 608 | exit(1); |
---|
| 609 | } |
---|
| 610 | |
---|
| 611 | q = q->next; |
---|
| 612 | } |
---|
| 613 | } |
---|
| 614 | |
---|
| 615 | /* delete cluster mappings */ |
---|
| 616 | if (map_remove_queue) { |
---|
| 617 | struct string_list *q = map_remove_queue; |
---|
| 618 | |
---|
| 619 | while(q) { |
---|
| 620 | char *clustername = q->string; |
---|
| 621 | char *args[2]; |
---|
| 622 | |
---|
| 623 | args[0] = canonicalize_hostname(strdup(hostname)); |
---|
| 624 | args[1] = clustername; |
---|
| 625 | status = wrap_mr_query("delete_machine_from_cluster", 2, args, |
---|
| 626 | NULL, NULL); |
---|
| 627 | if (status) { |
---|
| 628 | com_err(whoami, status, "while deleting cluster mapping"); |
---|
| 629 | exit(1); |
---|
| 630 | } |
---|
| 631 | |
---|
| 632 | q = q->next; |
---|
| 633 | } |
---|
| 634 | } |
---|
| 635 | |
---|
| 636 | /* add container mappings */ |
---|
| 637 | if (container_add_queue) { |
---|
| 638 | struct string_list *q = container_add_queue; |
---|
| 639 | |
---|
| 640 | while (q) { |
---|
| 641 | char *containername = q->string; |
---|
| 642 | char *args[2]; |
---|
| 643 | |
---|
| 644 | args[0] = canonicalize_hostname(strdup(hostname)); |
---|
| 645 | args[1] = containername; |
---|
| 646 | status = wrap_mr_query("add_machine_to_container", 2, args, |
---|
| 647 | NULL, NULL); |
---|
| 648 | |
---|
| 649 | if (status) { |
---|
| 650 | com_err(whoami, status, "while adding container mapping"); |
---|
| 651 | exit(1); |
---|
| 652 | } |
---|
| 653 | |
---|
| 654 | q = q->next; |
---|
| 655 | } |
---|
| 656 | } |
---|
| 657 | |
---|
| 658 | /* delete container mappings */ |
---|
| 659 | if (container_remove_queue) { |
---|
| 660 | struct string_list *q = container_remove_queue; |
---|
| 661 | |
---|
| 662 | while (q) { |
---|
| 663 | char *containername = q->string; |
---|
| 664 | char *args[2]; |
---|
| 665 | |
---|
| 666 | args[0] = canonicalize_hostname(strdup(hostname)); |
---|
| 667 | args[1] = containername; |
---|
| 668 | status = wrap_mr_query("delete_machine_from_container", 2, args, |
---|
| 669 | NULL, NULL); |
---|
| 670 | |
---|
| 671 | if (status) { |
---|
| 672 | com_err(whoami, status, "while deleting container mapping"); |
---|
| 673 | exit(1); |
---|
| 674 | } |
---|
| 675 | |
---|
| 676 | q = q->next; |
---|
| 677 | } |
---|
| 678 | } |
---|
| 679 | |
---|
| 680 | /* display list info if requested to */ |
---|
| 681 | if (info_flag) { |
---|
| 682 | struct mqelem *elem = NULL; |
---|
| 683 | char *args[5]; |
---|
| 684 | char *argv[30]; |
---|
| 685 | |
---|
| 686 | args[0] = canonicalize_hostname(strdup(hostname)); |
---|
| 687 | args[1] = args[2] = args[3] = "*"; |
---|
| 688 | status = wrap_mr_query("get_host", 4, args, store_host_info, argv); |
---|
| 689 | if (status) { |
---|
| 690 | com_err(whoami, status, "while getting host information"); |
---|
| 691 | exit(1); |
---|
| 692 | } |
---|
| 693 | if (unformatted_flag) |
---|
| 694 | show_host_info_unformatted(argv); |
---|
| 695 | else |
---|
| 696 | show_host_info(argv); |
---|
| 697 | args[0] = argv[M_SUBNET]; |
---|
| 698 | status = wrap_mr_query("get_subnet", 1, args, store_host_info, argv); |
---|
| 699 | if (status) |
---|
| 700 | com_err(whoami, status, "while getting subnet information"); |
---|
| 701 | if (atoi(argv[SN_STATUS]) == SNET_STATUS_PRIVATE_10MBPS || |
---|
| 702 | atoi(argv[SN_STATUS]) == SNET_STATUS_PRIVATE_100MBPS || |
---|
| 703 | atoi(argv[SN_STATUS]) == SNET_STATUS_PRIVATE_1000MBPS) |
---|
| 704 | { |
---|
| 705 | fprintf(stderr, "\nWarning: This host is on a private subnet.\n"); |
---|
| 706 | fprintf(stderr, "Billing information shown is superseded by billing information for the subnet.\n"); |
---|
| 707 | } |
---|
| 708 | } |
---|
| 709 | |
---|
| 710 | /* list cluster mappings if needed */ |
---|
| 711 | if (list_map_flag) { |
---|
| 712 | char *args[3]; |
---|
| 713 | |
---|
| 714 | args[0] = canonicalize_hostname(strdup(hostname)); |
---|
| 715 | args[1] = "*"; |
---|
| 716 | status = wrap_mr_query("get_machine_to_cluster_map", 2, args, |
---|
| 717 | show_machine_in_cluster, NULL); |
---|
| 718 | if (status) |
---|
| 719 | if (status != MR_NO_MATCH) { |
---|
| 720 | com_err(whoami, status, "while getting cluster mappings"); |
---|
| 721 | exit(1); |
---|
| 722 | } |
---|
| 723 | } |
---|
| 724 | |
---|
| 725 | /* list container mappings if needed */ |
---|
| 726 | if (list_container_flag) { |
---|
| 727 | char *argv[1]; |
---|
| 728 | |
---|
| 729 | argv[0] = canonicalize_hostname(strdup(hostname)); |
---|
| 730 | status = wrap_mr_query("get_machine_to_container_map", 1, argv, |
---|
| 731 | show_machine_in_container, NULL); |
---|
| 732 | |
---|
| 733 | if (status) |
---|
| 734 | if (status != MR_NO_MATCH) { |
---|
| 735 | com_err(whoami, status, "while getting container mappings"); |
---|
| 736 | exit(1); |
---|
| 737 | } |
---|
| 738 | } |
---|
| 739 | |
---|
| 740 | if (delete_flag) { |
---|
| 741 | char *argv[1]; |
---|
| 742 | |
---|
| 743 | argv[0] = canonicalize_hostname(strdup(hostname)); |
---|
| 744 | status = wrap_mr_query("delete_host", 1, argv, NULL, NULL); |
---|
| 745 | if (status) { |
---|
| 746 | com_err(whoami, status, "while deleting host"); |
---|
| 747 | exit(1); |
---|
| 748 | } |
---|
| 749 | } |
---|
| 750 | |
---|
| 751 | /* We're done! */ |
---|
| 752 | mr_disconnect(); |
---|
| 753 | exit(success ? 0 : 1); |
---|
| 754 | } |
---|
| 755 | |
---|
| 756 | void usage(char **argv) |
---|
| 757 | { |
---|
| 758 | #define USAGE_OPTIONS_FORMAT " %-39s%s\n" |
---|
| 759 | fprintf(stderr, "Usage: %s hostname [options]\n", argv[0]); |
---|
| 760 | fprintf(stderr, "Options are\n"); |
---|
| 761 | fprintf(stderr, USAGE_OPTIONS_FORMAT, "-C | -create", |
---|
| 762 | "-O | -owner owner"); |
---|
| 763 | fprintf(stderr, USAGE_OPTIONS_FORMAT, "-D | -delete", |
---|
| 764 | "-S | -status status"); |
---|
| 765 | fprintf(stderr, USAGE_OPTIONS_FORMAT, "-R | -rename newname", |
---|
| 766 | "-V | -vendor vendor"); |
---|
| 767 | fprintf(stderr, USAGE_OPTIONS_FORMAT, "-a | -addalias alias", |
---|
| 768 | "-M | -model model"); |
---|
| 769 | fprintf(stderr, USAGE_OPTIONS_FORMAT, "-d | -deletealias alias", |
---|
| 770 | "-L | -location location"); |
---|
| 771 | fprintf(stderr, USAGE_OPTIONS_FORMAT, "-i | -info", |
---|
| 772 | "-o | -os os"); |
---|
| 773 | fprintf(stderr, USAGE_OPTIONS_FORMAT, "-oc | -opcmt op_cmt", |
---|
| 774 | "-c | -contact contact"); |
---|
| 775 | fprintf(stderr, USAGE_OPTIONS_FORMAT, "-ac | -admcmt adm_cmt", |
---|
| 776 | "-bc | -billingcontact billing_contact"); |
---|
| 777 | fprintf(stderr, USAGE_OPTIONS_FORMAT, "-an | -accountnumber account_number", "-A | -address address"); |
---|
| 778 | fprintf(stderr, USAGE_OPTIONS_FORMAT, "-N | -network network", |
---|
| 779 | "-am | -addmap cluster"); |
---|
| 780 | fprintf(stderr, USAGE_OPTIONS_FORMAT, "-dm | deletemap cluster", |
---|
| 781 | "-acn | -addcontainer container"); |
---|
| 782 | fprintf(stderr, USAGE_OPTIONS_FORMAT, "-dcn | -deletecontainer container", |
---|
| 783 | "-lm | -listmap"); |
---|
| 784 | fprintf(stderr, USAGE_OPTIONS_FORMAT, "-lcn | -listcontainer", |
---|
| 785 | "-u | -unformatted"); |
---|
| 786 | fprintf(stderr, USAGE_OPTIONS_FORMAT, "-v | -verbose", |
---|
| 787 | "-n | -noauth"); |
---|
| 788 | fprintf(stderr, " %-39s\n" , "-db | -database host[:port]"); |
---|
| 789 | exit(1); |
---|
| 790 | } |
---|
| 791 | |
---|
| 792 | /* Show alias information */ |
---|
| 793 | |
---|
| 794 | static int show_has_aliases; |
---|
| 795 | |
---|
| 796 | int show_alias_info(int argc, char **argv, void *hint) |
---|
| 797 | { |
---|
| 798 | if(!show_has_aliases++) |
---|
| 799 | printf("Aliases: %s", argv[0]); |
---|
| 800 | else |
---|
| 801 | printf(", %s", argv[0]); |
---|
| 802 | |
---|
| 803 | return MR_CONT; |
---|
| 804 | } |
---|
| 805 | |
---|
| 806 | int show_alias_info_unformatted(int argc, char **argv, void *hint) |
---|
| 807 | { |
---|
| 808 | if(!show_has_aliases++) |
---|
| 809 | printf("Alias: %s", argv[0]); |
---|
| 810 | else |
---|
| 811 | printf(", %s", argv[0]); |
---|
| 812 | |
---|
| 813 | return MR_CONT; |
---|
| 814 | } |
---|
| 815 | |
---|
| 816 | static char *states[] = { |
---|
| 817 | "Reserved (0)", |
---|
| 818 | "Active (1)", |
---|
| 819 | "None (2)", |
---|
| 820 | "Deleted (3)" |
---|
| 821 | }; |
---|
| 822 | |
---|
| 823 | static char *MacState(int state) |
---|
| 824 | { |
---|
| 825 | static char buf[BUFSIZ]; |
---|
| 826 | |
---|
| 827 | if (state < 0 || state > 3) |
---|
| 828 | { |
---|
| 829 | sprintf(buf, "Unknown (%d)", state); |
---|
| 830 | return buf; |
---|
| 831 | } |
---|
| 832 | return states[state]; |
---|
| 833 | } |
---|
| 834 | |
---|
| 835 | /* Retrieve information about a host */ |
---|
| 836 | |
---|
| 837 | int store_host_info(int argc, char **argv, void *hint) |
---|
| 838 | { |
---|
| 839 | int i; |
---|
| 840 | char **nargv = hint; |
---|
| 841 | |
---|
| 842 | for(i=0; i<argc; i++) |
---|
| 843 | nargv[i] = strdup(argv[i]); |
---|
| 844 | |
---|
| 845 | return MR_CONT; |
---|
| 846 | } |
---|
| 847 | |
---|
| 848 | void show_host_info(char **argv) |
---|
| 849 | { |
---|
| 850 | char tbuf[256]; |
---|
| 851 | char *args[3]; |
---|
| 852 | struct mqelem *elem = NULL; |
---|
| 853 | int stat; |
---|
| 854 | |
---|
| 855 | printf("Machine: %s\n", argv[M_NAME]); |
---|
| 856 | args[0] = "*"; |
---|
| 857 | args[1] = argv[M_NAME]; |
---|
| 858 | show_has_aliases = 0; |
---|
| 859 | stat = wrap_mr_query("get_hostalias", 2, args, show_alias_info, &elem); |
---|
| 860 | printf("\n"); |
---|
| 861 | if (stat) { |
---|
| 862 | if (stat != MR_NO_MATCH) |
---|
| 863 | com_err(whoami, stat, "while getting aliases"); |
---|
| 864 | } else { |
---|
| 865 | printf("\n"); |
---|
| 866 | } |
---|
| 867 | sprintf(tbuf, "%s %s", argv[M_OWNER_TYPE], |
---|
| 868 | strcmp(argv[M_OWNER_TYPE], "NONE") ? argv[M_OWNER_NAME] : ""); |
---|
| 869 | printf("Address: %-16s Network: %-16s\n", |
---|
| 870 | argv[M_ADDR], argv[M_SUBNET]); |
---|
| 871 | printf("Owner: %-16s Use data: %s\n", tbuf, argv[M_INUSE]); |
---|
| 872 | printf("Status: %-16s Changed: %s\n", |
---|
| 873 | MacState(atoi(argv[M_STAT])), argv[M_STAT_CHNG]); |
---|
| 874 | printf("\n"); |
---|
| 875 | printf("Vendor: %-16s Location: %s\n", argv[M_VENDOR], |
---|
| 876 | argv[M_LOC]); |
---|
| 877 | printf("Model: %-16s Contact: %s\n", argv[M_MODEL], |
---|
| 878 | argv[M_CONTACT]); |
---|
| 879 | printf("OS: %-16s Billing Contact: %s\n", argv[M_OS], |
---|
| 880 | argv[M_BILL_CONTACT]); |
---|
| 881 | printf("Opt: %-16s Account Number: %s\n", argv[M_USE], |
---|
| 882 | argv[M_ACCT_NUMBER]); |
---|
| 883 | printf("\nAdm cmt: %s\n", argv[M_ACOMMENT]); |
---|
| 884 | printf("Op cmt: %s\n", argv[M_OCOMMENT]); |
---|
| 885 | printf("\n"); |
---|
| 886 | printf("Created by %s on %s\n", argv[M_CREATOR], argv[M_CREATED]); |
---|
| 887 | printf("Last mod by %s at %s with %s.\n", argv[M_MODBY], argv[M_MODTIME], argv[M_MODWITH]); |
---|
| 888 | } |
---|
| 889 | |
---|
| 890 | void show_host_info_unformatted(char **argv) |
---|
| 891 | { |
---|
| 892 | char *args[3]; |
---|
| 893 | struct mqelem *elem = NULL; |
---|
| 894 | int stat; |
---|
| 895 | |
---|
| 896 | printf("Machine: %s\n", argv[M_NAME]); |
---|
| 897 | args[0] = "*"; |
---|
| 898 | args[1] = argv[M_NAME]; |
---|
| 899 | show_has_aliases = 0; |
---|
| 900 | stat = wrap_mr_query("get_hostalias", 2, args, show_alias_info_unformatted, |
---|
| 901 | &elem); |
---|
| 902 | if (stat && stat != MR_NO_MATCH) |
---|
| 903 | com_err(whoami, stat, "while getting aliases"); |
---|
| 904 | else |
---|
| 905 | printf("\n"); |
---|
| 906 | printf("Address: %s\n", argv[M_ADDR]); |
---|
| 907 | printf("Network: %s\n", argv[M_SUBNET]); |
---|
| 908 | printf("Owner Type: %s\n", argv[M_OWNER_TYPE]); |
---|
| 909 | printf("Owner: %s\n", argv[M_OWNER_NAME]); |
---|
| 910 | printf("Status: %s\n", MacState(atoi(argv[M_STAT]))); |
---|
| 911 | printf("Changed: %s\n", argv[M_STAT_CHNG]); |
---|
| 912 | printf("Use data: %s\n", argv[M_INUSE]); |
---|
| 913 | printf("Vendor: %s\n", argv[M_VENDOR]); |
---|
| 914 | printf("Model: %s\n", argv[M_MODEL]); |
---|
| 915 | printf("OS: %s\n", argv[M_OS]); |
---|
| 916 | printf("Location: %s\n", argv[M_LOC]); |
---|
| 917 | printf("Contact: %s\n", argv[M_CONTACT]); |
---|
| 918 | printf("Billing Contact: %s\n", argv[M_BILL_CONTACT]); |
---|
| 919 | printf("Account Number: %s\n", argv[M_ACCT_NUMBER]); |
---|
| 920 | printf("Opt: %s\n", argv[M_USE]); |
---|
| 921 | printf("Adm cmt: %s\n", argv[M_ACOMMENT]); |
---|
| 922 | printf("Op cmt: %s\n", argv[M_OCOMMENT]); |
---|
| 923 | printf("Created by: %s\n", argv[M_CREATOR]); |
---|
| 924 | printf("Created on: %s\n", argv[M_CREATED]); |
---|
| 925 | printf("Last mod by: %s\n", argv[M_MODBY]); |
---|
| 926 | printf("Last mod on: %s\n", argv[M_MODTIME]); |
---|
| 927 | printf("Last mod with: %s\n", argv[M_MODWITH]); |
---|
| 928 | } |
---|
| 929 | |
---|
| 930 | int show_machine_in_cluster(int argc, char **argv, void *hint) |
---|
| 931 | { |
---|
| 932 | printf("Machine: %-30s Cluster: %-30s\n", argv[0], argv[1]); |
---|
| 933 | |
---|
| 934 | return MR_CONT; |
---|
| 935 | } |
---|
| 936 | |
---|
| 937 | int show_machine_in_container(int argc, char **argv, void *hint) |
---|
| 938 | { |
---|
| 939 | printf("Machine: %-30s Container: %-25s\n", argv[0], argv[1]); |
---|
| 940 | |
---|
| 941 | return MR_CONT; |
---|
| 942 | } |
---|
| 943 | |
---|
| 944 | /* Parse a line of input, fetching a member. NULL is returned if a member |
---|
| 945 | * is not found. ';' is a comment character. |
---|
| 946 | */ |
---|
| 947 | |
---|
| 948 | struct owner_type *parse_member(char *s) |
---|
| 949 | { |
---|
| 950 | struct owner_type *m; |
---|
| 951 | char *p, *lastchar; |
---|
| 952 | |
---|
| 953 | while (*s && isspace(*s)) |
---|
| 954 | s++; |
---|
| 955 | lastchar = p = s; |
---|
| 956 | while (*p && *p != '\n' && *p != ';') |
---|
| 957 | { |
---|
| 958 | if (isprint(*p) && !isspace(*p)) |
---|
| 959 | lastchar = p++; |
---|
| 960 | else |
---|
| 961 | p++; |
---|
| 962 | } |
---|
| 963 | lastchar++; |
---|
| 964 | *lastchar = '\0'; |
---|
| 965 | if (p == s || strlen(s) == 0) |
---|
| 966 | return NULL; |
---|
| 967 | |
---|
| 968 | if (!(m = malloc(sizeof(struct owner_type)))) |
---|
| 969 | return NULL; |
---|
| 970 | |
---|
| 971 | if ((p = strchr(s, ':'))) |
---|
| 972 | { |
---|
| 973 | *p = '\0'; |
---|
| 974 | m->name = ++p; |
---|
| 975 | if (!strcasecmp("user", s)) |
---|
| 976 | m->type = M_USER; |
---|
| 977 | else if (!strcasecmp("list", s)) |
---|
| 978 | m->type = M_LIST; |
---|
| 979 | else if (!strcasecmp("kerberos", s)) |
---|
| 980 | m->type = M_KERBEROS; |
---|
| 981 | else if (!strcasecmp("none", s)) |
---|
| 982 | m->type = M_NONE; |
---|
| 983 | else |
---|
| 984 | { |
---|
| 985 | m->type = M_ANY; |
---|
| 986 | *(--p) = ':'; |
---|
| 987 | m->name = s; |
---|
| 988 | } |
---|
| 989 | m->name = strdup(m->name); |
---|
| 990 | } |
---|
| 991 | else |
---|
| 992 | { |
---|
| 993 | m->name = strdup(s); |
---|
| 994 | m->type = strcasecmp(s, "none") ? M_ANY : M_NONE; |
---|
| 995 | } |
---|
| 996 | return m; |
---|
| 997 | } |
---|
| 998 | |
---|
| 999 | struct string_list *add_to_string_list(struct string_list *old_list, char *s) { |
---|
| 1000 | struct string_list *new_list; |
---|
| 1001 | |
---|
| 1002 | new_list = (struct string_list *)malloc(sizeof(struct string_list *)); |
---|
| 1003 | new_list->next = old_list; |
---|
| 1004 | new_list->string = s; |
---|
| 1005 | |
---|
| 1006 | return new_list; |
---|
| 1007 | } |
---|
| 1008 | |
---|
| 1009 | int wrap_mr_query(char *handle, int argc, char **argv, |
---|
| 1010 | int (*callback)(int, char **, void *), void *callarg) { |
---|
| 1011 | if (verbose) |
---|
| 1012 | print_query(handle, argc, argv); |
---|
| 1013 | |
---|
| 1014 | return mr_query(handle, argc, argv, callback, callarg); |
---|
| 1015 | } |
---|
| 1016 | |
---|
| 1017 | void print_query(char *query_name, int argc, char **argv) { |
---|
| 1018 | int cnt; |
---|
| 1019 | |
---|
| 1020 | printf("qy %s", query_name); |
---|
| 1021 | for(cnt=0; cnt<argc; cnt++) |
---|
| 1022 | printf(" <%s>", argv[cnt]); |
---|
| 1023 | printf("\n"); |
---|
| 1024 | } |
---|