On Sun, Aug 13, 2017 at 02:13:42PM +0200, Jesper Wallin wrote:
> On Sun, Aug 13, 2017 at 09:52:22AM +0200, Martijn van Duren wrote:
> > I've also been bitten by this a couple of times, but you can also solve
> > this via the sensorsd framework, which is how I've done it.
> 
> Yeah, someone on IRC also suggested sensorsd or even ksh and a cronjob.
> I personally find it a bit too ducttapey though, especially for a
> feature one would expect on a laptop. This also saves me from running an
> extra daemon just in case my battery runs out.
> 
> > I'm no expert in this area and I'm not going to make any statements on
> > whether we should add this or not, but two (non functionality) nits
> > inline for future reference.
> 
> Thanks for the feedback, greatly appreciated! I've done a few changes
> and also rewrote some of the manual, as my previous patch was lying.
> 
> 
> 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      13 Aug 2017 11:50:16 -0000
> @@ -113,6 +113,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      13 Aug 2017 11:50:16 -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,18 @@ 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)
> +                             error("invalid percent: %s", errstr);
> +                     break;
> +             case 'Z':
> +                     autoaction = AUTO_HIBERNATE;
> +                     autolimit = strtonum(optarg, 1, 100, &errstr);
> +                     if (errstr != NULL)
> +                             error("invalid percent: %s", errstr);
> +                     break;
>               case '?':
>               default:
>                       usage();
> @@ -479,6 +497,20 @@ 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);
>                       }
>               }
>  
> 
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.

Reply via email to