The officially official Devuan Forum!

You are not logged in.

#1 2023-11-30 10:51:42

greenant
Member
Registered: 2022-05-04
Posts: 13  

missing sysvinit config for power-profiles-daemon

I am trying to access power profiles for AMD laptop (thinkpad 14s Gen4 AMD).

Devuan daedalus works well in general on this laptop but trying to set power profiles fails.

install:

apt install power-profiles-daemon

try to access power-profiles:

# powerprofilesctl get
Failed to communicate with power-profiles-daemon: g-dbus-error-quark: Error calling StartServiceByName for net.hadess.PowerProfiles: Launch helper exited with unknown return code 1 (25)

looks like the service is not running.

There is no sysvinit definition but there is a systemd unit file:

[Unit]
Description=Power Profiles daemon
Conflicts=tuned.service auto-cpufreq.service system76-power.service
Before=multi-user.target display-manager.target

[Service]
Type=dbus
BusName=net.hadess.PowerProfiles
ExecStart=/usr/libexec/power-profiles-daemon
Restart=on-failure
# This always corresponds to /var/lib/power-profiles-daemon
StateDirectory=power-profiles-daemon
#Uncomment this to enable debug
#Environment="G_MESSAGES_DEBUG=all"

# Lockdown
ProtectSystem=strict
ProtectControlGroups=true
ProtectHome=true
ProtectKernelModules=true
PrivateTmp=true
RestrictAddressFamilies=AF_UNIX AF_LOCAL AF_NETLINK
MemoryDenyWriteExecute=true
RestrictRealtime=true

[Install]
WantedBy=graphical.target

running the command directly does allow access to power profile:

/usr/libexec/power-profiles-daemon

I am looking to create a sysvinit file for this daemon.  I think I can do that with just the daemon command, but not sure if it should be connected to Dbus more explicitly?

Offline

#2 2023-11-30 12:35:55

aluma
Member
Registered: 2022-10-26
Posts: 646  

Re: missing sysvinit config for power-profiles-daemon

There is another solution - power management using DE.
In Trinity, for example, there is a tdepowersave program in which everything is configured in 15 seconds.
It hangs in the tray and issues warnings when necessary.
KDE5 has something similar.

Another question is that in Daedalus, turning off the laptop when closing the lid (this is how I set it up) happens every other time, sometimes it “falls asleep” in the middle of the process and to continue you need to open the lid.
There was no such glitch in Chimaera.

Regards.

Offline

#3 2023-12-01 00:10:44

GlennW
Member
From: Brisbane, Australia
Registered: 2019-07-18
Posts: 648  

Re: missing sysvinit config for power-profiles-daemon

# systemd to sysvinit startup script conversion
# ref. https://dev1galaxy.org/viewtopic.php?pid=23309#p23309

...has this handy link to a converting script.

sysd2v-0.3.sh , over 500 lines, 15kb file not at the link in that post...

#!/bin/sh
# sysd2v v0.3  --  systemd unit to sysvinit script converter
# Copyright (C) 2019  Trek http://www.trek.eu.org/devel/sysd2v
# distributed under the terms of the GNU General Public License 3

nl="
"

# read a systemd unit file and set variables named ini_{section}_{key}
# usage: read_unit filename instance
# filename	service unit configuration file, '-' to read from stdin
# instance	instance name for template units
read_unit()
{
  filename=$1
  instance=$2

  if [ "$filename" != - ]
  then
    inifile_unit_name=${filename##*/}
    inifile_unit_name=${inifile_unit_name%.*}
  fi

  rm_comm='/^[#;]/d'
  concat=':l; /\\$/ { N; s/[[:space:]]*\\\n/ /; tl }'
  subst_inst="s/%[Ii]/$instance/g"
  unit=$(
    cat "$filename" |
    sed "$rm_comm" |
    sed "$concat;$subst_inst"
  )
  section_list=$(
    printf %s "$unit" |
    sed -n 's/^\[\([[:alnum:]]\+\)\].*/\1/p'
  )
  oldifs=$IFS
  IFS=$nl

  for section in $section_list
  do
    get_sect='/^\['"$section"'\]/,/^\[.\+\]/'
    key_list=$(
      printf %s "$unit" |
      sed -n "$get_sect"'s/^\([[:alnum:]]\+\)[[:space:]]*=.*/\1/p' |
      sort -u
    )

    for key in $key_list
    do
      val=$(
        printf %s "$unit" |
        sed -n "$get_sect"'s/^'"$key"'[[:space:]]*=[[:space:]]*\(.*\)/\1/p'
      )
      var=$(
        echo "${section}_$key" |
        tr '[:upper:]' '[:lower:]'
      )
      eval ini_$var=\$val
      [ -n "$debug" ] && echo "ini_$var=$val" >&2
    done
  done

  IFS=$oldifs
}

# read a systemd configuration value and write its prefix to stdout
# usage: get_prefix val
# val		systemd configuration value
get_prefix () { printf %s "$1" | sed -n 's/^\([-@:+!|]*\).*/\1/p'; }

# read a boolean value and returns true or false
# usage: is_true val
# val		boolean value
is_true () { case "$1" in 1|[Oo][Nn]|[Tt]*|[Yy]*) true;; *) false; esac }

