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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
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 <stdio.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <stdlib.h>
34 #include <stdarg.h>
35 #include <strings.h>
36 #include <limits.h>
37 #include <syslog.h>
38 #include <sys/open.h>
39 #include <string.h>
40 #include <alloca.h>
41 #include <libintl.h>
42 #include <sys/stat.h>
43 #include <sys/systeminfo.h>
44 #include <picl.h>
45 #include <picltree.h>
46 #include <fru_access.h>
47 #include <sys/sgfrutree.h>
48 
49 /*
50  * these functions will overlay the symbol table of libfruaccess
51  * at runtime
52  */
53 container_hdl_t	fru_open_container(picl_nodehdl_t fru);
54 int		fru_close_container(container_hdl_t fru);
55 int		fru_get_num_sections(container_hdl_t container,
56 		    door_cred_t *cred);
57 int		fru_get_sections(container_hdl_t container, section_t *section,
58 		    int max_sections, door_cred_t *cred);
59 int		fru_get_num_segments(section_hdl_t section, door_cred_t *cred);
60 int		fru_get_segments(section_hdl_t section, segment_t *segment,
61 		    int max_segments, door_cred_t *cred);
62 int		fru_add_segment(section_hdl_t section, segment_t *segment,
63 		    section_hdl_t *newsection, door_cred_t *cred);
64 int		fru_delete_segment(segment_hdl_t segment,
65 		    section_hdl_t *newsection, door_cred_t *cred);
66 ssize_t		fru_read_segment(segment_hdl_t segment, void *buffer,
67 		    size_t nbytes, door_cred_t *cred);
68 ssize_t		fru_write_segment(segment_hdl_t segment, const void *data,
69 		    size_t nbytes, segment_hdl_t *newsegment,
70 		    door_cred_t *cred);
71 int		fru_get_num_packets(segment_hdl_t segment, door_cred_t *cred);
72 int		fru_get_packets(segment_hdl_t segment, packet_t *packet,
73 		    int max_packets, door_cred_t *cred);
74 int		fru_update_payload(packet_hdl_t packet, const void *data,
75 		    size_t nbytes, packet_hdl_t *newpacket, door_cred_t *cred);
76 int		fru_append_packet(segment_hdl_t segment, packet_t *packet,
77 		    const void *payload, size_t nbytes,
78 		    segment_hdl_t *newsegment, door_cred_t *cred);
79 int		fru_delete_packet(packet_hdl_t packet,
80 		    segment_hdl_t *newsegment, door_cred_t *cred);
81 int 		fru_is_data_available(picl_nodehdl_t fru);
82 
83 #define	PICL_PROP_SC_HANDLE	"SC_handle"
84 #define	PICL_PROP_DATA_AVAIL	"FRUDataAvailable"
85 #define	MAX_LINE_SIZE		1024
86 
87 #define	OPENDEVFRU gettext("fru_open_dev: open of %s failed %s")
88 #define	GETPV gettext("fru_open_container: ptree_get_propval_by_name failed %s")
89 
90 static int
91 fru_open_dev(void)
92 {
93 	static int opendevfru = 0;
94 	static int frufd = 0;
95 
96 	if ((opendevfru == 0) && (frufd == 0)) {
97 		if ((frufd = open(FRU_PSEUDO_DEV, O_RDWR, access)) == -1) {
98 			syslog(LOG_ERR, OPENDEVFRU, FRU_PSEUDO_DEV,
99 			    strerror(errno));
100 			return (-1);
101 		}
102 		opendevfru = 1;
103 	}
104 	return (frufd);
105 }
106 
107 /*
108  * Look up the container_hdl in the PICL tree.
109  */
110 container_hdl_t
111 fru_open_container(picl_nodehdl_t fruh)
112 {
113 	int err;
114 	container_hdl_t container_hdl;
115 
116 	if (fru_open_dev() == -1) {
117 		return (NULL);
118 	}
119 
120 	err = ptree_get_propval_by_name(fruh, PICL_PROP_DATA_AVAIL, NULL, NULL);
121 	if (err != PICL_SUCCESS) {
122 		syslog(LOG_ERR, GETPV, PICL_PROP_DATA_AVAIL, err);
123 		return (NULL);
124 	}
125 	err = ptree_get_propval_by_name(fruh, PICL_PROP_SC_HANDLE,
126 	    &container_hdl, sizeof (container_hdl_t));
127 	if (err != PICL_SUCCESS) {
128 		syslog(LOG_ERR, GETPV, PICL_PROP_SC_HANDLE, err);
129 		return (NULL);
130 	}
131 	return (container_hdl);
132 }
133 
134 /*
135  * Note : fru_open_container and fru_close_container do not map onto the opens
136  * and closes of the sgfru device on lw8. There is one sgfru device which
137  * handles all containers.
138  */
139 /*ARGSUSED*/
140 int
141 fru_close_container(container_hdl_t fru)
142 {
143 	if (fru_open_dev() == -1) {
144 		return (-1);
145 	}
146 	return (0);
147 }
148 
149 /*ARGSUSED*/
150 int
151 fru_get_num_sections(container_hdl_t container, door_cred_t *cred)
152 {
153 	section_info_t numsections;
154 	int fd;
155 
156 	if ((fd = fru_open_dev()) == -1) {
157 		return (-1);
158 	}
159 	numsections.hdl = container;
160 	numsections.cnt = 0;
161 	if (ioctl(fd, SGFRU_GETNUMSECTIONS, &numsections) != 0) {
162 		return (-1);
163 	}
164 	return (numsections.cnt);
165 }
166 
167 /*ARGSUSED*/
168 int
169 fru_get_sections(container_hdl_t container, section_t *section,
170     int max_sections, door_cred_t *cred)
171 {
172 	sections_t sections;
173 	int fd;
174 
175 	if ((fd = fru_open_dev()) == -1) {
176 		return (-1);
177 	}
178 	sections.fru_hdl = container;
179 	sections.fru_cnt = max_sections;
180 	sections.frus = section;
181 	if (ioctl(fd, SGFRU_GETSECTIONS, &sections) != 0) {
182 		return (-1);
183 	}
184 	return (sections.fru_cnt);
185 }
186 
187 /*ARGSUSED*/
188 int
189 fru_get_num_segments(section_hdl_t section, door_cred_t *cred)
190 {
191 	segment_info_t numsegments;
192 	int fd;
193 
194 	if ((fd = fru_open_dev()) == -1) {
195 		return (-1);
196 	}
197 	numsegments.hdl = section;
198 	numsegments.cnt = 0;
199 	if (ioctl(fd, SGFRU_GETNUMSEGMENTS, &numsegments) != 0) {
200 		return (-1);
201 	}
202 	return (numsegments.cnt);
203 }
204 
205 /*ARGSUSED*/
206 int
207 fru_get_segments(section_hdl_t section, segment_t *segment, int max_segments,
208     door_cred_t *cred)
209 {
210 	segments_t segments;
211 	int fd;
212 
213 	if ((fd = fru_open_dev()) == -1) {
214 		return (-1);
215 	}
216 	segments.fru_hdl = section;
217 	segments.fru_cnt = max_segments;
218 	segments.frus = segment;
219 	if (ioctl(fd, SGFRU_GETSEGMENTS, &segments) != 0) {
220 		return (-1);
221 	}
222 	return (segments.fru_cnt);
223 }
224 
225 /*ARGSUSED*/
226 int
227 fru_add_segment(section_hdl_t section, segment_t *segment,
228     section_hdl_t *newsection, door_cred_t *cred)
229 {
230 	segments_t newsegment;
231 	int fd;
232 
233 	/* check the effective uid of the client */
234 	if (cred->dc_euid != 0) {
235 		errno = EPERM;
236 		return (-1);	/* not a root */
237 	}
238 
239 	if ((fd = fru_open_dev()) == -1) {
240 		return (-1);
241 	}
242 	newsegment.fru_hdl = section;
243 	newsegment.fru_cnt = 1;
244 	newsegment.frus = segment;
245 	if (ioctl(fd, SGFRU_ADDSEGMENT, &newsegment) != 0) {
246 		return (-1);
247 	}
248 	/*
249 	 * The new segment handle is returned in segment,
250 	 * return the updated section handle in newsection.
251 	 */
252 	*newsection = newsegment.fru_hdl;
253 	return (0);
254 }
255 
256 int
257 fru_delete_segment(segment_hdl_t segment, section_hdl_t *newsection,
258     door_cred_t *cred)
259 {
260 	segment_info_t delsegment;
261 	int fd;
262 
263 	/* check the effective uid of the client */
264 	if (cred->dc_euid != 0) {
265 		errno = EPERM;
266 		return (-1);	/* not a root */
267 	}
268 
269 	if ((fd = fru_open_dev()) == -1) {
270 		return (-1);
271 	}
272 	delsegment.hdl = segment;
273 	if (ioctl(fd, SGFRU_DELETESEGMENT, &delsegment) != 0) {
274 		return (-1);
275 	}
276 	/* Return the updated section handle in newsection. */
277 	*newsection = delsegment.hdl;
278 	return (0);
279 }
280 
281 /*ARGSUSED*/
282 ssize_t
283 fru_read_segment(segment_hdl_t segment, void *buffer, size_t nbytes,
284     door_cred_t *cred)
285 {
286 	segments_t readsegment;
287 	int fd;
288 
289 	if ((fd = fru_open_dev()) == -1) {
290 		return (-1);
291 	}
292 	readsegment.fru_hdl = segment;
293 	readsegment.fru_cnt = nbytes;
294 	readsegment.frus = buffer;
295 	if (ioctl(fd, SGFRU_READRAWSEGMENT, &readsegment) != 0) {
296 		return (-1);
297 	}
298 	return ((ssize_t)readsegment.fru_cnt);
299 }
300 
301 /*ARGSUSED*/
302 ssize_t
303 fru_write_segment(segment_hdl_t segment, const void *buffer, size_t nbytes,
304     segment_hdl_t *newsegment, door_cred_t *cred)
305 {
306 	segments_t writesegment;
307 	int fd;
308 
309 	if ((fd = fru_open_dev()) == -1) {
310 		return (-1);
311 	}
312 	writesegment.fru_hdl = segment;
313 	writesegment.fru_cnt = nbytes;
314 	writesegment.frus = (void *)buffer;
315 	if (ioctl(fd, SGFRU_WRITERAWSEGMENT, &writesegment) != 0) {
316 		return (-1);
317 	}
318 	/* Return the updated segment handle in newsegment. */
319 	*newsegment = writesegment.fru_hdl;
320 	return ((ssize_t)writesegment.fru_cnt);
321 }
322 
323 /*ARGSUSED*/
324 int
325 fru_get_num_packets(segment_hdl_t segment, door_cred_t *cred)
326 {
327 	packet_info_t numpackets;
328 	int fd;
329 
330 	if ((fd = fru_open_dev()) == -1) {
331 		return (-1);
332 	}
333 	numpackets.hdl = segment;
334 	numpackets.cnt = 0;
335 	if (ioctl(fd, SGFRU_GETNUMPACKETS, &numpackets) != 0) {
336 		return (-1);
337 	}
338 	return (numpackets.cnt);
339 }
340 
341 /*ARGSUSED*/
342 int
343 fru_get_packets(segment_hdl_t segment, packet_t *packet, int max_packets,
344     door_cred_t *cred)
345 {
346 	packets_t packets;
347 	int fd;
348 
349 	if ((fd = fru_open_dev()) == -1) {
350 		return (-1);
351 	}
352 	packets.fru_hdl = segment;
353 	packets.fru_cnt = max_packets;
354 	packets.frus = packet;
355 	if (ioctl(fd, SGFRU_GETPACKETS, &packets) != 0) {
356 		return (-1);
357 	}
358 	return (packets.fru_cnt);
359 }
360 
361 /*ARGSUSED*/
362 ssize_t
363 fru_get_payload(packet_hdl_t packet, void *buffer, size_t nbytes,
364     door_cred_t *cred)
365 {
366 	payload_t payload;
367 	int fd;
368 
369 	if ((fd = fru_open_dev()) == -1) {
370 		return (-1);
371 	}
372 	payload.fru_hdl = packet;
373 	payload.fru_cnt = nbytes;
374 	payload.frus = buffer;
375 	if (ioctl(fd, SGFRU_GETPAYLOAD, &payload) != 0) {
376 		return (-1);
377 	}
378 	return ((ssize_t)payload.fru_cnt);
379 }
380 
381 int
382 fru_update_payload(packet_hdl_t packet, const void *data, size_t nbytes,
383     packet_hdl_t *newpacket, door_cred_t *cred)
384 {
385 	payload_t payload;
386 	int fd;
387 
388 	/* check the effective uid of the client */
389 	if (cred->dc_euid != 0) {
390 		errno = EPERM;
391 		return (-1);	/* not a root */
392 	}
393 
394 	if ((fd = fru_open_dev()) == -1) {
395 		return (-1);
396 	}
397 	payload.fru_hdl = packet;
398 	payload.fru_cnt = nbytes;
399 	payload.frus = (void *)data;
400 	if (ioctl(fd, SGFRU_UPDATEPAYLOAD, &payload) != 0) {
401 		return (-1);
402 	}
403 	/* Return the updated packet handle in newpacket. */
404 	*newpacket = payload.fru_hdl;
405 	return (0);
406 }
407 
408 int
409 fru_append_packet(segment_hdl_t segment, packet_t *packet, const void *payload,
410     size_t nbytes, segment_hdl_t *newsegment, door_cred_t *cred)
411 {
412 	append_info_t appendpkt;
413 	int fd;
414 
415 	/* check the effective uid of the client */
416 	if (cred->dc_euid != 0) {
417 		errno = EPERM;
418 		return (-1);	/* not a root */
419 	}
420 
421 	if ((fd = fru_open_dev()) == -1) {
422 		return (-1);
423 	}
424 	appendpkt.packet = *packet;
425 	appendpkt.payload_hdl = segment;
426 	appendpkt.payload_cnt = nbytes;
427 	appendpkt.payload_data = (void *)payload;
428 	if (ioctl(fd, SGFRU_APPENDPACKET, &appendpkt) != 0) {
429 		return (-1);
430 	}
431 	/*
432 	 * The new packet handle is returned in packet,
433 	 * return the updated segment handle in newsegment.
434 	 */
435 	packet->handle = appendpkt.packet.handle;
436 	*newsegment = appendpkt.payload_hdl;
437 	return (0);
438 }
439 
440 int
441 fru_delete_packet(packet_hdl_t packet, segment_hdl_t *newsegment,
442     door_cred_t *cred)
443 {
444 	packet_info_t delpacket;
445 	int fd;
446 
447 	/* check the effective uid of the client */
448 	if (cred->dc_euid != 0) {
449 		errno = EPERM;
450 		return (-1);	/* not a root */
451 	}
452 
453 	if ((fd = fru_open_dev()) == -1) {
454 		return (-1);
455 	}
456 	delpacket.hdl = packet;
457 	if (ioctl(fd, SGFRU_DELETEPACKET, &delpacket) != 0) {
458 		return (-1);
459 	}
460 	/* Return the updated segment handle in newsegment. */
461 	*newsegment = delpacket.hdl;
462 	return (0);
463 }
464 
465 /*
466  * Description :
467  *		fru_is_data_available() checks to see if the frudata
468  *		is available on a fru.
469  *
470  * Arguments   :
471  *		picl_nodehdl_t holds the picl node handle of the fru.
472  *
473  * Return      :
474  *		int
475  *		return 1: if FRUID information is available
476  *		return 0: if FRUID information is not present
477  *
478  */
479 
480 /* ARGSUSED */
481 int
482 fru_is_data_available(picl_nodehdl_t fru)
483 {
484 	return (0);
485 }
486