Today I had my first real encounter with the new Linux world, with namespaces, cgroups and systemd. As it turns out, old wisdoms like “an absolute file path is an absolute file path” don’t hold any more :-)
But let’s start from the beginning. I just recently updated a machine to the latest openSUSE 13.1, which uses systemd unit files for a lot of services. I use this machine to develop a web application in PHP, and for debugging I wrote something to /tmp, like that:
<?php file_put_contents('/tmp/some-file', 'some-content'); ?>
The script always worked fine and it still does work fine. But not really the way I expected it to … The file /tmp/some-file does not exist after the script ran, even though I could read it back from PHP! Strange… the file simply seems to disappear!
After scratching my head for some time, I finally found out what’s going on:
$> cat /usr/lib/systemd/system/apache2.service [Unit] Description=The Apache Webserver Wants=network.target nss-lookup.target After=network.target nss-lookup.target Beforefirstname.lastname@example.org
[Service] Type=notify PrivateTmp=true EnvironmentFile=/etc/sysconfig/apache2 ExecStart=/usr/sbin/start_apache2 -D SYSTEMD -DFOREGROUND -k start ExecReload=/usr/sbin/start_apache2 -D SYSTEMD -DFOREGROUND -t -k graceful ExecStop=/usr/sbin/start_apache2 -D SYSTEMD -DFOREGROUND -k graceful-stop [Install] WantedBy=multi-user.target
I already highlighted the offending line in the unit file. What does it? Let’s have a look at the man page (man systemd.exec)
PrivateTmp= Takes a boolean argument. If true, sets up a new file system namespace for the executed processes and mounts private /tmp and /var/tmp directories inside it, that are not shared by processes outside of the namespace. This is useful to secure access to temporary files of the process, but makes sharing between processes via /tmp or /var/tmp impossible. All temporary data created by service will be removed after service is stopped. Defaults to false.
So yes, that’s the solution. Apache (and thus PHP, which runs as Apache module) sees a different /tmp as I do. The solution is easy obviously: either use a different directory for storing your files or disable PrivateTmp. The latter is quite easy as well, thanks to the configuration overrides in systemd (you may need to change the directory of the override, it’s the name of the unit + “.d”, see the announcement for details)
#> mkdir /etc/systemd/system/apache2.service.d #> echo -e "[Service]\nPrivateTmp=no" > /etc/systemd/system/apache2.service.d/privatetmp.conf #> systemctl daemon-reload #> systemctl restart apache2 #> systemctl show apache | grep PrivateTmp PrivateTmp=no