freebsd-dev/usr.sbin/apmd/contrib/pccardq.c
Mitsuru IWASAKI d50a71bdd8 The apmd package provides a means of handling various APM events from
userland code.  Using apmd.conf, the apmd(8) configuration file, you
can select the APM events to be handled from userland and specify the
commands for a given event, allowing APM behaviour to be configured
flexibly.

Have Fun!

Submitted by:	iwasaki, KOIE Hidetaka <hide@koie.org>
Reviewed by:	-hackers, -mobile and bsd-nomads ML folks.
Contributed by:	Warner Losh <imp@FreeBSD.org>,
	Hiroshi Yamashita <bluemoon@msj.biglobe.ne.jp>,
	Yoshihiko SARUMARU <mistral@imasy.or.jp>,
	Norihiro Kumagai <kuma@nk.rim.or.jp>,
	NAKAGAWA Yoshihisa <nakagawa@jp.FreeBSD.org>, and
	Nick Hilliard <nick@foobar.org>.
1999-07-10 17:39:36 +00:00

274 lines
5.4 KiB
C

/* $Id: pccardq.c,v 1.2 1999/06/08 15:18:52 koie Exp $ */
#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()
{
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:")) != EOF) {
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;
slen = snprintf(buf, sizeof buf, "N%d", slot);
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;
*manuf = strdup(_manuf);
*version = strdup(_version);
*device = strdup(_device);
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);
}