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 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 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 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 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 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, §ions) != 0) { 180 return (-1); 181 } 182 return (sections.fru_cnt); 183 } 184 185 /*ARGSUSED*/ 186 int 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 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 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 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 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 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 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 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 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 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 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 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 480 fru_is_data_available(picl_nodehdl_t fru) 481 { 482 return (0); 483 } 484