[patch] Add -z and -Z to apmd for automatic suspend/hibernate

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
13 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[patch] Add -z and -Z to apmd for automatic suspend/hibernate

Jesper Wallin
Hello tech@

I've been stuck with fsck for way to many times now because of me
forgetting to connect the AC power. This patch will add -z and -Z
followed by the percentage. apmd will try to suspend or hibernate the
system if the AC is not connected and the estimated battery life goes
below the specified percentage.


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 12 Aug 2017 21:18:28 -0000
@@ -113,6 +113,16 @@ 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 .
+This will supersedes
+.Fl z .
 .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 12 Aug 2017 21:18:28 -0000
@@ -94,8 +94,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 +348,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;
@@ -361,7 +363,7 @@ main(int argc, char *argv[])
  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 +404,14 @@ main(int argc, char *argv[])
  doperf = PERF_MANUAL;
  setperfpolicy("high");
  break;
+ case 'z':
+ autoaction = 1;
+ autolimit = strtoul(optarg, NULL, 0);
+ break;
+ case 'Z':
+ autoaction = 2;
+ autolimit = strtoul(optarg, NULL, 0);
+ break;
  case '?':
  default:
  usage();
@@ -479,6 +489,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 == 1)
+ suspend(ctl_fd);
+ else
+ hibernate(ctl_fd);
  }
  }
 

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [patch] Add -z and -Z to apmd for automatic suspend/hibernate

Martijn van Duren-5
Hello Jesper,

On 08/12/17 23:39, Jesper Wallin wrote:
> Hello tech@
>
> I've been stuck with fsck for way to many times now because of me
> forgetting to connect the AC power. This patch will add -z and -Z
> followed by the percentage. apmd will try to suspend or hibernate the
> system if the AC is not connected and the estimated battery life goes
> below the specified percentage.
>
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.

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.

martijn@

>
> 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 12 Aug 2017 21:18:28 -0000
> @@ -113,6 +113,16 @@ 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 .
> +This will supersedes
> +.Fl z .
>  .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 12 Aug 2017 21:18:28 -0000
> @@ -94,8 +94,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 +348,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;
> @@ -361,7 +363,7 @@ main(int argc, char *argv[])
>   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 +404,14 @@ main(int argc, char *argv[])
>   doperf = PERF_MANUAL;
>   setperfpolicy("high");
>   break;
> + case 'z':
> + autoaction = 1;
Use a define here to remove the use of magic numbers.
Similar discussion has been going around for the lidsuspend sysctl.
> + autolimit = strtoul(optarg, NULL, 0);
Use strtonum here, and check for errors.
> + break;
> + case 'Z':
> + autoaction = 2;
> + autolimit = strtoul(optarg, NULL, 0);
Same here.

> + break;
>   case '?':
>   default:
>   usage();
> @@ -479,6 +489,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 == 1)
> + suspend(ctl_fd);
> + else
> + hibernate(ctl_fd);
>   }
>   }
>  
>

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [patch] Add -z and -Z to apmd for automatic suspend/hibernate

Jesper Wallin
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);
  }
  }
 

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [patch] Add -z and -Z to apmd for automatic suspend/hibernate

Klemens Nanni
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 | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [patch] Add -z and -Z to apmd for automatic suspend/hibernate

Ted Unangst-6
Klemens Nanni wrote:

> > + case 'z':
> > + autoaction = AUTO_SUSPEND;
> > + autolimit = strtonum(optarg, 1, 100, &errstr);
> > + if (errstr != NULL)
> > + error("invalid percent: %s", errstr);
> > + break;
> 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

actually, both, but you should use something like errc() instead of errno.

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [patch] Add -z and -Z to apmd for automatic suspend/hibernate

Klemens Nanni
On Mon, Aug 14, 2017 at 11:21:03AM -0400, Ted Unangst wrote:

> Klemens Nanni wrote:
> > > + case 'z':
> > > + autoaction = AUTO_SUSPEND;
> > > + autolimit = strtonum(optarg, 1, 100, &errstr);
> > > + if (errstr != NULL)
> > > + error("invalid percent: %s", errstr);
> > > + break;
> > 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
>
> actually, both, but you should use something like errc() instead of errno.
Sure

        error("%s percentage: %s", errstr, optarg)

would be the idiomatic way but that requires changing error()'s
signature and usage all over apmd.c. Do you suggest replacing err(3)
with errc(3) in error()?

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [patch] Add -z and -Z to apmd for automatic suspend/hibernate

Craig Skinner-3
In reply to this post by Jesper Wallin
Hi Jesper/all,

On Sun, 13 Aug 2017 14:13:42 +0200 Jesper Wallin wrote:
>
> ... 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.


For what its worth, below is an unpriv duck tape cron ksh script,
which I've been meaning to port & package up... (It is very reliable.)

If the battery status is critical, it syslogs & wall(1)s.

When disaster seems iminent, it starts a delayed shutdown(8),
which it later kills if power is plugged.


