summaryrefslogtreecommitdiffstats
path: root/usr.sbin/apmd/contrib/pccardq.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/apmd/contrib/pccardq.c')
-rw-r--r--usr.sbin/apmd/contrib/pccardq.c286
1 files changed, 286 insertions, 0 deletions
diff --git a/usr.sbin/apmd/contrib/pccardq.c b/usr.sbin/apmd/contrib/pccardq.c
new file mode 100644
index 0000000..aebd1d5
--- /dev/null
+++ b/usr.sbin/apmd/contrib/pccardq.c
@@ -0,0 +1,286 @@
+/* $FreeBSD$ */
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+const char *const pccardd_file = "/var/tmp/.pccardd";
+const char *prog = "pccardq";
+const char *tmp_dir = "/tmp";
+unsigned slot_map = ~0;
+
+void
+usage(void)
+{
+ fprintf(stderr, "usage: %s [-a] [-n] [-s slot]\n", prog);
+}
+
+int
+proc_arg(int ac, char **av)
+{
+ int rc = -1;
+ int ch;
+
+ char *p = strrchr(av[0], '/');
+ prog = p ? p + 1 : av[0];
+
+ tmp_dir = getenv("TMPDIR") ? getenv("TMPDIR") : tmp_dir;
+
+ while ((ch = getopt(ac, av, "ans:")) != -1) {
+ switch (ch) {
+ case 'a':
+ slot_map = ~0;
+ break;
+ case 'n':
+ slot_map = 0;
+ break;
+ case 's':
+ {
+ int n = atoi(optarg);
+ if (n < 0 || n >= CHAR_BIT * sizeof slot_map) {
+ warnc(0, "Invalid slot number.");
+ usage();
+ goto out;
+ }
+ if (slot_map == ~0)
+ slot_map = 0;
+ slot_map |= 1 << n;
+ }
+ break;
+ default:
+ usage();
+ goto out;
+ }
+ }
+
+ rc = 0;
+ out:
+ return rc;
+}
+
+int
+connect_to_pccardd(char **path)
+{
+ int so = -1;
+ int pccardd_len;
+ struct sockaddr_un pccardq;
+ struct sockaddr_un pccardd;
+
+ if ((so = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) {
+ warn("socket");
+ goto err;
+ }
+
+ snprintf(pccardq.sun_path, sizeof pccardq.sun_path,
+ "%s/%s%ld%ld", tmp_dir, prog, (long) getpid(), (long) time(0));
+ pccardq.sun_family = AF_UNIX;
+ pccardq.sun_len = offsetof(struct sockaddr_un, sun_path) + strlen(pccardq.sun_path);
+ if (bind(so, (struct sockaddr *) &pccardq, pccardq.sun_len) < 0) {
+ warn("bind: %s", pccardq.sun_path);
+ goto err;
+ }
+ if ((*path = strdup(pccardq.sun_path)) == NULL) {
+ warn("strdup");
+ goto err;
+ }
+
+ pccardd_len = strlen(pccardd_file) + 1;
+ if (pccardd_len > sizeof pccardd.sun_path) {
+ warnc(0, "%s: too long", pccardd_file);
+ goto err;
+ }
+ pccardd.sun_len = offsetof(struct sockaddr_un, sun_path) + pccardd_len;
+ pccardd.sun_family = AF_UNIX;
+ strcpy(pccardd.sun_path, pccardd_file);
+ if (connect(so, (struct sockaddr *) &pccardd, pccardd.sun_len) < 0) {
+ warn("connect: %s", pccardd_file);
+ goto err;
+ }
+ return so;
+ err:
+ if (so >= 0)
+ close(so);
+ return -1;
+}
+
+int
+get_slot_number(int so)
+{
+ char buf[8];
+ int rv;
+ int nslot;
+
+ if ((rv = write(so, "S", 1)) < 1) {
+ warn("write");
+ goto err;
+ } else if (rv != 1) {
+ warnc(0, "write: fail.");
+ goto err;
+ }
+
+ if ((rv = read(so, buf, sizeof buf)) < 0) {
+ warn("read");
+ goto err;
+ }
+ buf[sizeof buf - 1] = 0;
+ if (sscanf(buf, "%d", &nslot) != 1) {
+ warnc(0, "Invalid response.");
+ goto err;
+ }
+ return nslot;
+ err:
+ return -1;
+}
+
+enum {
+ SLOT_EMPTY = 0,
+ SLOT_FILLED = 1,
+ SLOT_INACTIVE = 2,
+ SLOT_UNDEFINED = 9
+};
+
+int
+get_slot_info(int so, int slot, char **manuf, char **version, char
+ **device, int *state)
+{
+ int rc = -1;
+ int rv;
+ static char buf[1024];
+ int slen;
+ char *s;
+ char *sl;
+
+ char *_manuf;
+ char *_version;
+ char *_device;
+
+ if ((slen = snprintf(buf, sizeof buf, "N%d", slot)) < 0) {
+ warnc(0, "write");
+ goto err;
+ }
+
+ if ((rv = write(so, buf, slen)) < 0) {
+ warn("write");
+ goto err;
+ } else if (rv != slen) {
+ warnc(0, "write");
+ goto err;
+ }
+
+ if ((rv = read(so, buf, sizeof buf)) < 0) {
+ warn("read");
+ goto err;
+ }
+
+ s = buf;
+ if ((sl = strsep(&s, "~")) == NULL)
+ goto parse_err;
+ if (atoi(sl) != slot)
+ goto parse_err;
+ if ((_manuf = strsep(&s, "~")) == NULL)
+ goto parse_err;
+ if ((_version = strsep(&s, "~")) == NULL)
+ goto parse_err;
+ if ((_device = strsep(&s, "~")) == NULL)
+ goto parse_err;
+ if (sscanf(s, "%1d", state) != 1)
+ goto parse_err;
+ if (s != NULL && strchr(s, '~') != NULL)
+ goto parse_err;
+
+ if ((*manuf = strdup(_manuf)) == NULL) {
+ warn("strdup");
+ goto err;
+ }
+ if ((*version = strdup(_version)) == NULL) {
+ warn("strdup");
+ goto err;
+ }
+ if ((*device = strdup(_device)) == NULL) {
+ warn("strdup");
+ goto err;
+ }
+ if (*manuf == NULL || *version == NULL || *device == NULL) {
+ warn("strdup");
+ goto err;
+ }
+
+ rc = 0;
+ err:
+ return rc;
+ parse_err:
+ warnc(0, "Invalid response: %*s", rv, buf);
+ return rc;
+}
+
+const char *
+strstate(int state)
+{
+ switch (state) {
+ case 0:
+ return "empty";
+ case 1:
+ return "filled";
+ case 2:
+ return "inactive";
+ default:
+ return "unknown";
+ }
+}
+
+int
+main(int ac, char **av)
+{
+ char *path = NULL;
+ int so = -1;
+ int nslot;
+ int i;
+
+ if (proc_arg(ac, av) < 0)
+ goto out;
+ if ((so = connect_to_pccardd(&path)) < 0)
+ goto out;
+ if ((nslot = get_slot_number(so)) < 0)
+ goto out;
+ if (slot_map == 0) {
+ printf("%d\n", nslot);
+ } else {
+ for (i = 0; i < nslot; i++) {
+ if ((slot_map & (1 << i))) {
+ char *manuf;
+ char *version;
+ char *device;
+ int state;
+
+ if (get_slot_info(so, i, &manuf, &version, &device,
+ &state) < 0)
+ goto out;
+ if (manuf == NULL || version == NULL || device == NULL)
+ goto out;
+ printf("%d~%s~%s~%s~%s\n",
+ i, manuf, version, device, strstate(state));
+ free(manuf);
+ free(version);
+ free(device);
+ }
+ }
+ }
+ out:
+ if (path) {
+ unlink(path);
+ free(path);
+ }
+ if (so >= 0)
+ close(so);
+ exit(0);
+}
OpenPOWER on IntegriCloud