#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdarg.h>
#include <strings.h>
#include <limits.h>
#include <syslog.h>
#include <sys/open.h>
#include <string.h>
#include <alloca.h>
#include <libintl.h>
#include <sys/stat.h>
#include <sys/systeminfo.h>
#include <picl.h>
#include <picltree.h>
#include <fru_access.h>
#include <sys/sgfrutree.h>
container_hdl_t fru_open_container(picl_nodehdl_t fru);
int fru_close_container(container_hdl_t fru);
int fru_get_num_sections(container_hdl_t container,
door_cred_t *cred);
int fru_get_sections(container_hdl_t container, section_t *section,
int max_sections, door_cred_t *cred);
int fru_get_num_segments(section_hdl_t section, door_cred_t *cred);
int fru_get_segments(section_hdl_t section, segment_t *segment,
int max_segments, door_cred_t *cred);
int fru_add_segment(section_hdl_t section, segment_t *segment,
section_hdl_t *newsection, door_cred_t *cred);
int fru_delete_segment(segment_hdl_t segment,
section_hdl_t *newsection, door_cred_t *cred);
ssize_t fru_read_segment(segment_hdl_t segment, void *buffer,
size_t nbytes, door_cred_t *cred);
ssize_t fru_write_segment(segment_hdl_t segment, const void *data,
size_t nbytes, segment_hdl_t *newsegment,
door_cred_t *cred);
int fru_get_num_packets(segment_hdl_t segment, door_cred_t *cred);
int fru_get_packets(segment_hdl_t segment, packet_t *packet,
int max_packets, door_cred_t *cred);
int fru_update_payload(packet_hdl_t packet, const void *data,
size_t nbytes, packet_hdl_t *newpacket, door_cred_t *cred);
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);
int fru_delete_packet(packet_hdl_t packet,
segment_hdl_t *newsegment, door_cred_t *cred);
int fru_is_data_available(picl_nodehdl_t fru);
#define PICL_PROP_SC_HANDLE "SC_handle"
#define PICL_PROP_DATA_AVAIL "FRUDataAvailable"
#define MAX_LINE_SIZE 1024
#define OPENDEVFRU gettext("fru_open_dev: open of %s failed %s")
#define GETPV gettext("fru_open_container: ptree_get_propval_by_name failed %s")
static int
fru_open_dev(void)
{
static int opendevfru = 0;
static int frufd = 0;
if ((opendevfru == 0) && (frufd == 0)) {
if ((frufd = open(FRU_PSEUDO_DEV, O_RDWR, access)) == -1) {
syslog(LOG_ERR, OPENDEVFRU, FRU_PSEUDO_DEV,
strerror(errno));
return (-1);
}
opendevfru = 1;
}
return (frufd);
}
container_hdl_t
fru_open_container(picl_nodehdl_t fruh)
{
int err;
container_hdl_t container_hdl;
if (fru_open_dev() == -1) {
return (0);
}
err = ptree_get_propval_by_name(fruh, PICL_PROP_DATA_AVAIL, NULL, 0);
if (err != PICL_SUCCESS) {
syslog(LOG_ERR, GETPV, PICL_PROP_DATA_AVAIL, err);
return (0);
}
err = ptree_get_propval_by_name(fruh, PICL_PROP_SC_HANDLE,
&container_hdl, sizeof (container_hdl_t));
if (err != PICL_SUCCESS) {
syslog(LOG_ERR, GETPV, PICL_PROP_SC_HANDLE, err);
return (0);
}
return (container_hdl);
}
int
fru_close_container(container_hdl_t fru)
{
if (fru_open_dev() == -1) {
return (-1);
}
return (0);
}
int
fru_get_num_sections(container_hdl_t container, door_cred_t *cred)
{
section_info_t numsections;
int fd;
if ((fd = fru_open_dev()) == -1) {
return (-1);
}
numsections.hdl = container;
numsections.cnt = 0;
if (ioctl(fd, SGFRU_GETNUMSECTIONS, &numsections) != 0) {
return (-1);
}
return (numsections.cnt);
}
int
fru_get_sections(container_hdl_t container, section_t *section,
int max_sections, door_cred_t *cred)
{
sections_t sections;
int fd;
if ((fd = fru_open_dev()) == -1) {
return (-1);
}
sections.fru_hdl = container;
sections.fru_cnt = max_sections;
sections.frus = section;
if (ioctl(fd, SGFRU_GETSECTIONS, §ions) != 0) {
return (-1);
}
return (sections.fru_cnt);
}
int
fru_get_num_segments(section_hdl_t section, door_cred_t *cred)
{
segment_info_t numsegments;
int fd;
if ((fd = fru_open_dev()) == -1) {
return (-1);
}
numsegments.hdl = section;
numsegments.cnt = 0;
if (ioctl(fd, SGFRU_GETNUMSEGMENTS, &numsegments) != 0) {
return (-1);
}
return (numsegments.cnt);
}
int
fru_get_segments(section_hdl_t section, segment_t *segment, int max_segments,
door_cred_t *cred)
{
segments_t segments;
int fd;
if ((fd = fru_open_dev()) == -1) {
return (-1);
}
segments.fru_hdl = section;
segments.fru_cnt = max_segments;
segments.frus = segment;
if (ioctl(fd, SGFRU_GETSEGMENTS, &segments) != 0) {
return (-1);
}
return (segments.fru_cnt);
}
int
fru_add_segment(section_hdl_t section, segment_t *segment,
section_hdl_t *newsection, door_cred_t *cred)
{
segments_t newsegment;
int fd;
if (cred->dc_euid != 0) {
errno = EPERM;
return (-1);
}
if ((fd = fru_open_dev()) == -1) {
return (-1);
}
newsegment.fru_hdl = section;
newsegment.fru_cnt = 1;
newsegment.frus = segment;
if (ioctl(fd, SGFRU_ADDSEGMENT, &newsegment) != 0) {
return (-1);
}
*newsection = newsegment.fru_hdl;
return (0);
}
int
fru_delete_segment(segment_hdl_t segment, section_hdl_t *newsection,
door_cred_t *cred)
{
segment_info_t delsegment;
int fd;
if (cred->dc_euid != 0) {
errno = EPERM;
return (-1);
}
if ((fd = fru_open_dev()) == -1) {
return (-1);
}
delsegment.hdl = segment;
if (ioctl(fd, SGFRU_DELETESEGMENT, &delsegment) != 0) {
return (-1);
}
*newsection = delsegment.hdl;
return (0);
}
ssize_t
fru_read_segment(segment_hdl_t segment, void *buffer, size_t nbytes,
door_cred_t *cred)
{
segments_t readsegment;
int fd;
if ((fd = fru_open_dev()) == -1) {
return (-1);
}
readsegment.fru_hdl = segment;
readsegment.fru_cnt = nbytes;
readsegment.frus = buffer;
if (ioctl(fd, SGFRU_READRAWSEGMENT, &readsegment) != 0) {
return (-1);
}
return ((ssize_t)readsegment.fru_cnt);
}
ssize_t
fru_write_segment(segment_hdl_t segment, const void *buffer, size_t nbytes,
segment_hdl_t *newsegment, door_cred_t *cred)
{
segments_t writesegment;
int fd;
if ((fd = fru_open_dev()) == -1) {
return (-1);
}
writesegment.fru_hdl = segment;
writesegment.fru_cnt = nbytes;
writesegment.frus = (void *)buffer;
if (ioctl(fd, SGFRU_WRITERAWSEGMENT, &writesegment) != 0) {
return (-1);
}
*newsegment = writesegment.fru_hdl;
return ((ssize_t)writesegment.fru_cnt);
}
int
fru_get_num_packets(segment_hdl_t segment, door_cred_t *cred)
{
packet_info_t numpackets;
int fd;
if ((fd = fru_open_dev()) == -1) {
return (-1);
}
numpackets.hdl = segment;
numpackets.cnt = 0;
if (ioctl(fd, SGFRU_GETNUMPACKETS, &numpackets) != 0) {
return (-1);
}
return (numpackets.cnt);
}
int
fru_get_packets(segment_hdl_t segment, packet_t *packet, int max_packets,
door_cred_t *cred)
{
packets_t packets;
int fd;
if ((fd = fru_open_dev()) == -1) {
return (-1);
}
packets.fru_hdl = segment;
packets.fru_cnt = max_packets;
packets.frus = packet;
if (ioctl(fd, SGFRU_GETPACKETS, &packets) != 0) {
return (-1);
}
return (packets.fru_cnt);
}
ssize_t
fru_get_payload(packet_hdl_t packet, void *buffer, size_t nbytes,
door_cred_t *cred)
{
payload_t payload;
int fd;
if ((fd = fru_open_dev()) == -1) {
return (-1);
}
payload.fru_hdl = packet;
payload.fru_cnt = nbytes;
payload.frus = buffer;
if (ioctl(fd, SGFRU_GETPAYLOAD, &payload) != 0) {
return (-1);
}
return ((ssize_t)payload.fru_cnt);
}
int
fru_update_payload(packet_hdl_t packet, const void *data, size_t nbytes,
packet_hdl_t *newpacket, door_cred_t *cred)
{
payload_t payload;
int fd;
if (cred->dc_euid != 0) {
errno = EPERM;
return (-1);
}
if ((fd = fru_open_dev()) == -1) {
return (-1);
}
payload.fru_hdl = packet;
payload.fru_cnt = nbytes;
payload.frus = (void *)data;
if (ioctl(fd, SGFRU_UPDATEPAYLOAD, &payload) != 0) {
return (-1);
}
*newpacket = payload.fru_hdl;
return (0);
}
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)
{
append_info_t appendpkt;
int fd;
if (cred->dc_euid != 0) {
errno = EPERM;
return (-1);
}
if ((fd = fru_open_dev()) == -1) {
return (-1);
}
appendpkt.packet = *packet;
appendpkt.payload_hdl = segment;
appendpkt.payload_cnt = nbytes;
appendpkt.payload_data = (void *)payload;
if (ioctl(fd, SGFRU_APPENDPACKET, &appendpkt) != 0) {
return (-1);
}
packet->handle = appendpkt.packet.handle;
*newsegment = appendpkt.payload_hdl;
return (0);
}
int
fru_delete_packet(packet_hdl_t packet, segment_hdl_t *newsegment,
door_cred_t *cred)
{
packet_info_t delpacket;
int fd;
if (cred->dc_euid != 0) {
errno = EPERM;
return (-1);
}
if ((fd = fru_open_dev()) == -1) {
return (-1);
}
delpacket.hdl = packet;
if (ioctl(fd, SGFRU_DELETEPACKET, &delpacket) != 0) {
return (-1);
}
*newsegment = delpacket.hdl;
return (0);
}
int
fru_is_data_available(picl_nodehdl_t fru)
{
return (0);
}