xref: /illumos-gate/usr/src/cmd/cmd-inet/sbin/dhcpagent/class_id.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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