3 ms·
The main nice thing about the environment in systemd is that it is standard and mostly a blank slate, whereas at least for me I was always getting bit by the fa
by jchw 5mo ago
The main nice thing about the environment in systemd is that it is standard and mostly a blank slate, whereas at least for me I was always getting bit by the fact that the environment in Crontab was completely different from say, the environment inherited by supervisord or sysvinit scripts. In systemd the actual unit that gets executed is the same regardless of what triggers it, so there is no gap.
That does require you to still know what the default environment is, but it is a mostly completely clean environment, without any influence from any shell.
I'd have to concur that I agree this is an advantage of systemd.
- skydhash 5mo agoI use cron in OpenBSD and it's a deterministic environment and mostly clean[0]. I like that instead of having other subsystems creep in. [0]: https://man.openbsd.org/crontab.5#ENVIRONMENT https://man.openbsd.org/crontab.5#ENVIRONMENT
- simoncion 5mo ago> That does require you to still know what the default environment is, but it is a mostly completely clean environment, without any influence from any shell. Odd. This script #!/bin/bash set > /tmp/set.txt when scheduled like so * * * * * $HOME/bin/testCronScript.sh Produces this file in /tmp/set.txt which has had a handful of values (HOME, UID, etc) lightly redacted prior to posting here -to remove PII or for length- but its keys are entirely untouched: BASH=/bin/bash BASHOPTS=<redacted because long> BASH_ALIASES=() BASH_ARGC=() BASH_ARGV=() BASH_CMDS=() BASH_LINENO=([0]="0") BASH_LOADABLES_PATH=/usr/local/lib64/bash:/usr/lib64/bash BASH_SOURCE=([0]="/home/user/bin/testCronScript.sh") BASH_VERSINFO=<redacted bash 5.3.x> BASH_VERSION=<redacted bash 5.3.x> DIRSTACK=() EUID=13370 GROUPS=() HOME=/home/user HOSTNAME=hostname HOSTTYPE=x86_64 IFS=$' \t\n' LANG=en_US.utf8 LOGNAME=user MACHTYPE=x86_64-pc-linux-gnu OPTERR=1 OPTIND=1 OSTYPE=linux-gnu PATH=/usr/bin:/bin:/usr/sbin:/sbin PPID=1337 PS4='+ ' PWD=/home/user SHELL=/bin/sh SHELLOPTS=braceexpand:hashall:interactive-comments SHLVL=1 TERM=dumb UID=13370 USER=user _=/home/user/bin/testCronScript.sh Seems pretty clean to me. Even when I run this via /etc/crontab, rather than as a user cron job: * * * * * root /home/user/bin/testCronScript.sh I get effectively the same results. Maybe your distro's default cron environment was bad, and you never bothered to check and unset the badness? I'd be surprised if they were unable to make the default environment for Timer Units to be bad.
- jchw 5mo agoRegardless of exactly how clean the environment is, my favorite part of systemd is the fact that there is only one regardless of how something was triggered. Whether a unit is triggered via a mount unit, timer unit, udev rule, it's the same units at the end, so it's the same environment. The same problems that could be caused by a polluted environment in cron can be caused in reverse by a polluted environment elsewhere, when you unwittingly copy a command that depends on some environment being set. If you are using systemd as the service manager, this necessarily doesn't happen because it's all units. (Well, you could still copy something from outside of systemd and run into a similar problem, but at least there's essentially only one set of caveats you have to learn for whatever thing you want executed in the background.) So I guess this isn't so much cron vs systemd timers, but more cron + other init and service supervisors vs systemd init in general.
- simoncion 5mo ago> Regardless of exactly how clean the environment is, my favorite part of systemd is the fact that there is only one regardless of how something was triggered. Whether a unit is triggered via a mount unit, timer unit, udev rule, it's the same units at the end, so it's the same environment. > > The same problems that could be caused by a polluted environment in cron can be caused in reverse by a polluted environment elsewhere, when you unwittingly copy a command that depends on some environment being set. I'm confused about what you need this for? Are you running some utility command that needs the same environment provided by the daemon's service file? If so, any competent init system lets you extend upstream-provided service files. In OpenRC: # tail -n 1000 /etc/*/test-service ==> /etc/conf.d/test-service <== extra_commands="${extra_commands} maintenance" OTHER_THING="overriden other-thing" maintenance () { ebegin "doing maintenance. IV='$INIT_VAR' OT='$OTHER_THING'" set > /tmp/maintenance-set.txt eend 0 } ==> /etc/init.d/test-service <== #!/sbin/openrc-run name="test-service daemon" command=/usr/bin/socat command_user=nobody:nobody command_args="UDP-RECVFROM:6666,fork SYSTEM:'/bin/true'" supervisor=supervise-daemon extra_commands="rebuild" INIT_VAR=${INIT_VAR:-"init var"} OTHER_THING=${OTHER_THING:-"stock other-thing"} depend() { use net } start_pre() { set > /tmp/start-set.txt } rebuild () { ebegin "doing rebuild. IV='$INIT_VAR' OT='$OTHER_THING'" eend 0 } # /etc/init.d/test-service start test-service | * Starting test-service daemon ... [ ok ] # /etc/init.d/test-service maintenance test-service | * doing maintenance. IV='init var' OT='overriden other-thing' ... [ ok ] # /etc/init.d/test-service rebuild test-service | * doing rebuild. IV='init var' OT='overriden other-thing' ... [ ok ] # pgrep --list-full socat 133705 /usr/bin/socat UDP-RECVFROM:6666,fork SYSTEM:/bin/true The environment when the service is starting is effectively identical to the one when our custom function is being called: # diff -u0 /tmp/*-set.txt --- /tmp/maintenance-set.txt 2026-06-02 23:53:19.703048431 -0700 +++ /tmp/start-set.txt 2026-06-02 23:53:15.265094855 -0700 @@ -9 +9 @@ -BASH_LINENO=([0]="410" [1]="0") +BASH_LINENO=([0]="409" [1]="0") @@ -11 +11 @@ -BASH_SOURCE=([0]="/etc/init.d/../conf.d/test-service" [1]="/usr/libexec/rc/sh/openrc-run.sh") +BASH_SOURCE=([0]="/etc/init.d/test-service" [1]="/usr/libexec/rc/sh/openrc-run.sh") @@ -30 +30 @@ -FUNCNAME=([0]="maintenance" [1]="main") +FUNCNAME=([0]="start_pre" [1]="main") @@ -64 +64 @@ -PPID=133712 +PPID=133702 @@ -69 +69 @@ -RC_CMD=maintenance +RC_CMD=start @@ -73 +73 @@ -RC_OPENRC_PID=133710 +RC_OPENRC_PID=133700 @@ -75 +75 @@ -RC_RUNSCRIPT_PID=133711 +RC_RUNSCRIPT_PID=133701 @@ -93 +93 @@ -_='doing maintenance. IV='\''init var'\'' OT='\''overriden other-thing'\''' +_=']' So, if you need to do maintenance for a service on a schedule in the same environment that is provided for starting that service, you can simply extend the service script and use cron to execute that functionality. But. Another thing that confuses me is why you think that SystemD [0] provides anything special here? If you were to create a service file in most any other service manager and start it with cron, you'd get exactly the same environment sanitization as you get for all other services. Given your testimony, I expect that prior to SystemD, you'd have refused to create service files for things like one-off jobs that weren't system services... so why are you okay with it now that you're using SystemD? [0] I spell it "SystemD" not to mock it -as I understand some do- but to distinguish The Systemd Project from systemd(1). It sucks minor ass that the two share the same name, but what can you do?