0

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.

JdeBP
  • 68,745
WoJ
  • 1,545
  • 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 09 '18 at 07: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 09 '18 at 07: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 09 '18 at 07: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 09 '18 at 08: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 09 '18 at 08:13
  • @JdeBP: would "how can the running program check whether it was started by a systemd unit" fine for you? – WoJ Aug 09 '18 at 08:16
  • It doesn't address the part where you are doing the conflation. Here you go. – JdeBP Aug 09 '18 at 09:51

2 Answers2

2

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:
└─tinydns@127.53.0.1.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@127.53.0.1/service/run
#!/bin/nosh
#Run file generated from ./tinydns@.socket
#DNS/UDP socket on 127.53.0.1
udp-socket-listen --systemd-compatibility --combine4and6 127.53.0.1 domain
move-to-control-group "../tinydns@.service/tinydns@127.53.0.1.service"
envdir env
envuidgid -- tinydns-d
setlogin -- tinydns-d
hardlimit -d 3000000
softlimit -d hard
./service
% 

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

JdeBP
  • 68,745
0

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.

perror
  • 3,239
  • 7
  • 33
  • 45