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