<operator@fir:~ 0>$ crontab -l | fgrep batt-crit
*/5     *       *       *       *       ~/bin/batt-crit


<operator@fir:~ 0>$ cat ~/bin/batt-crit
#!/bin/ksh
#
# $Id: batt-crit,v 1.14 2016/05/13 13:22:58 craig Exp $
#
#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#
# Copyright (c) 2015-2016 Craig R. Skinner <[hidden email]>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#


# A/C charger ! disconnected
[[ $(apm -a) -ne 0 ]] && exit


# Battery status ! critical
[[ $(apm -b) -eq 2 ]] || exit 0


alias logger='logger -p daemon.crit'
apm | tr -s '\n' ' ' | logger


batt_lvl=$(apm -l)
[[ ${batt_lvl} -gt 15 ]] && exit
apm | wall
[[ ${batt_lvl} -gt 5 ]] && exit


warning='battery charge level critically low'
shutdown -hp +${batt_lvl} ${warning}
print "shutdown -hp +${batt_lvl} ${warning}" | logger


renice -n 20 $$ > /dev/null

count=100
until [[ ${count} -eq 0 ]]
do
        sleep 20
        [[ $(apm -a) -eq 0 ]] ||
        {
                pgrep -l -f shutdown &&
                {
                        print 'killing...'
                        pkill -l shutdown
                        break
                }
        }
        let count--
done


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [patch] Add -z and -Z to apmd for automatic suspend/hibernate

Jesper Wallin
In reply to this post by Klemens Nanni
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 | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [patch] Add -z and -Z to apmd for automatic suspend/hibernate

Ted Unangst-6
Jesper Wallin wrote:

> 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.

this looks good. will commit soon.

(one nit, i'll correct, is man page options are upper case first.)

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [patch] Add -z and -Z to apmd for automatic suspend/hibernate

Ted Unangst-6
In reply to this post by Jesper Wallin
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.

as regards the sensorsd approach, i've known about that possibility since
forever, and think about it every time i find my laptop has a dead battery,
but have never quite been motivated enough to set it up. i've heard the same
from several others. to me this suggests a certain usability hurdle. sensor
framework is great to make sure your scsi enclosure doesn't melt down and
sends you a page, but it's a little too diy for something as simple as
suspend. after all, we could eliminate lidsuspend/action and rely entirely on
sensors for that too, but that'd be silly.

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [patch] Add -z and -Z to apmd for automatic suspend/hibernate

Ingo Schwarze
Hi Ted,

Ted Unangst wrote on Tue, Aug 15, 2017 at 07:42:39PM -0400:
> 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.

> as regards the sensorsd approach, i've known about that possibility since
> forever, and think about it every time i find my laptop has a dead battery,
> but have never quite been motivated enough to set it up. i've heard the same
> from several others. to me this suggests a certain usability hurdle.

Recently, i looked at sensorsd because my laptop has a power supply with
a cable that keeps falling out, and the machine itself has no LEDs.

So when the cable falls out again, my screen turns red now.  When
configuring that, i noticed and fixed some inaccuracies and fuzzy
wordings in the manual pages, but i agree that this is still less
intuitive than the average OpenBSD utility.

Would adding something like the following to sensorsd.conf(5) EXAMPLES
lower the barrier?  It does look hackish, but i think that's due to the
design of sensorsd and hard to implement more cleanly.

  schwarze@isnote $ cat /etc/sensorsd.conf
  hw.sensors.acpiac0.indicator0:low=1:command=/etc/sensorsd/acpiac %2

  schwarze@isnote $ cat /etc/sensorsd/acpibat
  #!/bin/sh
  export XAUTHORITY=/home/schwarze/.Xauthority
  if [ "X$1" = "X2" ]; then
        xsetroot -display :0 -def
  else
        xsetroot -display :0 -solid red
  fi
  exit 0

Yours,
  Ingo

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [patch] Add -z and -Z to apmd for automatic suspend/hibernate

Ingo Schwarze
Whoa, and i promptly sent the wrong example.
Here is the working one:

  schwarze@isnote $ cat /etc/sensorsd.conf
  hw.sensors.acpiac0.indicator0:low=1:command=/etc/sensorsd/acpiac %2 %3 %4

  schwarze@isnote $ cat /etc/sensorsd/acpiac
  #!/bin/sh
  export XAUTHORITY=/home/schwarze/.Xauthority
  logger -p daemon.info -t acpiac status=$1 low=$2 high=$3
  if [ "X$1" = "XOn" ]; then
        xsetroot -display :0 -def
  else
        xsetroot -display :0 -solid red
  fi
  exit 0

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [patch] Add -z and -Z to apmd for automatic suspend/hibernate

Jesper Wallin
In reply to this post by Ted Unangst-6
On Tue, Aug 15, 2017 at 07:24:47PM -0400, Ted Unangst wrote:
> this looks good. will commit soon.
>
> (one nit, i'll correct, is man page options are upper case first.)

Noted for future reference. Thanks!

Loading...