systemd is a modern init system that manages the startup and supervision of services, processes, and other units on Linux systems. systemd provides various types of units to handle different kinds of tasks, such as service units, timer units, socket units, and path units.
In this article, I will explain what path units are, how they work, and how to use them to trigger services based on file or directory events. I will also show you an example of a path unit that monitors the /etc/passwd file for changes and sends an email alert when it happens.
What are Path Units?
Table of Contents
Path units are a type of systemd unit that monitor files or directories for certain events, such as creation, deletion, modification, or access. When a specified event occurs, a service unit is executed, and it usually carries the same name as the path unit (except for the suffix).
For example, a path unit named foo.path can activate a service unit named foo.service when a file or directory specified in foo.path changes.
Path units are useful for scenarios where you want to run a script or a command when a file or directory changes, without having to poll or watch it manually. For instance, you can use path units to:
- Backup or sync files when they are modified
- Restart or reload services when their configuration files change
- Send notifications or alerts when certain files or directories are accessed
- Run custom tasks based on file or directory events
How do Path Units Work?
Path units work by using the inotify API to monitor file systems for changes. inotify is a Linux kernel feature that allows applications to register for notifications on file or directory events. systemd uses inotify to monitor the paths specified in the path unit files and trigger the corresponding service units when an event occurs.
Path units have a [Path] section that defines the paths to monitor and the events to watch for. The following options are available:
- PathExists= : Triggers the service unit if the specified path exists
- PathExistsGlob= : Triggers the service unit if any of the paths matching the glob pattern exist
- PathChanged= : Triggers the service unit if the specified path is modified
- PathModified= : Triggers the service unit if the specified path is modified or its metadata is changed
- DirectoryNotEmpty= : Triggers the service unit if the specified directory is not empty
- Unit= : Specifies the service unit to activate when an event occurs (optional, defaults to the same name as the path unit)
You can specify multiple paths and events in a single path unit file. The service unit will be triggered if any of the specified conditions are met.
Path units also have a [Unit] section that defines the general properties and dependencies of the unit, such as Description= , After= , Requires= , etc. See systemd.unit(5) for more details.
Path units can be enabled, started, stopped, and restarted using the systemctl command, just like any other systemd unit.
Example: Monitor /etc/passwd and Send Email Alert
To demonstrate how to use path units, let’s create an example that monitors the /etc/passwd file for changes and sends an email alert when it happens.
To achieve this, we need three files:
- A script that sends the email alert
- A service unit that runs the script
- A path unit that monitors /etc/passwd and triggers the service
Create a Script for Email Alerts
Let’s start by creating a simple script that will send an email alert to our administrator. Create a file called email-alert.sh in the /usr/local/bin/ directory with the following contents:
#!/bin/bash mail -S sendwait -s "/etc/passwd CHANGED ON $(hostname)" [email protected] < /etc/passwd
This script uses the mail command to send an email with the subject “/etc/passwd CHANGED ON hostname” and the content of /etc/passwd as the message body. You can customize this script according to your needs and preferences.
Make sure that your system is configured correctly to send email and that you have mailx installed. You can test your script by running it manually:
sudo chmod +x /usr/local/bin/email-alert.sh sudo /usr/local/bin/email-alert.sh
You should receive an email from your system with the current content of /etc/passwd .
Create a Service Unit File to Execute Script
The next step is to create a service unit file that will run our script when triggered by our path unit. Create a file called passwd-mon.service in the /etc/systemd/system/ directory with the following contents:
[Unit] Description="Run script to send email alert" [Service] ExecStart=/usr/local/bin/email-alert.sh
This is a simple service unit file that only specifies the command to execute when started. You can add more options to customize your service behavior, such as Restart= , Environment= , etc. See systemd.service(5) for more details.
Create a Path Unit File
The final step is to create a path unit file that will monitor /etc/passwd for changes and activate our service unit when it happens. Create a file called passwd-mon.path in the /etc/systemd/system/ directory with the following contents:
[Unit] Description="Monitor /etc/passwd for changes" [Path] PathChanged=/etc/passwd Unit=passwd-mon.service [Install] WantedBy=multi-user.target
This path unit file specifies that we want to watch for changes in /etc/passwd and run passwd-mon.service when it happens. We also specify that we want this path unit to be enabled and started when the system reaches the multi-user target.
Test the Path Unit
Now that we have created all the necessary files, we can test our path unit by enabling, starting, and modifying /etc/passwd .
First, reload the systemd daemon to recognize our new unit files:
sudo systemctl daemon-reload
Then, enable and start our path unit:
sudo systemctl enable --now passwd-mon.path
You can check the status of our path unit with:
sudo systemctl status passwd-mon.path
You should see something like this:
passwd-mon.path - Monitor /etc/passwd for changes Loaded: loaded (/etc/systemd/system/passwd-mon.path; enabled; vendor preset: disabled) Active: active (waiting) since Tue 2021-11-16 15:10:24 UTC; 1min 3s ago Nov 16 15:10:24 ubuntu systemd: Started Monitor /etc/passwd for changes.
This means that our path unit is active and waiting for changes in /etc/passwd .
To test if our path unit works as expected, let’s modify /etc/passwd by adding or removing a user. For example, let’s create a new user called testuser:
sudo useradd testuser
This will change /etc/passwd and trigger our path unit. You can check the status of our service unit with:
sudo systemctl status passwd-mon.service
You should see something like this:
passwd-mon.service - Run script to send email alert Loaded: loaded (/etc/systemd/system/passwd-mon.service; static) Active: inactive (dead) since Tue 2021-11-16 15:11:38 UTC; 4s ago Process: 1234 ExecStart=/usr/local/bin/email-alert.sh (code=exited, status=0/SUCCESS) Main PID: 1234 (code=exited, status=0/SUCCESS) Nov 16 15:11:38 ubuntu systemd: Starting Run script to send email alert... Nov 16 15:11:38 ubuntu systemd: passwd-mon.service: Succeeded. Nov 16 15:11:38 ubuntu systemd: Finished Run script to send email alert.
This means that our service unit was started and executed our script successfully.
You should also receive an email from your system with the updated content of /etc/passwd .
In this article, I have shown you how to use systemd path units to monitor files or directories for events and execute service units accordingly. Path units are a powerful and convenient feature of systemd that can help you automate tasks based on file or directory changes.
I hope this article was helpful and informative for you. If you have any questions or feedback, please leave a comment below.
Frequently Asked Questions (FAQs)
Here are some frequently asked questions related to this topic:
Question: How can I list all the path units on my system?
Answer: You can use the command systemctl list-units –type=path to list all the path units on your system, whether they are active or not. You can also use systemctl list-unit-files –type=path to list all the path unit files installed on your system, whether they are enabled or not.
Question: How can I see the dependencies of a path unit?
Answer: You can use the command systemctl list-dependencies <unit> to see the dependencies of a path unit or any other type of unit. This will show you which units are required or wanted by the specified unit, as well as which units require or want the specified unit. You can also use the option –reverse to show only the reverse dependencies.