15

I created a test service under /etc/systemd/system which is the correct path to create custom unit files.

[root@apollo system]# cat sample.service
[Unit]
Description=This is my test service
Wants=chronyd.service
After=chronyd.service

[Service]
Type=forking
ExecStart=/root/sample.sh

[Install]
WantedBy=multiuser.target chronyd.service
#RequiredBy=multiuser.target chronyd.service
#Alias=xyz
[root@apollo system]# pwd
/etc/systemd/system
[root@apollo system]#

I made sure systemd is aware by running "systemctl daemon-reload". I was also able to stop/start the service.

When I tried to mask it, it shows me this error:

[root@apollo system]# systemctl mask sample.service
Failed to execute operation: File exists
[root@apollo system]#

That is because systemd is trying to create a symlink using this command:

ln -s /dev/null /etc/systemd/system/sample.service

Since sample.service already exists inside /etc/systemd/system, the command will fail unless systemd will use "ln -fs".

So meaning we cannot mask any unit files we create under /etc/systemd/system?

I tried to move sample.service to /usr/lib/systemd/system and I was able to mask it because it was able to create a symlink under /etc/systemd/system without any hindrance.

Has anybody experience this? Do you think this is a bug?

2

3 Answers 3

13

There is not a way to mask services which have service files in /etc/systemd/system without first removing the file from there. This is intentional design.

You can disable the service by using systemctl disable servicename.service which will have the same effect as masking it in many cases.

The post by the author of systemd Three Levels of Off has more detail on the differences between stop, disable and mask in systemd.

0
0

Mark Stosberg's accepted answer is entirely correct and gladly upvoted: this is impossible by design. But I agree that masking your own service temporarily could be useful once in a lifetime—for example, while debugging, or because a piece of hardware is temporarily out of working order.

But since the endless discussion is endless, fake it if can't make it: rename your.service to your.service.masked and do systemctl daemon-reload so that systemd notices. The only downside is the service is not reported at all instead of existing but masked¹.

$ sudo mv -v /etc/systemd/system/dpkg-daily.service{,.masked}
renamed '/etc/systemd/system/dpkg-daily.service' -> '/etc/systemd/system/dpkg-daily.service.masked'
$ sudo systemctl daemon-reload
$ journalctl -n5
 . . .
Oct 06 18:31:16 [previous irrelevant message, logged 5.5 hours ago...
                 ... systemd itself is totally nonchalant about something ending in .masked ...]
Oct 06 23:53:57 buba systemd[1]: Reloading.
$ systemctl status dpkg-daily.service
Unit dpkg-daily.service could not be found. <== If you can live with that...

... and failed dependencies—but they would still fail if the unit were masked anyway. Note that you have no reason to mask a service unless it's started as a dependency of some other unit—just disable it in this case, as is recommended in the accepted answer.

$ sudo mv -v /etc/systemd/system/dpkg-daily.service{.masked,}
renamed '/etc/systemd/system/dpkg-daily.service.masked' -> '/etc/systemd/system/dpkg-daily.service'
$ sudo systemctl daemon-reload
$ systemctl status dpkg-daily.service
● dpkg-daily.service - Daily dpkg database backup
     Loaded: loaded (/etc/systemd/system/dpkg-daily.service; static)
     Active: inactive (dead) since Fri 2023-10-06 00:00:07 PDT; 24h ago
TriggeredBy: 🔴 dpkg-daily.timer  <=== A red dot for a failed dependency. The red Emoji is fake, of course.
 . . .

The matching .timer wasn't extremely happy about its disappeared dependency. Since the dependency has been "unmasked" now, reset failed units:

$ systemctl list-units --failed
  UNIT             LOAD   ACTIVE SUB    DESCRIPTION
● dpkg-daily.timer loaded failed failed Daily dpkg database backup
 . . .
$ sudo systemctl reset-failed
$ systemctl list-units --failed
  UNIT LOAD ACTIVE SUB DESCRIPTION
0 loaded units listed.

Two commands instead of one (mv and ...daemon-reload) aren't that bad. The closest to masking you can probably get.


¹ I have no idea how I got this service in /etc/systemd/system; I probably wrote it while getting rid of cron in Debian 10, back around the 2nd century BC, before upgrading to this distro, which is Debian 11 and long overdue an upgrade to 12, but I have no time. Newer Debians come with timers and services. A whole cron process for one daily and one weekly jobs felt kinda wasteful...


FWIW, such renaming is one of the ideas proposed in that thread, and the most acceptable by systemd design principles, as I understand them. This feature, if implemented, would be rather extremely rarely used, thus needs to be implemented using as few CPU cycles as possible, and, heaven save, without additional disk reads to determine if a unit is masked—but systemd reads the whole directory anyway.

0

Caution:
As mentioned in the comments, it's not recommended to make changes in the /lib directory. However, if you're dealing with a local issue, you might consider this solution. In my case, I didn't want a service to be accidentally run by anyone, so I used this approach and didn't ruin anything.


In case you are determined to mask the service, you have to move the unit’s configuration file to /lib/systemd/system.

sudo mv /etc/systemd/system/sample.service /lib/systemd/system/

After that you are able to run:

sudo systemctl mask sample.service

which will creat a symlink in /etc/systemd/system/sample.service.

3
  • Incorrrect: user/admin should not move service unit files under /lib Commented Sep 6, 2023 at 15:43
  • 1
    Please no. Never touch /lib when configuring systemd. /etc belongs to you, /lib to the distro vendor. Commented Oct 7, 2023 at 6:35
  • 1
    thank you for your feed back @scrat.squirrel . I've added a caution to inform people about the point
    – mahyard
    Commented Oct 7, 2023 at 10:37

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .