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 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/stat.h> 30 #include <sys/types.h> 31 #include <fcntl.h> 32 #include <sys/openpromio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <stdio.h> /* sprintf() */ 36 #include <unistd.h> 37 38 /* 39 * opp_zalloc(): allocates and initializes a struct openpromio 40 * 41 * input: size_t: the size of the variable-length part of the openpromio 42 * const char *: an initial value for oprom_array, if non-NULL 43 * output: struct openpromio: the allocated, initialized openpromio 44 */ 45 46 static struct openpromio * 47 opp_zalloc(size_t size, const char *prop) 48 { 49 struct openpromio *opp = malloc(sizeof (struct openpromio) + size); 50 51 if (opp != NULL) { 52 (void) memset(opp, 0, sizeof (struct openpromio) + size); 53 opp->oprom_size = size; 54 if (prop != NULL) 55 (void) strcpy(opp->oprom_array, prop); 56 } 57 return (opp); 58 } 59 60 /* 61 * goto_rootnode(): moves to the root of the devinfo tree 62 * 63 * input: int: an open descriptor to /dev/openprom 64 * output: int: nonzero on success 65 */ 66 67 static int 68 goto_rootnode(int prom_fd) 69 { 70 struct openpromio op = { sizeof (int), 0 }; 71 72 /* zero it explicitly since a union is involved */ 73 op.oprom_node = 0; 74 return (ioctl(prom_fd, OPROMNEXT, &op) == 0); 75 } 76 77 /* 78 * return_property(): returns the value of a given property 79 * 80 * input: int: an open descriptor to /dev/openprom 81 * const char *: the property to look for in the current devinfo node 82 * output: the value of that property (dynamically allocated) 83 */ 84 85 static char * 86 return_property(int prom_fd, const char *prop) 87 { 88 int proplen; 89 char *result; 90 struct openpromio *opp = opp_zalloc(strlen(prop) + 1, prop); 91 92 if (opp == NULL) 93 return (NULL); 94 95 if (ioctl(prom_fd, OPROMGETPROPLEN, opp) == -1) { 96 free(opp); 97 return (NULL); 98 } 99 100 proplen = opp->oprom_len; 101 if (proplen > (strlen(prop) + 1)) { 102 free(opp); 103 opp = opp_zalloc(proplen, prop); 104 if (opp == NULL) 105 return (NULL); 106 } 107 108 if (ioctl(prom_fd, OPROMGETPROP, opp) == -1) { 109 free(opp); 110 return (NULL); 111 } 112 113 result = strdup(opp->oprom_array); 114 free(opp); 115 return (result); 116 } 117 118 /* 119 * sanitize_class_id(): translates the class id into a canonical format, 120 * so that it can be used easily with dhcptab(4). 121 * 122 * input: char *: the class id to canonicalize 123 * output: void 124 */ 125 126 static void 127 sanitize_class_id(char *src_ptr) 128 { 129 char *dst_ptr = src_ptr; 130 131 /* remove all spaces and change all commas to periods */ 132 while (*src_ptr != '\0') { 133 134 switch (*src_ptr) { 135 136 case ' ': 137 break; 138 139 case ',': 140 *dst_ptr++ = '.'; 141 break; 142 143 default: 144 *dst_ptr++ = *src_ptr; 145 break; 146 } 147 src_ptr++; 148 } 149 *dst_ptr = '\0'; 150 } 151 152 /* 153 * get_class_id(): retrieves the class id from the prom, then canonicalizes it 154 * 155 * input: void 156 * output: char *: the class id (dynamically allocated and sanitized) 157 */ 158 159 char * 160 get_class_id(void) 161 { 162 int prom_fd; 163 char *name, *class_id = NULL; 164 size_t len; 165 166 prom_fd = open("/dev/openprom", O_RDONLY); 167 if (prom_fd == -1) 168 return (NULL); 169 170 if (goto_rootnode(prom_fd) == 0) { 171 (void) close(prom_fd); 172 return (NULL); 173 } 174 175 /* 176 * the `name' property is the same as the result of `uname -i', modulo 177 * some stylistic issues we fix up via sanitize_class_id() below. 178 */ 179 180 name = return_property(prom_fd, "name"); 181 (void) close(prom_fd); 182 if (name == NULL) 183 return (NULL); 184 185 /* 186 * if the name is not prefixed with a vendor name, add "SUNW," to make 187 * it more likely to be globally unique; see PSARC/2004/674. 188 */ 189 190 if (strchr(name, ',') == NULL) { 191 len = strlen(name) + sizeof ("SUNW,"); 192 class_id = malloc(len); 193 if (class_id == NULL) { 194 free(name); 195 return (NULL); 196 } 197 (void) snprintf(class_id, len, "SUNW,%s", name); 198 free(name); 199 } else { 200 class_id = name; 201 } 202 203 sanitize_class_id(class_id); 204 return (class_id); 205 } 206