# read systemd services list and write LSB facilities to stdout
# usage: get_provides services
# services	list of service units
get_provides ()
{
  lst=
  for dep in $1
  do
    lst=${lst:+$lst }${dep%.service}
  done
  printf %s "$lst"
}

# read systemd units list and write LSB facilities to stdout
# usage: get_depends dependencies [ignores]
# dependencies	list of required units
# ignores	facilities to ignore
get_depends ()
{
  lst=
  for dep in $1
  do
    d=
    case $dep in
      local-fs-pre.target) d=mountkernfs;;
      time-sync.target) d=\$time;;
      systemd-modules-load.service) d=kmod;;
      local-fs.target|network-pre.target) d=\$local_fs;;
      systemd-sysctl.service) d=procps;;
      network.target|network-online.target|systemd-networkd.service)
        d=\$network;;
      nss-lookup.target) d=\$named;;
      rpcbind.target|remote-fs-pre.target) d=\$portmap;;
      remote-fs.target|sysinit.target|basic.target) d=\$remote_fs;;
      syslog.service) d=\$syslog;;
      boot-complete.target|multi-user.target|default.target) d=\$all;;
      *.service) d=${dep%.service};;
      *) echo "WARNING: unsupported target '$dep'" >&2
    esac

    ign=${2:+$2 }$lst
    [ -z "$ign" -o -n "${ign%%*"$d"*}" ] &&
      lst=${lst:+$lst }$d
  done

  printf %s "$lst"
}

# read LSB facilities list and write runlevel to stdout
# usage: get_runlevel facilities
# facilities	list of required facilities
get_runlevel ()
{
  case $1 in
    *\$remote_fs*) echo 2 3 4 5;;
    *) echo S
  esac
}

# write a list of environment files to be executed
# usage: write_env list
# list		files separated by newlines, with prefix (-)
write_env ()
{
  oldifs=$IFS
  IFS=$nl

  for env in $1
  do
    pre=$(get_prefix "$env")
    noerr=

    [ -n "$pre" -a -z "${pre%%*-*}" ] && noerr="[ -r ${env#$pre} ] && "

    printf '%s\n' "$noerr. ${env#$pre}"
  done

  IFS=$oldifs
}

# write an environment variable containing paths
# usage: write_path name prefix list
# name		name of the environment variable
# prefix	path prefix to append directories
# list		paths separated by spaces or newlines
write_path ()
{
  lst=
  for dir in $3
  do
    lst=${lst:+$lst:}$2/$dir
  done

  [ -z "$3" ] || printf '%s=%s\n' $1 $lst
}

# write a list of directories to be created
# usage: write_install prefix list [user [group [mode]]]
# prefix	path prefix to append directories
# list		paths separated by spaces or newlines
# user		user ownership
# group		group ownership
# mode		permission mode
write_install ()
{
  for dir in $2
  do
    printf '  install -d %s%s/%s || return 2\n' \
      "${3:+-o $3 }${4:+-g $4 }${5:+-m $5 }" "$1" "$dir"
  done
}

# write a list of commands applying systemd executable prefixes
# usage: write_commands list [run [runpriv]]
# list		commands separated by newlines, with prefixes (-@:+!)
# run		command line to run each command (nice, chrt, ...)
# runpriv	command line to set privileges (runuser, ...)
write_commands ()
{
  oldifs=$IFS
  IFS=$nl

  for cmd in $1
  do
    pre=$(get_prefix "$cmd")
    beg=$3
    end=' || return 2'

    if [ -n "$pre" ]
    then
      [ -z "${pre%%*-*}" ] && end=
      [ -z "${pre%%*[+!]*}" ] && beg=
      [ -z "${pre%%*[@:]*}" ] &&
        echo "WARNING: unsupported exec prefix '$pre'" >&2
    fi

    printf '  %s\n' "$2$beg${cmd#$pre}$end"
  done

  IFS=$oldifs
}

