#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <strings.h>
#include <stdlib.h>
#include <libgen.h>
#include <unistd.h>
#include <stdio.h>
#include <libdevinfo.h>
#include "pcp_utils.h"
typedef enum { false = 0, true = 1 } bool_t;
#define SERVICE_PREFIX "SUNW,sun4v-"
#define DEVICES_DIR "/devices"
#define GLVC ":glvc"
#define VCHAN "virtual-channel@"
#define VCHAN_C "virtual-channel-client@"
static bool_t
get_vldc_svc_name(char *dev_path, char *service, char **match)
{
bool_t ret = false;
char *pathname = strdup(dev_path);
char *devname, *s;
if (NULL == pathname)
return (false);
devname = basename(pathname);
s = strrchr(devname, ':');
if (s++ == NULL) {
goto end;
}
if ((strncmp(devname, VCHAN, strlen(VCHAN)) == 0) ||
(strncmp(devname, VCHAN_C, strlen(VCHAN_C)) == 0)) {
if (service != NULL) {
if (strcmp(s, service) == 0) {
if (match)
*match = strdup(s);
ret = true;
goto end;
} else {
ret = false;
goto end;
}
} else if (match) {
*match = strdup(s);
}
ret = true;
goto end;
}
end:
free(pathname);
return (ret);
}
static bool_t
get_glvc_svc_name(char *dev_path, char *service, char **match)
{
bool_t ret = true;
char *pathname = strdup(dev_path);
char *devname, *substr, *t;
int len;
if (NULL == pathname)
return (false);
devname = basename(pathname);
substr = strstr(devname, GLVC);
if (!((substr != NULL) && (strcmp(substr, GLVC) == 0))) {
ret = false;
goto end;
}
if ((t = strrchr(devname, '@')) == NULL) {
ret = false;
goto end;
}
len = t - devname;
if ((service != NULL) && (strncmp(devname, service, len) != 0))
ret = false;
if ((ret == true) && (match != NULL)) {
*match = calloc(len + 1, 1);
if (*match)
(void) strncpy(*match, devname, len);
}
end:
free(pathname);
return (ret);
}
char *
platsvc_extract_svc_name(char *devname)
{
char *sname = NULL;
char *vldc_path, *glvc_path;
if (strncmp(devname, SERVICE_PREFIX, strlen(SERVICE_PREFIX)) == 0) {
sname = strdup(devname + strlen(SERVICE_PREFIX));
return (sname);
}
if (!(devname[0] == '/' || devname[0] == '.')) {
return (NULL);
}
if (get_vldc_svc_name(devname, NULL, &vldc_path) == true) {
return (vldc_path);
} else if (get_glvc_svc_name(devname, NULL, &glvc_path) == true) {
return (glvc_path);
}
return (NULL);
}
static char *
svc_name_to_glvc_dev_path(char *service)
{
di_node_t root_node, service_node;
char *glvc_path;
char *minor_name;
di_minor_t minor;
char *dev_path = NULL;
if (service == NULL)
return (NULL);
root_node = di_init_driver("glvc", DINFOCPYALL);
if (root_node == DI_NODE_NIL) {
return (dev_path);
}
service_node = di_drv_first_node("glvc", root_node);
while (service_node != DI_NODE_NIL) {
if (strcmp(service, di_node_name(service_node)) == 0) {
minor = di_minor_next(service_node, DI_NODE_NIL);
while (minor != DI_NODE_NIL) {
glvc_path = di_devfs_minor_path(minor);
minor_name = di_minor_name(minor);
if (strcmp(minor_name, "glvc") == 0) {
dev_path = malloc(strlen(glvc_path) +
strlen(DEVICES_DIR) + 1);
(void) strcpy(dev_path, DEVICES_DIR);
(void) strcat(dev_path, glvc_path);
di_devfs_path_free(glvc_path);
break;
}
di_devfs_path_free(glvc_path);
minor = di_minor_next(service_node, minor);
}
}
if (dev_path != NULL)
break;
service_node = di_drv_next_node(service_node);
}
di_fini(root_node);
return (dev_path);
}
static char *
svc_name_to_vldc_dev_path(char *service)
{
di_node_t root_node, vldc_node;
char *vldc_path;
char *minor_name;
di_minor_t minor;
char *dev_path = NULL;
root_node = di_init_driver("vldc", DINFOCPYALL);
if (root_node == DI_NODE_NIL) {
return (dev_path);
}
vldc_node = di_drv_first_node("vldc", root_node);
while (vldc_node != DI_NODE_NIL) {
minor = di_minor_next(vldc_node, DI_NODE_NIL);
while (minor != DI_NODE_NIL) {
vldc_path = di_devfs_minor_path(minor);
minor_name = di_minor_name(minor);
if (strcmp(minor_name, service) == 0) {
dev_path = malloc(strlen(vldc_path) +
strlen(DEVICES_DIR) + 1);
(void) strcpy(dev_path, DEVICES_DIR);
(void) strcat(dev_path, vldc_path);
di_devfs_path_free(vldc_path);
break;
}
di_devfs_path_free(vldc_path);
minor = di_minor_next(vldc_node, minor);
}
if (dev_path != NULL)
break;
vldc_node = di_drv_next_node(vldc_node);
}
di_fini(root_node);
return (dev_path);
}
char *
platsvc_name_to_path(char *svc_or_path, pcp_xport_t *type)
{
char *pathn_p;
char *service;
if ((service = platsvc_extract_svc_name(svc_or_path)) == NULL)
return (NULL);
pathn_p = svc_name_to_vldc_dev_path(service);
if (pathn_p != NULL) {
*type = VLDC_STREAMING;
} else {
pathn_p = svc_name_to_glvc_dev_path(service);
if (pathn_p != NULL) {
*type = GLVC_NON_STREAM;
}
}
free(service);
return (pathn_p);
}