On Mon, Aug 14, 2017 at 05:12:05PM +0200, Klemens Nanni wrote:
> Personally I'd also prefer having this in apmd(8) rather than some other
> daemon or script. Some comments:
> 
> You should pass optarg instead of errstr to error(). Either ways error()
> will still append since it uses err(3). This leads to
> 
>       $ obj/apmd -dz0
>       apmd: invalid percent: too small: Result too large
> 
> apmd.8's SYNOPSIS does not reflect your changes.

Oh, I completely forgot about the SYNOPSIS, my apologies.

I also went with tedu@'s suggestion for errc(3), but only in the
getopt-loop, as I would most likely do more harm than good trying to
rewrite error().

The syslog(3) line, when suspending, was too long and corrected now.


Jesper Wallin


Index: usr.sbin/apmd/apmd.8
===================================================================
RCS file: /cvs/src/usr.sbin/apmd/apmd.8,v
retrieving revision 1.47
diff -u -p -r1.47 apmd.8
--- usr.sbin/apmd/apmd.8        12 Feb 2015 14:03:49 -0000      1.47
+++ usr.sbin/apmd/apmd.8        15 Aug 2017 14:57:31 -0000
@@ -38,6 +38,8 @@
 .Op Fl f Ar devname
 .Op Fl S Ar sockname
 .Op Fl t Ar seconds
+.Op Fl z Ar percent
+.Op Fl Z Ar percent
 .Sh DESCRIPTION
 .Nm
 monitors the advanced power management device,
@@ -113,6 +115,20 @@ The polling rate defaults to
 once per 10 minutes, but may be specified using the
 .Fl t
 command-line flag.
+.It Fl z Ar percent
+Automatically suspend the system if no AC is connected and the
+estimated battery life is equal or below
+.Ar percent .
+.It Fl Z Ar percent
+Automatically hibernate the system if no AC is connected and the
+estimated battery life is equal or below
+.Ar percent .
+.Pp
+If both 
+.Fl Z
+and
+.Fl z
+are specified, the first one will supersede the other.
 .El
 .Pp
 When a client requests a suspend or stand-by state,
Index: usr.sbin/apmd/apmd.c
===================================================================
RCS file: /cvs/src/usr.sbin/apmd/apmd.c,v
retrieving revision 1.79
diff -u -p -r1.79 apmd.c
--- usr.sbin/apmd/apmd.c        16 Nov 2015 17:35:05 -0000      1.79
+++ usr.sbin/apmd/apmd.c        15 Aug 2017 14:57:31 -0000
@@ -56,6 +56,9 @@
 #define TRUE 1
 #define FALSE 0
 
+#define AUTO_SUSPEND 1
+#define AUTO_HIBERNATE 2
+
 const char apmdev[] = _PATH_APM_CTLDEV;
 const char sockfile[] = _PATH_APM_SOCKET;
 
@@ -94,8 +97,8 @@ void
 usage(void)
 {
        fprintf(stderr,
-           "usage: %s [-AadHLs] [-f devname] [-S sockname] [-t seconds]\n",
-           __progname);
+           "usage: %s [-AadHLs] [-f devname] [-S sockname] [-t seconds] "
+               "[-z percent] [-Z percent]\n", __progname);
        exit(1);
 }
 
@@ -348,6 +351,8 @@ main(int argc, char *argv[])
 {
        const char *fname = apmdev;
        int ctl_fd, sock_fd, ch, suspends, standbys, hibernates, resumes;
+       int autoaction = 0;
+       int autolimit = 0;
        int statonly = 0;
        int powerstatus = 0, powerbak = 0, powerchange = 0;
        int noacsleep = 0;
@@ -355,13 +360,14 @@ main(int argc, char *argv[])
        struct apm_power_info pinfo;
        time_t apmtimeout = 0;
        const char *sockname = sockfile;
+       const char *errstr;
        int kq, nchanges;
        struct kevent ev[2];
        int ncpu_mib[2] = { CTL_HW, HW_NCPU };
        int ncpu;
        size_t ncpu_sz = sizeof(ncpu);
 
-       while ((ch = getopt(argc, argv, "aACdHLsf:t:S:")) != -1)
+       while ((ch = getopt(argc, argv, "aACdHLsf:t:S:z:Z:")) != -1)
                switch(ch) {
                case 'a':
                        noacsleep = 1;
@@ -402,6 +408,20 @@ main(int argc, char *argv[])
                        doperf = PERF_MANUAL;
                        setperfpolicy("high");
                        break;
+               case 'z':
+                       autoaction = AUTO_SUSPEND;
+                       autolimit = strtonum(optarg, 1, 100, &errstr);
+                       if (errstr != NULL)
+                               errc(1, EINVAL, "%s percentage: %s", errstr,
+                                   optarg);
+                       break;
+               case 'Z':
+                       autoaction = AUTO_HIBERNATE;
+                       autolimit = strtonum(optarg, 1, 100, &errstr);
+                       if (errstr != NULL)
+                               errc(1, EINVAL, "%s percentage: %s", errstr,
+                                   optarg);
+                       break;
                case '?':
                default:
                        usage();
@@ -479,6 +499,21 @@ main(int argc, char *argv[])
                        if (powerstatus != powerbak) {
                                powerstatus = powerbak;
                                powerchange = 1;
+                       }
+
+                       if (!powerstatus && autoaction &&
+                           autolimit > (int)pinfo.battery_life) {
+                               syslog(LOG_NOTICE,
+                                   "estimated battery life %d%%, "
+                                   "autoaction limit set to %d%% .",
+                                   pinfo.battery_life,
+                                   autolimit
+                               );
+
+                               if (autoaction == AUTO_SUSPEND)
+                                       suspend(ctl_fd);
+                               else
+                                       hibernate(ctl_fd);
                        }
                }
 

Reply via email to