# read a list of commands separated by newlines and write an override function
# usage: write_function name [commands]
# name		function name (start_cmd, stop_cmd, ...)
# commands	list of commands, read from stdin if omitted
write_function ()
{
  lst=${2-$(cat)}

  [ -n "$lst" ] || return
  [ "$lst" = : ] && printf "do_${1}_override () :\n\n" && return

  end='  true\n'
  [ -z "${lst%%*|| return [0-9]}" -o -z "${lst%%*|| return \$?}" ] && end=
  printf "do_${1}_override ()\n{\n%s\n$end}\n\n" "$lst"
}

# write an init-d-script file starting from the ini_* vars (see read_unit)
# usage: write_init servicename instance
# servicename	name of the service provided
# instance	instance name for template units
write_init ()
{
  name=$1
  instance=$2

  if [ "${name%@}" != "$name" ]
  then
    name=$name$instance
  fi

  daemon_pre=$(get_prefix "$ini_service_execstart")
  daemon=${ini_service_execstart#$daemon_pre}

  if [ "${daemon%%[[:space:]]*}" != "$daemon" ]
  then
    daemon_args=${daemon#*[[:space:]]}
    daemon=${daemon%%[[:space:]]*}
  fi

  pidfile=$ini_service_pidfile

  if [ -n "$ini_service_user" ]
  then
    start_args="--user $ini_service_user"
    [ -n "$daemon_pre" -a -z "${daemon_pre%%*[+!]*}" ] ||
      start_args="$start_args --chuid $ini_service_user"
    stop_args="--user $ini_service_user"
    runprivstart="runuser -u $ini_service_user -- "
    is_true "$ini_service_permissionsstartonly" || runpriv=$runprivstart
  fi

  cls=$ini_service_ioschedulingclass
  pri=$ini_service_ioschedulingpriority
  [ -n "$cls$pri" ] &&
    start_args="$start_args --iosched ${cls:-best-effort}${pri:+:$pri}" &&
    run="ionice ${cls:+-c $cls }${pri:+-n $pri }"

  pol=$ini_service_cpuschedulingpolicy
  pri=$ini_service_cpuschedulingpriority
  [ -n "$pol$pri" ] &&
    start_args="$start_args --procsched ${pol:-other}${pri:+:$pri}" &&
    run="${run}chrt ${pol:+--$pol }${pri:-0} "

  [ -n "$ini_service_nice" ] &&
    start_args="$start_args --nicelevel $ini_service_nice" &&
    run="${run}nice -n $ini_service_nice "

  pre=$(get_prefix "$ini_service_workingdirectory")
  workdir=${ini_service_workingdirectory#$pre}
  [ "$workdir" = '~' ] && workdir=\~$ini_service_user
  [ -n "$workdir" ] &&
    start_args="$start_args --chdir $workdir" &&
    chdir="${pre}cd $workdir"

  if [ -z "${service_type:=$ini_service_type}" ]
  then
    if [ -n "$ini_service_busname" ]
    then
      service_type=dbus
    elif [ -n "$ini_service_execstart" ]
    then
      service_type=simple
    else
      service_type=oneshot
    fi
  fi

  if [ "$service_type" != forking ]
  then
    start_args="$start_args --background"
    [ -z "$pidfile" -a "$ini_service_killmode" != none ] &&
      start_args="$start_args --make-pidfile" &&
      pidfile="/var/run/$name-sysd2v.pid"
  fi

  if [ "$service_type" = notify ]
  then
    start_args="$start_args --notify-await"
    timeout=${ini_service_timeoutstartsec:-$ini_service_timeoutsec}
    timeout=${timeout%s}
    [ -n "${timeout#60}" ] &&
      start_args="$start_args --notify-timeout $timeout"
    [ -n "$timeout" -a -z "${timeout%%*[^0-9]*}" ] &&
      echo "WARNING: unsupported timeout '$timeout'" >&2
  elif [ "$service_type" = dbus ]
  then
    : TODO
  fi

  signal=${ini_service_killsignal#SIG}
  timeout=${ini_service_timeoutstopsec:-$ini_service_timeoutsec}
  timeout=${timeout%s}
  [ -n "${signal#TERM}" -o -n "${timeout#90}" ] &&
    stop_args="$stop_args --retry=${signal:-TERM}/${timeout:-90}/KILL/5"

  limitnofile=$ini_service_limitnofile
  [ "$limitnofile" = infinity ] && limitnofile=unlimited

  need_install=$ini_service_runtimedirectory
  need_install=$need_install$ini_service_statedirectory
  need_install=$need_install$ini_service_cachedirectory
  need_install=$need_install$ini_service_logsdirectory
  need_install=$need_install$ini_service_configurationdirectory

  need_do_start=$ini_service_execstartpre$ini_service_execstartpost
  need_do_start=$need_do_start$need_install

  execstop=$ini_service_execstop

  if [ "$service_type" != oneshot ]
  then
    [ "$pidfile" = "/var/run/${daemon##*/}.pid" ] && unset pidfile
    [ "$name" = "${daemon##*/}" ] && unset name

    [ -n "$daemon_args" -a -z "${daemon_args%%*[\"\\]*}" ] &&
      echo "WARNING: DAEMON_ARGS needs to be escaped" >&2
    errcheck=' || return $?'

    if [ -n "$daemon_pre" ]
    then
      [ -z "${daemon_pre%%*-*}" ] && errcheck=
      [ -z "${daemon_pre%%*[@:]*}" ] &&
        echo "WARNING: unsupported exec prefix '$daemon_pre'" >&2
    fi

    # TODO: test if already running before start (pretest="+do_status_cmd")
    [ -n "$need_do_start" -o -z "$errcheck" ] &&
      execstart="-+do_start_cmd$errcheck"

    errcheck=' || return $?'
    [ -n "$execstop" ] && errcheck=
    [ -n "$execstop$ini_service_execstoppost" -a \
      "$ini_service_killmode" != none ] &&
      killstop="-do_stop_cmd$errcheck"

    [ -n "$timeout" -a -z "${timeout%%*[^0-9]*}" ] &&
      echo "WARNING: unsupported timeout '$timeout'" >&2
  else
    daemon=none
    pidfile=none
    : ${name:=SERVICE_NAME}
    unset daemon_args start_args stop_args
    execstart=$ini_service_execstart
    runstart=$run
  fi

  need_do_start=$need_do_start$execstart
  start_args=${start_args# }
  stop_args=${stop_args# }

  aliases=$(get_provides "$ini_install_alias")

  [ -z "$ini_unit_defaultdependencies" ] ||
    is_true "$ini_unit_defaultdependencies" &&
    defdep=sysinit.target

  req_start=$(get_depends "$ini_unit_requires $defdep")
  should_start=$(get_depends "$ini_unit_wants $ini_unit_after" "$req_start")

  default_start=$(get_runlevel "$req_start $should_start")
  [ "$default_start" = S ] && default_stop='0 6' || default_stop='0 1 6'
  [ -z "$execstop$ini_service_execstoppost" ] &&
    [ "$service_type" = oneshot -o "$ini_service_killmode" = none ] &&
    default_stop=

  [ "$default_start" = S ] && ignore=\$remote_fs
  start_before=$(get_depends "$ini_unit_requiredby $ini_install_wantedby
    $ini_unit_before" "$req_start $should_start \$all $ignore")

  cat <<EOF
#!/bin/sh
# Generated by sysd2v v0.3  --  http://www.trek.eu.org/devel/sysd2v
# kFreeBSD do not accept scripts as interpreters, using #!/bin/sh and sourcing.
if [ true != "\$INIT_D_SCRIPT_SOURCED" ] ; then
    set "\$0" "\$@"; INIT_D_SCRIPT_SOURCED=true . /lib/init/init-d-script
fi
### BEGIN INIT INFO
# Provides:       ${name:-${daemon##*/}}${aliases:+ $aliases}
# Required-Start: $req_start
# Required-Stop:  ${default_stop:+$req_start}
${should_start:+# Should-Start:   $should_start
${default_stop:+# Should-Stop:    $should_start
}}${start_before:+# X-Start-Before: $start_before
${default_stop:+# X-Stop-After:   $start_before
}}# Default-Start:  $default_start
# Default-Stop:   $default_stop
# Description:    ${ini_unit_description:-SERVICE_DESCRIPTION}
### END INIT INFO
EOF

  if [ -n "$ini_service_environment$ini_service_environmentfile$need_install" ]
  then
    echo set -a
    write_path RUNTIME_DIRECTORY /run "$ini_service_runtimedirectory"
    write_path STATE_DIRECTORY /var/lib "$ini_service_statedirectory"
    write_path CACHE_DIRECTORY /var/cache "$ini_service_cachedirectory"
    write_path LOGS_DIRECTORY /var/log "$ini_service_logsdirectory"
    write_path CONFIGURATION_DIRECTORY /etc \
      "$ini_service_configurationdirectory"
    printf '%s' "${ini_service_environment:+$ini_service_environment$nl}"
    write_env "$ini_service_environmentfile"
    printf 'set +a\n\n'
  fi

  cat <<EOF
${name:+DESC=\"$name\"
}DAEMON=$daemon
${daemon_args:+DAEMON_ARGS=\"$daemon_args\"
}${pidfile:+PIDFILE=$pidfile
}${start_args:+START_ARGS=\"$start_args\"
}${stop_args:+STOP_ARGS=\"$stop_args\"
}${limitnofile:+ulimit -n $limitnofile
}${ini_service_umask:+umask $ini_service_umask
}
EOF

  if [ -n "$need_do_start" ]
  then
    {
      write_install /run "$ini_service_runtimedirectory" \
        "$ini_service_user" "$ini_service_group" \
        "$ini_service_runtimedirectorymode"
      write_install /var/lib "$ini_service_statedirectory" \
        "$ini_service_user" "$ini_service_group" \
        "$ini_service_statedirectorymode"
      write_install /var/cache "$ini_service_cachedirectory" \
        "$ini_service_user" "$ini_service_group" \
        "$ini_service_cachedirectorymode"
      write_install /var/log "$ini_service_logsdirectory" \
        "$ini_service_user" "$ini_service_group" \
        "$ini_service_logsdirectorymode"
      write_install /etc "$ini_service_configurationdirectory" '' '' \
        "$ini_service_configurationdirectorymode"
      write_commands "$chdir"
      write_commands "$ini_service_execstartpre" "$run" "$runpriv"
      write_commands "$execstart" "$runstart" "$runprivstart"
      write_commands "$ini_service_execstartpost" "$run" "$runpriv"
    } | write_function start_cmd
  else
    [ "$service_type" = oneshot ] && write_function start :
  fi

  if [ -n "$execstop$ini_service_execstoppost" ]
  then
    {
      write_commands "$chdir"
      write_commands "$execstop" "$run" "$runpriv"
      write_commands "$killstop"
      write_commands "$ini_service_execstoppost" "$run" "$runpriv"
    } | write_function stop_cmd
  else
    [ "$service_type" = oneshot -o "$ini_service_killmode" = none ] &&
      write_function stop :
  fi

  if [ "$ini_service_execreload" = '/bin/kill -HUP $MAINPID' -a \
       -z "$run$runpriv" ]
  then
    printf 'alias do_reload=do_reload_sigusr1\n\n'
  elif [ -n "$ini_service_execreload" ]
  then
    {
      write_commands "$chdir"
      write_commands "$ini_service_execreload" "$run" "$runpriv"
    } | write_function reload_cmd

    cat <<"EOF"
do_reload ()
{
  log_daemon_msg "Reloading $DESC configuration files" "$NAME"
  MAINPID=$(cat $PIDFILE)
  do_reload_cmd_override
  log_end_msg $?
}
EOF
  fi

  [ "$service_type" = oneshot ] && write_function status :
}

# parse command line
while getopts di:n: opt
do
    case $opt in
      d) debug=1;;
      i) instance=$OPTARG;;
      n) name=$OPTARG;;
      ?) printf "Usage: %s [-d] [-i instance] [-n servicename] [filename]\n" \
           "$0"
         exit 2;;
    esac
done

: ${instance=INSTANCE_NAME}
shift $(($OPTIND - 1))

# convert unit file
read_unit "${1:--}" "$instance"
write_init "${name-$inifile_unit_name}" "$instance"

I have a copy... (not sure if I may post it here in code tags???)
happy to share.

Maybe it'll work for you. Just look out for start and stop levels being consistent with your system.

Last edited by GlennW (2023-12-01 00:51:28)


pic from 1993, new guitar day.

Offline

#4 2023-12-01 02:14:06

greenant
Member
Registered: 2022-05-04
Posts: 13  

Re: missing sysvinit config for power-profiles-daemon

Thanks GlennW, a useful script!

There are a few things to consider as far as the best power management solution...

Here are some useful references:
- https://www.reddit.com/r/thinkpad/comme … ittle_fan/
- https://wiki.archlinux.org/title/Lenovo … -State_EPP
- https://www.phoronix.com/review/linux-65-thinkpad
- https://www.phoronix.com/news/Linux-6.6 … Management

Currently, I am using the 6.5.0.0. kernel from daedalus-backports.

aluma, if you are having sleep issues, you may want to try that kernel, no sleep issues for me.
However, the wifi driver doesn't wake from hibernate (known issue for that kernel driver)
- https://wiki.archlinux.org/title/Lenovo … ibernation

Note that I have tried the suggestion from the reddit post above and getting good power utilisation rate now (around 5.5 - 7W which should give close to 10hr battery life).

echo 'power' | tee /sys/devices/system/cpu/cpu*/cpufreq/energy_performance_preference

I will write up an install guide for Devuan for the laptop soon, but looks really good and should improve even further with new kernel releases.

Offline

Board footer