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