]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
tmpfiles: add %D specifier resolution
authorSkye Soss <skye@soss.website>
Sun, 31 May 2026 17:24:33 +0000 (12:24 -0500)
committerLuca Boccassi <luca.boccassi@gmail.com>
Sun, 21 Jun 2026 17:20:53 +0000 (18:20 +0100)
systemd-tmpfiles now resolves the %D specifier to /usr/share
(for the system manager) or $XDG_DATA_HOME (for the user manager).

Closes: https://github.com/systemd/systemd/issues/42010
Signed-off-by: Skye Soss <skye@soss.website>
man/standard-specifiers.xml
man/systemd.unit.xml
man/tmpfiles.d.xml
src/tmpfiles/tmpfiles.c
test/test-systemd-tmpfiles.py

index 3a2c0b0266a68b8abd751c932312dfa4610f8995..f4150531f2d7ccf0b4e64ea503a368a36c938893 100644 (file)
     <entry>Operating system build ID</entry>
     <entry>The operating system build identifier of the running system, as read from the <varname>BUILD_ID=</varname> field of <filename>/etc/os-release</filename>. If not set, resolves to an empty string. See <citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more information.</entry>
   </row>
+  <row id='D'>
+    <entry><literal>%D</literal></entry>
+    <entry>Shared data directory</entry>
+    <entry>This is either <filename>/usr/share/</filename> (for the system manager) or the path <literal>$XDG_DATA_HOME</literal> resolves to (for user managers).</entry>
+  </row>
   <row id='H'>
     <entry><literal>%H</literal></entry>
     <entry>Host name</entry>
index 5d2f32dfcefac1bc03b8ab05a3b7fdb347bee9c4..d032d91f3a08a7d0d5825525fa28d82bd19348bc 100644 (file)
             <entry>Credentials directory</entry>
             <entry>This is the value of the <literal>$CREDENTIALS_DIRECTORY</literal> environment variable if available. See section "Credentials" in <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more information.</entry>
           </row>
-          <row>
-            <entry><literal>%D</literal></entry>
-            <entry>Shared data directory</entry>
-            <entry>This is either <filename>/usr/share/</filename> (for the system manager) or the path <literal>$XDG_DATA_HOME</literal> resolves to (for user managers).</entry>
-          </row>
+          <xi:include href="standard-specifiers.xml" xpointer="D"/>
           <row>
             <entry><literal>%E</literal></entry>
             <entry>Configuration directory root</entry>
index e5f694611a60d25010e0f34987d690e4d4f83e95..00c6ecb39959d52834affea2d9da0d26a8d5a7eb 100644 (file)
@@ -778,6 +778,7 @@ d /tmp/foo/bar - - - bmA:1h -</programlisting></para>
               <entry>System or user cache directory</entry>
               <entry>In <option>--user</option> mode, this is the same as <varname>$XDG_CACHE_HOME</varname>, and <filename>/var/cache</filename> otherwise.</entry>
             </row>
+            <xi:include href="standard-specifiers.xml" xpointer="D"/>
             <row>
               <entry><literal>%g</literal></entry>
               <entry>User group</entry>
index 2c7ac181095788039e689aeaa5575065a494678d..82d682545786c89211f51457985fa9cbc19626c8 100644 (file)
@@ -205,6 +205,7 @@ typedef enum DirectoryType {
         DIRECTORY_STATE,
         DIRECTORY_CACHE,
         DIRECTORY_LOGS,
+        DIRECTORY_SHARED,
         _DIRECTORY_TYPE_MAX,
 } DirectoryType;
 
@@ -293,6 +294,7 @@ static int specifier_directory(
                 [DIRECTORY_STATE] =   { SD_PATH_SYSTEM_STATE_PRIVATE      },
                 [DIRECTORY_CACHE] =   { SD_PATH_SYSTEM_STATE_CACHE        },
                 [DIRECTORY_LOGS] =    { SD_PATH_SYSTEM_STATE_LOGS         },
+                [DIRECTORY_SHARED] =  { SD_PATH_SYSTEM_SHARED             },
         };
 
         static const struct table_entry paths_user[] = {
@@ -300,6 +302,7 @@ static int specifier_directory(
                 [DIRECTORY_STATE] =   { SD_PATH_USER_STATE_PRIVATE        },
                 [DIRECTORY_CACHE] =   { SD_PATH_USER_STATE_CACHE          },
                 [DIRECTORY_LOGS] =    { SD_PATH_USER_STATE_PRIVATE, "log" },
+                [DIRECTORY_SHARED] =  { SD_PATH_USER_SHARED               },
         };
 
         const struct table_entry *paths;
@@ -3907,6 +3910,7 @@ static int parse_line(
                 { 'h', specifier_user_home,       NULL },
 
                 { 'C', specifier_directory,       UINT_TO_PTR(DIRECTORY_CACHE)   },
+                { 'D', specifier_directory,       UINT_TO_PTR(DIRECTORY_SHARED)  },
                 { 'L', specifier_directory,       UINT_TO_PTR(DIRECTORY_LOGS)    },
                 { 'S', specifier_directory,       UINT_TO_PTR(DIRECTORY_STATE)   },
                 { 't', specifier_directory,       UINT_TO_PTR(DIRECTORY_RUNTIME) },
index 03022a9d5dedf966bd38bb3dcc165a3946a32fb7..10e6f69b56ac418ae6685d613d0f8fec2c72ada6 100755 (executable)
@@ -160,6 +160,13 @@ def test_valid_specifiers(*, user):
                  xdg_cache_home if user else '/var/cache',
                  user=user)  # fmt: skip
 
+    xdg_data_home = os.getenv('XDG_DATA_HOME')
+    if xdg_data_home is None and user:
+        xdg_data_home = os.path.join(home, '.local/share')
+    test_content('f {} - - - - %D',
+                 xdg_data_home if user else '/usr/share',
+                 user=user)  # fmt: skip
+
     test_content('f {} - - - - %L',
                  os.path.join(xdg_state_home, 'log') if user else '/var/log',
                  user=user)  # fmt: skip