1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 1999-2001 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <stdlib.h> 31 #include <stdio.h> 32 #include <ctype.h> 33 #include <dhcpagent_ipc.h> 34 #include <dhcp_inittab.h> 35 #include <dhcp_symbol.h> 36 37 #define DHCP_INFO_VENDOR_START 256 38 39 static void 40 usage(const char *program) 41 { 42 (void) fprintf(stderr, 43 "usage: %s [-i interface] [-n limit] [-c] code\n" 44 " %s [-i interface] [-n limit] [-c] identifier\n", 45 program, program); 46 47 exit(DHCP_EXIT_BADARGS); 48 } 49 50 int 51 main(int argc, char **argv) 52 { 53 ssize_t max_lines = -1; 54 size_t gran, n_spaces = 0; 55 dhcp_optnum_t optnum; 56 dhcp_ipc_request_t *request; 57 dhcp_ipc_reply_t *reply; 58 int c, error, i; 59 char *ifname = ""; 60 char *value, *valuep; 61 dhcp_symbol_t *entry; 62 DHCP_OPT *opt; 63 size_t opt_len; 64 boolean_t is_canonical = B_FALSE; 65 66 while ((c = getopt(argc, argv, "cn:i:")) != EOF) { 67 68 switch (c) { 69 70 case 'c': 71 is_canonical = B_TRUE; 72 break; 73 74 case 'i': 75 ifname = optarg; 76 break; 77 78 case 'n': 79 max_lines = strtoul(optarg, NULL, 0); 80 break; 81 82 case '?': 83 usage(argv[0]); 84 85 default: 86 break; 87 } 88 } 89 90 if (argc - optind != 1) 91 usage(argv[0]); 92 93 /* 94 * we either have a code or an identifer. if we have a code, 95 * then values over 256 indicate a vendor option. if we have 96 * an identifier, then use inittab_getbyname() to turn the 97 * identifier into a code, then send the request over the wire. 98 */ 99 100 if (isalpha(*argv[optind])) { 101 102 entry = inittab_getbyname(ITAB_CAT_SITE|ITAB_CAT_STANDARD| 103 ITAB_CAT_VENDOR|ITAB_CAT_FIELD, ITAB_CONS_INFO, 104 argv[optind]); 105 106 if (entry == NULL) { 107 (void) fprintf(stderr, "%s: unknown identifier `%s'\n", 108 argv[0], argv[optind]); 109 return (DHCP_EXIT_BADARGS); 110 } 111 112 optnum.code = entry->ds_code; 113 optnum.category = entry->ds_category; 114 115 } else { 116 117 optnum.code = strtoul(argv[optind], 0, 0); 118 optnum.category = ITAB_CAT_STANDARD|ITAB_CAT_SITE; 119 120 /* 121 * sigh. this is a hack, but it's needed for backward 122 * compatibility with the CA dhcpinfo program. 123 */ 124 125 if (optnum.code > DHCP_INFO_VENDOR_START) { 126 optnum.code -= DHCP_INFO_VENDOR_START; 127 optnum.category = ITAB_CAT_VENDOR; 128 } 129 130 entry = inittab_getbycode(optnum.category, ITAB_CONS_INFO, 131 optnum.code); 132 133 if (entry == NULL) { 134 (void) fprintf(stderr, "%s: unknown code `%s'\n", 135 argv[0], argv[optind]); 136 return (DHCP_EXIT_BADARGS); 137 } 138 optnum.category = entry->ds_category; 139 } 140 141 optnum.size = entry->ds_max * inittab_type_to_size(entry); 142 143 /* 144 * send the request to the agent and reap the reply 145 */ 146 147 request = dhcp_ipc_alloc_request(DHCP_GET_TAG, ifname, &optnum, 148 sizeof (dhcp_optnum_t), DHCP_TYPE_OPTNUM); 149 150 if (request == NULL) 151 return (DHCP_EXIT_SYSTEM); 152 153 error = dhcp_ipc_make_request(request, &reply, DHCP_IPC_WAIT_DEFAULT); 154 if (error != 0 || reply->return_code != 0) { 155 156 if (error == 0) 157 error = reply->return_code; 158 159 (void) fprintf(stderr, "%s: %s\n", argv[0], 160 dhcp_ipc_strerror(error)); 161 162 if (error == DHCP_IPC_E_TIMEOUT) 163 return (DHCP_EXIT_TIMEOUT); 164 165 return (DHCP_EXIT_FAILURE); 166 } 167 168 opt = dhcp_ipc_get_data(reply, &opt_len, NULL); 169 170 /* 171 * no data means that the client has an ACK but has no information 172 * about the specified option; return success 173 */ 174 175 if (opt_len == 0) 176 return (DHCP_EXIT_SUCCESS); 177 178 /* 179 * check for protocol error 180 */ 181 182 if (opt_len < 2 || (opt_len - 2 != opt->len)) 183 return (DHCP_EXIT_FAILURE); 184 185 if (is_canonical) { 186 187 value = malloc(opt->len * (sizeof ("0xNN") + 1)); 188 if (value == NULL) { 189 (void) fprintf(stderr, "%s: out of memory\n", argv[0]); 190 return (DHCP_EXIT_FAILURE); 191 } 192 193 for (i = 0, valuep = value; i < opt->len; i++) 194 valuep += sprintf(valuep, "0x%02X ", opt->value[i]); 195 196 valuep[-1] = '\0'; 197 gran = 1; 198 199 } else { 200 201 value = inittab_decode(entry, opt->value, opt->len, B_TRUE); 202 if (value == NULL) { 203 (void) fprintf(stderr, "%s: cannot decode agent's " 204 "reply\n", argv[0]); 205 return (DHCP_EXIT_FAILURE); 206 } 207 208 gran = entry->ds_gran; 209 } 210 211 /* 212 * now display `gran' items per line, printing at most `max_lines'. 213 */ 214 215 for (i = 0; value[i] != '\0'; i++) { 216 if (value[i] == ' ') { 217 if ((++n_spaces % gran) == 0) { 218 value[i] = '\n'; 219 if (max_lines != -1 && --max_lines == 0) { 220 value[i] = '\0'; 221 break; 222 } 223 } 224 } 225 } 226 227 (void) printf("%s\n", value); 228 229 return (DHCP_EXIT_SUCCESS); 230 } 231