Is there a documented way to check, from within the code of the program running as the service itself, that it has been started by systemd (as opposed to being started from within an interactive login session, from cron, etc.)?

My current solution is to define an environment variable in the .service unit (Environment=...) and check for its existence in my code. But there may be something directly available.

  • If you don't wrongly conflate prompts with shells and shells with login sessions, not only is the question clearer but you are halfway to an answer. – JdeBP Aug 9 '18 at 7:47
  • If your process is owned by a service and not some overarching scope, it's a safe bet that it was started by that service. – muru Aug 9 '18 at 7:56
  • @JdeBP: sorry but I do not understand. I can start my program either from a prompt (a login session), or via a non-login session such as a cron entry - so checking for a login/non-login environment not enough. I need to check if the program was started as part of a systemd service. It would help if your comment was more clear on what to check for. – WoJ Aug 9 '18 at 7:57
  • @muru: I realized that the question was not clear enough, fixed that. While the duplicate you mention is useful, it deals with a check outside of the code. I will use it, though, if there is no more straightforward way (by walking the PIDs in my code) – WoJ Aug 9 '18 at 8:11
  • A prompt is not a shell, nor is a shell a login session. Get the concepts right in what you ask, and not only will you have a clearer question that is halfway to an answer, you'll also see the conceptual error in what you just wrote about cron jobs. – JdeBP Aug 9 '18 at 8:13

One cannot.

Everything that systemd provides to a process invoked for a service — its arguments, its environment, the control group(s) containing it, its resource limits, its open file descriptors — can be and is done by other service managers, too. Moreover, there is no shared convention for identifying what service manager is managing services; no conventional environment variables, nor other markers.

Erroneous mechanisms

You might be thinking of checking the executable name of the parent process. This is a non-starter, for the reasons expounded in https://unix.stackexchange.com/a/196252/5132 . The name of the executable program image of the parent process (for system-wide services) will be /sbin/init on Debian Linux operating systems, because Debian has the convention of that being an alternatives-style symbolic link to the actual process 1 program image file, and the the /init program in the initramfs only needing to know that one name.

You might be thinking that, despite what I just wrote, control groups are a systemd marker. They are not. Here's the control group tree of a service process being managed by a completely different service manager, service-manager from the nosh toolset:

% systemd-cgls /system.slice/service-manager.service/tinydns@.service
Control group /system.slice/service-manager.service/tinydns@.service:
  └─1433 tinydns

The tinydns program, finding a control group in /proc/self/cgroup, has no justification for assuming that systemd set up that control group. It was actually set up by the move-to-control-group utility:

% cat /var/local/sv/tinydns@
#Run file generated from ./tinydns@.socket
#DNS/UDP socket on
udp-socket-listen --systemd-compatibility --combine4and6 domain
move-to-control-group "../tinydns@.service/tinydns@"
envdir env
envuidgid -- tinydns-d
setlogin -- tinydns-d
hardlimit -d 3000000
softlimit -d hard

No other process state changes are unique to systemd. Environment variables can be set with setenv (the chain-loading tool) userenv, machineenv, or export (the chain-loading tool), resource limits with softlimit, ulimit (the chain-loading tool), or s6-softlimit, open file descriptors with redirfd or fdredir, namespaces with unshare, scheduling priorities with rtprio or chrt, NUMA policy with numactl; and so forth.

systemd is not the only speaker of the LISTEN_FDS protocol, as can be seen from the aforegiven. INVOCATION_ID is likewise just an exercise in populating env/INVOCATION_ID at the start of a run program and chaining through envdir. None of these are reliable as markers.

Conceptual errors

There's also the flaw that you want to exclude processes started by cron. The conceptual flaw here is that cron is a service, and the processes that it spawns are running in the context of that service. There is no magic distinction between a process spawned by the cron process in the cron service and a process spawned by some other service process in some other service, that makes the former somehow distinguishable from the latter.

Rid yourself of this conceptual error, and an answer appears. The thing that distinguishes dæmons is that the (POSIX) sessions that they belong to do not have controlling terminals, and they have no other associations (from the name set by setlogin, through systemd's user-space login session mechanism, to various security contexts) with any login session. There's not a portable direct way to query what the controlling terminal of a session is, but noting that opening /dev/tty fails is an available indirect route. Note that some superficially promising C library functions are actually unreliable in practice.

Further reading

|improve this answer|||||

I guess that you can use the following command:

#> systemctl list-unit-files --state=enabled
cups.path                                  enabled        
accounts-daemon.service                    enabled        
anacron.service                            enabled        
apparmor.service                           enabled        
atd.service                                enabled        
autovt@.service                            enabled        
avahi-daemon.service                       enabled        

By itself systemctl list-unit-files list all installed unit files that may start a service. The ones labeled as enabled are the one started at the time you type the command.

|improve this answer|||||
  • Thanks, but as I mentioned in my question, I would like to check it from within the program – WoJ Aug 9 '18 at 7:59
  • Do you mean from the unit file itself ? – perror Aug 9 '18 at 8:00
  • 1
    systemctl list-unit-files --state=enabled – jasonwryan Aug 9 '18 at 8:02
  • @jasonwryan: Damn... so simpler... – perror Aug 9 '18 at 8:02
  • @perror: I realized that I was not clear enough, I clarified in the question. I meant from within the code of the program started in the service – WoJ Aug 9 '18 at 8:09

Not the answer you're looking for? Browse other questions tagged or ask your own question.