#include <unistd.h>
#include <stdio.h>
#include <stdarg.h>
#include <libgen.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <strings.h>
#include <libdladm.h>
#include <libdllink.h>
#include <sys/mac.h>
#include <sys/dld.h>
#include <sys/dld_ioc.h>
static const char *dlled_progname;
static dladm_handle_t dlled_hdl;
static char dlled_dlerrmsg[DLADM_STRSIZE];
typedef struct dlled_led_map {
const char *dlm_name;
mac_led_mode_t dlm_bits;
} dlled_led_map_t;
static dlled_led_map_t dlled_map[] = {
{ "default", MAC_LED_DEFAULT },
{ "off", MAC_LED_OFF },
{ "on", MAC_LED_ON },
{ "ident", MAC_LED_IDENT }
};
#define DLLED_MAP_NENTRIES \
(sizeof (dlled_map) / sizeof (dlled_led_map_t))
static void
dlled_usage(const char *fmt, ...)
{
if (fmt != NULL) {
va_list ap;
(void) fprintf(stderr, "%s: ", dlled_progname);
va_start(ap, fmt);
(void) vfprintf(stderr, fmt, ap);
va_end(ap);
}
(void) fprintf(stderr, "Usage: %s [-s mode] [link]\n"
"\n"
"\t-s mode set LED to mode\n",
dlled_progname);
}
static mac_led_mode_t
dlled_parse_mode(const char *orig)
{
char *mode;
char *part;
mac_led_mode_t m = 0;
mode = strdup(orig);
if (mode == NULL) {
fprintf(stderr, "failed to allocate memory to dup led "
"mode: %s\n", strerror(errno));
exit(1);
}
part = strtok(mode, ",");
while (part != NULL) {
int i;
for (i = 0; i < DLLED_MAP_NENTRIES; i++) {
if (strcmp(dlled_map[i].dlm_name, part) == 0) {
m |= dlled_map[i].dlm_bits;
break;
}
}
if (i == DLLED_MAP_NENTRIES) {
fprintf(stderr, "unknown LED mode: %s\n", part);
exit(1);
}
part = strtok(NULL, ",");
}
free(mode);
if (m == 0) {
fprintf(stderr, "failed to parse %s: no valid modes "
"specified\n", orig);
exit(1);
}
return (m);
}
static void
dlled_mode2str(mac_led_mode_t mode, char *buf, size_t len)
{
int i;
boolean_t first = B_TRUE;
mac_led_mode_t orig = mode;
for (i = 0; i < DLLED_MAP_NENTRIES; i++) {
if ((mode & dlled_map[i].dlm_bits) != 0) {
if (first) {
first = B_FALSE;
} else {
(void) strlcat(buf, ",", len);
}
(void) strlcat(buf, dlled_map[i].dlm_name, len);
mode &= ~dlled_map[i].dlm_bits;
}
}
if (mode != 0) {
(void) snprintf(buf, len, "unknown mode: 0x%x\n", orig);
}
}
static int
dlled_set(const char *link, mac_led_mode_t mode)
{
datalink_id_t linkid;
dladm_status_t status;
dld_ioc_led_t dil;
if ((status = dladm_name2info(dlled_hdl, link, &linkid, NULL, NULL,
NULL)) != DLADM_STATUS_OK) {
(void) fprintf(stderr, "failed to get link "
"id for link %s: %s\n", link,
dladm_status2str(status, dlled_dlerrmsg));
return (1);
}
bzero(&dil, sizeof (dil));
dil.dil_linkid = linkid;
dil.dil_active = mode;
if (ioctl(dladm_dld_fd(dlled_hdl), DLDIOC_SETLED, &dil) != 0) {
(void) fprintf(stderr, "failed to set LED on "
"device %s: %s\n", link, strerror(errno));
return (1);
}
return (0);
}
static int
dlled_get_led(dladm_handle_t hdl, datalink_id_t linkid, void *arg)
{
dladm_status_t status;
char name[MAXLINKNAMELEN];
char supported[128], active[128];
dld_ioc_led_t dil;
if ((status = dladm_datalink_id2info(hdl, linkid, NULL, NULL, NULL,
name, sizeof (name))) != DLADM_STATUS_OK) {
(void) fprintf(stderr, "failed to get datalink name for link "
"%d: %s", linkid, dladm_status2str(status,
dlled_dlerrmsg));
return (DLADM_WALK_CONTINUE);
}
bzero(&dil, sizeof (dil));
dil.dil_linkid = linkid;
if (ioctl(dladm_dld_fd(hdl), DLDIOC_GETLED, &dil) != 0) {
(void) fprintf(stderr, "failed to get LED information for "
"device %s: %s\n", name, strerror(errno));
return (DLADM_WALK_CONTINUE);
}
active[0] = '\0';
supported[0] = '\0';
dlled_mode2str(dil.dil_active, active, sizeof (active));
dlled_mode2str(dil.dil_supported, supported, sizeof (supported));
printf("%-20s %-12s %s\n", name, active, supported);
return (DLADM_WALK_CONTINUE);
}
int
main(int argc, char *argv[])
{
int c, ret;
boolean_t opt_s = B_FALSE;
mac_led_mode_t set_mode = 0;
dladm_status_t status;
dlled_progname = basename(argv[0]);
while ((c = getopt(argc, argv, ":s:")) != -1) {
switch (c) {
case 's':
opt_s = B_TRUE;
set_mode = dlled_parse_mode(optarg);
break;
case ':':
dlled_usage("option -%c requires an operand\n", optopt);
return (2);
case '?':
default:
dlled_usage("unknown option: -%c\n", optopt);
return (2);
}
}
argc -= optind;
argv += optind;
if (opt_s && argc > 1) {
dlled_usage("-s only operates on a single datalink\n");
return (2);
}
if (opt_s && argc <= 0) {
dlled_usage("-s requires a datalink\n");
return (2);
}
if ((status = dladm_open(&dlled_hdl)) != DLADM_STATUS_OK) {
(void) fprintf(stderr, "failed to open /dev/dld: %s\n",
dladm_status2str(status, dlled_dlerrmsg));
return (1);
}
if (opt_s) {
return (dlled_set(argv[0], set_mode));
}
(void) printf("%-20s %-12s %s\n", "LINK", "ACTIVE", "SUPPORTED");
ret = 0;
if (argc == 0) {
(void) dladm_walk_datalink_id(dlled_get_led, dlled_hdl, NULL,
DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE,
DLADM_OPT_ACTIVE);
} else {
int i, dlret;
datalink_id_t linkid;
for (i = 0; i < argc; i++) {
if ((status = dladm_name2info(dlled_hdl, argv[i],
&linkid, NULL, NULL, NULL)) != DLADM_STATUS_OK) {
(void) fprintf(stderr, "failed to get link "
"id for link %s: %s\n", argv[i],
dladm_status2str(status, dlled_dlerrmsg));
return (1);
}
dlret = dlled_get_led(dlled_hdl, linkid, NULL);
if (dlret != DLADM_WALK_CONTINUE) {
ret = 1;
break;
}
}
}
return (ret);
}