/* $NetBSD: apm.c,v 1.21 2011/11/25 12:51:28 joerg Exp $ */ /*- * Copyright (c) 1996 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by John Kohl. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pathnames.h" #include "apm-proto.h" #define FALSE 0 #define TRUE 1 __dead static void usage(void); __dead static void zzusage(void); static int do_zzz(const char *, enum apm_action); static int open_socket(const char *); static int send_command(int, struct apm_command *, struct apm_reply *); static void usage(void) { fprintf(stderr,"usage: %s [-v] [-z | -S] [-abdlms] [-f socket]\n", getprogname()); exit(1); } static void zzusage(void) { fprintf(stderr,"usage: %s [-z | -S] [-f socket]\n", getprogname()); exit(1); } static int send_command(int fd, struct apm_command *cmd, struct apm_reply *reply) { /* send a command to the apm daemon */ cmd->vno = APMD_VNO; if (send(fd, cmd, sizeof(*cmd), 0) == sizeof(*cmd)) { if (recv(fd, reply, sizeof(*reply), 0) != sizeof(*reply)) { warn("invalid reply from APM daemon"); return (1); } } else { warn("invalid send to APM daemon"); return (1); } return (0); } static int do_zzz(const char *pn, enum apm_action action) { struct apm_command command; struct apm_reply reply; int fd; switch (action) { case NONE: case SUSPEND: command.action = SUSPEND; break; case STANDBY: command.action = STANDBY; break; default: zzusage(); } fd = open_socket(pn); if (fd == -1) err(1, "cannot open connection to APM daemon"); printf("Suspending system...\n"); exit(send_command(fd, &command, &reply)); } static int open_socket(const char *sockname) { struct sockaddr_un s_un; int sock, errr; sock = socket(AF_LOCAL, SOCK_STREAM, 0); if (sock == -1) err(1, "cannot create local socket"); s_un.sun_family = AF_LOCAL; strncpy(s_un.sun_path, sockname, sizeof(s_un.sun_path)); s_un.sun_len = SUN_LEN(&s_un); if (connect(sock, (struct sockaddr *)&s_un, s_un.sun_len) == -1) { errr = errno; close(sock); errno = errr; return (-1); } return (sock); } int main(int argc, char *argv[]) { struct apm_command command; struct apm_reply reply; struct apm_power_info *api = &reply.batterystate; const char *sockname = _PATH_APM_SOCKET; enum apm_action action = NONE; int ch, doac, dobstate, domin, dopct, dostatus, fd, nodaemon, rval, verbose; doac = dobstate = domin = dopct = dostatus = nodaemon = verbose = FALSE; while ((ch = getopt(argc, argv, "Sabdf:lmsvz")) != -1) switch (ch) { case 'v': verbose = TRUE; break; case 'f': sockname = optarg; break; case 'z': if (action != NONE) usage(); action = SUSPEND; break; case 'S': if (action != NONE) usage(); action = STANDBY; break; case 's': if (action != NONE && action != GETSTATUS) usage(); dostatus = TRUE; action = GETSTATUS; break; case 'b': if (action != NONE && action != GETSTATUS) usage(); dobstate = TRUE; action = GETSTATUS; break; case 'l': if (action != NONE && action != GETSTATUS) usage(); dopct = TRUE; action = GETSTATUS; break; case 'm': if (action != NONE && action != GETSTATUS) usage(); domin = TRUE; action = GETSTATUS; break; case 'a': if (action != NONE && action != GETSTATUS) usage(); doac = TRUE; action = GETSTATUS; break; case 'd': nodaemon = TRUE; break; case '?': default: usage(); } if (strcmp(getprogname(), "zzz") == 0) exit(do_zzz(sockname, action)); if (nodaemon) fd = -1; else fd = open_socket(sockname); switch (action) { case NONE: verbose = doac = dopct = domin = dobstate = dostatus = TRUE; action = GETSTATUS; /* FALLTHROUGH */ case GETSTATUS: if (fd == -1) { /* open the device directly and get status */ fd = open(_PATH_APM_NORMAL, O_RDONLY); if (fd == -1) { err(1, "cannot contact APM daemon and " "cannot open " _PATH_APM_NORMAL); } memset(&reply, 0, sizeof(reply)); if (ioctl(fd, APM_IOC_GETPOWER, &reply.batterystate) == -1) err(1, "ioctl(APM_IOC_GETPOWER)"); goto printval; } /* FALLTHROUGH */ case SUSPEND: case STANDBY: if (nodaemon && fd == -1) { fd = open(_PATH_APM_CTLDEV, O_RDWR); if (fd == -1) err(1, "cannot open APM control device " _PATH_APM_CTLDEV); sync(); sync(); sleep(1); if (ioctl(fd, action == SUSPEND ? APM_IOC_SUSPEND : APM_IOC_STANDBY, 0) == -1) err(1, "cannot enter requested power state"); printf("System will enter %s in a moment.\n", action == SUSPEND ? "suspend mode" : "standby mode"); exit(0); } else if (fd == -1) err(1, "cannot contact APM daemon at socket " _PATH_APM_SOCKET); command.action = action; break; default: usage(); } if ((rval = send_command(fd, &command, &reply)) == 0) { switch (action) { case GETSTATUS: printval: if (verbose) { if (dobstate) printf("Battery charge state: %s\n", battstate(api->battery_state)); if (dopct && domin && api->minutes_left == 0) domin = FALSE; if (dopct || domin) { printf("Battery remaining: "); if (dopct) printf("%d percent", api->battery_life); if (dopct && domin) printf(" ("); if (domin) printf("%d minutes", api->minutes_left); if (dopct && domin) printf(")"); printf("\n"); } if (doac) printf("A/C adapter state: %s\n", ac_state(api->ac_state)); if (dostatus) printf("Power management enabled\n"); if (api->nbattery) { printf("Number of batteries: %u\n", api->nbattery); } } else { if (dobstate) printf("%d\n", api->battery_state); if (dopct) printf("%d\n", api->battery_life); if (domin) printf("%d\n", api->minutes_left); if (doac) printf("%d\n", api->ac_state); if (dostatus) printf("1\n"); } break; default: break; } switch (reply.newstate) { case SUSPEND: printf("System will enter suspend mode " "in a moment.\n"); break; case STANDBY: printf("System will enter standby mode " "in a moment.\n"); break; default: break; } } else errx(rval, "cannot get reply from APM daemon"); exit(0); }