]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/xdg-autostart-generator/xdg-autostart-service.c
tree-wide: use ASSERT_PTR more
[thirdparty/systemd.git] / src / xdg-autostart-generator / xdg-autostart-service.c
index ed9301d809cee0678a4331aca4d53d039b976357..75b6a62a9750c6bf9432c644bf36dd880c8b7f00 100644 (file)
@@ -73,12 +73,11 @@ static int xdg_config_parse_bool(
                 void *data,
                 void *userdata) {
 
-        bool *b = data;
+        bool *b = ASSERT_PTR(data);
 
         assert(filename);
         assert(lvalue);
         assert(rvalue);
-        assert(data);
 
         if (streq(rvalue, "true"))
                 *b = true;
@@ -157,13 +156,12 @@ static int xdg_config_parse_string(
                 void *userdata) {
 
         _cleanup_free_ char *res = NULL;
-        char **out = data;
+        char **out = ASSERT_PTR(data);
         int r;
 
         assert(filename);
         assert(lvalue);
         assert(rvalue);
-        assert(data);
 
         /* XDG does not allow duplicate definitions. */
         if (*out) {
@@ -188,7 +186,6 @@ static int strv_strndup_unescape_and_push(
                 const char *filename,
                 unsigned line,
                 char ***sv,
-                size_t *n_allocated,
                 size_t *n,
                 const char *start,
                 const char *end) {
@@ -207,7 +204,7 @@ static int strv_strndup_unescape_and_push(
         if (r < 0)
                 return r;
 
-        if (!greedy_realloc((void**) sv, n_allocated, *n + 2, sizeof(char*))) /* One extra for NULL */
+        if (!GREEDY_REALLOC(*sv, *n + 2)) /* One extra for NULL */
                 return log_oom();
 
         (*sv)[*n] = TAKE_PTR(copy);
@@ -229,13 +226,12 @@ static int xdg_config_parse_strv(
                 void *data,
                 void *userdata) {
 
-        char ***ret_sv = data;
+        char ***ret_sv = ASSERT_PTR(data);
         int r;
 
         assert(filename);
         assert(lvalue);
         assert(rvalue);
-        assert(data);
 
         /* XDG does not allow duplicate definitions. */
         if (*ret_sv) {
@@ -243,10 +239,10 @@ static int xdg_config_parse_strv(
                 return 0;
         }
 
-        size_t n = 0, n_allocated = 0;
+        size_t n = 0;
         _cleanup_strv_free_ char **sv = NULL;
 
-        if (!GREEDY_REALLOC0(sv, n_allocated, 1))
+        if (!GREEDY_REALLOC0(sv, 1))
                 return log_oom();
 
         /* We cannot use strv_split because it does not handle escaping correctly. */
@@ -265,7 +261,7 @@ static int xdg_config_parse_strv(
 
                 if (*end == ';') {
                         r = strv_strndup_unescape_and_push(unit, filename, line,
-                                                           &sv, &n_allocated, &n,
+                                                           &sv, &n,
                                                            start, end);
                         if (r < 0)
                                 return r;
@@ -276,7 +272,7 @@ static int xdg_config_parse_strv(
 
         /* Handle the trailing entry after the last separator */
         r = strv_strndup_unescape_and_push(unit, filename, line,
-                                           &sv, &n_allocated, &n,
+                                           &sv, &n,
                                            start, end);
         if (r < 0)
                 return r;
@@ -289,22 +285,22 @@ static int xdg_config_item_table_lookup(
                 const void *table,
                 const char *section,
                 const char *lvalue,
-                ConfigParserCallback *func,
-                int *ltype,
-                void **data,
+                ConfigParserCallback *ret_func,
+                int *ret_ltype,
+                void **ret_data,
                 void *userdata) {
 
         assert(lvalue);
 
         /* Ignore any keys with [] as those are translations. */
         if (strchr(lvalue, '[')) {
-                *func = NULL;
-                *ltype = 0;
-                *data = NULL;
+                *ret_func = NULL;
+                *ret_ltype = 0;
+                *ret_data = NULL;
                 return 1;
         }
 
-        return config_item_table_lookup(table, section, lvalue, func, ltype, data, userdata);
+        return config_item_table_lookup(table, section, lvalue, ret_func, ret_ltype, ret_data, userdata);
 }
 
 XdgAutostartService *xdg_autostart_service_parse_desktop(const char *path) {
@@ -320,33 +316,34 @@ XdgAutostartService *xdg_autostart_service_parse_desktop(const char *path) {
                 return NULL;
 
         const ConfigTableItem items[] = {
-                { "Desktop Entry", "Name",                      xdg_config_parse_string, 0, &service->description},
-                { "Desktop Entry", "Exec",                      xdg_config_parse_string, 0, &service->exec_string},
-                { "Desktop Entry", "Path",                      xdg_config_parse_string, 0, &service->working_directory},
-                { "Desktop Entry", "TryExec",                   xdg_config_parse_string, 0, &service->try_exec},
-                { "Desktop Entry", "Type",                      xdg_config_parse_string, 0, &service->type},
-                { "Desktop Entry", "OnlyShowIn",                xdg_config_parse_strv, 0,   &service->only_show_in},
-                { "Desktop Entry", "NotShowIn",                 xdg_config_parse_strv, 0,   &service->not_show_in},
-                { "Desktop Entry", "Hidden",                    xdg_config_parse_bool, 0,   &service->hidden},
-                { "Desktop Entry", "AutostartCondition",        xdg_config_parse_string, 0, &service->autostart_condition},
-                { "Desktop Entry", "X-KDE-autostart-condition", xdg_config_parse_string, 0, &service->kde_autostart_condition},
-                { "Desktop Entry", "X-GNOME-Autostart-Phase",   xdg_config_parse_string, 0, &service->gnome_autostart_phase},
-                { "Desktop Entry", "X-systemd-skip",            xdg_config_parse_bool, 0,   &service->systemd_skip},
+                { "Desktop Entry", "Name",                      xdg_config_parse_string, 0, &service->description             },
+                { "Desktop Entry", "Exec",                      xdg_config_parse_string, 0, &service->exec_string             },
+                { "Desktop Entry", "Path",                      xdg_config_parse_string, 0, &service->working_directory       },
+                { "Desktop Entry", "TryExec",                   xdg_config_parse_string, 0, &service->try_exec                },
+                { "Desktop Entry", "Type",                      xdg_config_parse_string, 0, &service->type                    },
+                { "Desktop Entry", "OnlyShowIn",                xdg_config_parse_strv,   0, &service->only_show_in            },
+                { "Desktop Entry", "NotShowIn",                 xdg_config_parse_strv,   0, &service->not_show_in             },
+                { "Desktop Entry", "Hidden",                    xdg_config_parse_bool,   0, &service->hidden                  },
+                { "Desktop Entry", "AutostartCondition",        xdg_config_parse_string, 0, &service->autostart_condition     },
+                { "Desktop Entry", "X-KDE-autostart-condition", xdg_config_parse_string, 0, &service->kde_autostart_condition },
+                { "Desktop Entry", "X-GNOME-Autostart-Phase",   xdg_config_parse_string, 0, &service->gnome_autostart_phase   },
+                { "Desktop Entry", "X-systemd-skip",            xdg_config_parse_bool,   0, &service->systemd_skip            },
 
                 /* Common entries that we do not use currently. */
-                { "Desktop Entry", "Categories", NULL, 0, NULL},
-                { "Desktop Entry", "Comment", NULL, 0, NULL},
-                { "Desktop Entry", "Encoding", NULL, 0, NULL},
-                { "Desktop Entry", "GenericName", NULL, 0, NULL},
-                { "Desktop Entry", "Icon", NULL, 0, NULL},
-                { "Desktop Entry", "Keywords", NULL, 0, NULL},
-                { "Desktop Entry", "MimeType", NULL, 0, NULL},
-                { "Desktop Entry", "NoDisplay", NULL, 0, NULL},
-                { "Desktop Entry", "StartupNotify", NULL, 0, NULL},
-                { "Desktop Entry", "StartupWMClass", NULL, 0, NULL},
-                { "Desktop Entry", "Terminal", NULL, 0, NULL},
-                { "Desktop Entry", "URL", NULL, 0, NULL},
-                { "Desktop Entry", "Version", NULL, 0, NULL},
+                { "Desktop Entry", "Categories",                NULL, 0, NULL},
+                { "Desktop Entry", "Comment",                   NULL, 0, NULL},
+                { "Desktop Entry", "DBusActivatable",           NULL, 0, NULL},
+                { "Desktop Entry", "Encoding",                  NULL, 0, NULL},
+                { "Desktop Entry", "GenericName",               NULL, 0, NULL},
+                { "Desktop Entry", "Icon",                      NULL, 0, NULL},
+                { "Desktop Entry", "Keywords",                  NULL, 0, NULL},
+                { "Desktop Entry", "MimeType",                  NULL, 0, NULL},
+                { "Desktop Entry", "NoDisplay",                 NULL, 0, NULL},
+                { "Desktop Entry", "StartupNotify",             NULL, 0, NULL},
+                { "Desktop Entry", "StartupWMClass",            NULL, 0, NULL},
+                { "Desktop Entry", "Terminal",                  NULL, 0, NULL},
+                { "Desktop Entry", "URL",                       NULL, 0, NULL},
+                { "Desktop Entry", "Version",                   NULL, 0, NULL},
                 {}
         };
 
@@ -375,20 +372,17 @@ int xdg_autostart_format_exec_start(
         int r;
 
         /*
-         * Unfortunately, there is a mismatch between systemd's idea of $PATH
-         * and XDGs. i.e. we need to ensure that we have an absolute path to
-         * support cases where $PATH has been modified from the default set.
+         * Unfortunately, there is a mismatch between systemd's idea of $PATH and XDGs. I.e. we need to
+         * ensure that we have an absolute path to support cases where $PATH has been modified from the
+         * default set.
          *
-         * Note that this is only needed for development environments though;
-         * so while it is important, this should have no effect in production
-         * environments.
+         * Note that this is only needed for development environments though; so while it is important, this
+         * should have no effect in production environments.
          *
-         * To be compliant with the XDG specification, we also need to strip
-         * certain parameters and such. Doing so properly makes parsing the
-         * command line unavoidable.
+         * To be compliant with the XDG specification, we also need to strip certain parameters and
+         * such. Doing so properly makes parsing the command line unavoidable.
          *
-         * NOTE: Technically, XDG only specifies " as quotes, while this also
-         *       accepts '.
+         * NOTE: Technically, XDG only specifies " as quotes, while this also accepts '.
          */
         r = strv_split_full(&exec_split, exec, NULL, EXTRACT_UNQUOTE | EXTRACT_RELAX);
         if (r < 0)
@@ -399,11 +393,12 @@ int xdg_autostart_format_exec_start(
 
         first_arg = true;
         for (i = n = 0; exec_split[i]; i++) {
-                _cleanup_free_ char *c = NULL, *raw = NULL, *p = NULL, *escaped = NULL, *quoted = NULL;
+                _cleanup_free_ char *c = NULL, *raw = NULL, *percent = NULL;
+                ssize_t l;
 
-                r = cunescape(exec_split[i], 0, &c);
-                if (r < 0)
-                        return log_debug_errno(r, "Failed to unescape '%s': %m", exec_split[i]);
+                l = cunescape(exec_split[i], 0, &c);
+                if (l < 0)
+                        return log_debug_errno(l, "Failed to unescape '%s': %m", exec_split[i]);
 
                 if (first_arg) {
                         _cleanup_free_ char *executable = NULL;
@@ -414,60 +409,45 @@ int xdg_autostart_format_exec_start(
                         if (r < 0)
                                 return log_info_errno(r, "Exec binary '%s' does not exist: %m", c);
 
-                        escaped = cescape(executable);
-                        if (!escaped)
-                                return log_oom();
-
-                        free(exec_split[n]);
-                        exec_split[n++] = TAKE_PTR(escaped);
+                        free_and_replace(exec_split[n++], executable);
                         continue;
                 }
 
                 /*
-                 * Remove any standardised XDG fields; we assume they never appear as
-                 * part of another argument as that just does not make any sense as
-                 * they can be empty (GLib will e.g. turn "%f" into an empty argument).
-                 * Other implementations may handle this differently.
+                 * Remove any standardised XDG fields; we assume they never appear as part of another
+                 * argument as that just does not make any sense as they can be empty (GLib will e.g. turn
+                 * "%f" into an empty argument).  Other implementations may handle this differently.
                  */
                 if (STR_IN_SET(c,
                                "%f", "%F",
                                "%u", "%U",
                                "%d", "%D",
                                "%n", "%N",
-                               "%i", /* Location of icon, could be implemented. */
-                               "%c", /* Translated application name, could be implemented. */
-                               "%k", /* Location of desktop file, could be implemented. */
+                               "%i",          /* Location of icon, could be implemented. */
+                               "%c",          /* Translated application name, could be implemented. */
+                               "%k",          /* Location of desktop file, could be implemented. */
                                "%v",
                                "%m"
                                ))
                         continue;
 
                 /*
-                 * %% -> % and then % -> %% means that we correctly quote any %
-                 * and also quote any left over (and invalid) % specifier from
-                 * the desktop file.
+                 * %% -> % and then % -> %% means that we correctly quote any % and also quote any left over
+                 * (and invalid) % specifier from the desktop file.
                  */
                 raw = strreplace(c, "%%", "%");
                 if (!raw)
                         return log_oom();
-                p = strreplace(raw, "%", "%%");
-                if (!p)
-                        return log_oom();
-                escaped = cescape(p);
-                if (!escaped)
+                percent = strreplace(raw, "%", "%%");
+                if (!percent)
                         return log_oom();
 
-                quoted = strjoin("\"", escaped, "\"");
-                if (!quoted)
-                        return log_oom();
-
-                free(exec_split[n]);
-                exec_split[n++] = TAKE_PTR(quoted);
+                free_and_replace(exec_split[n++], percent);
         }
         for (; exec_split[n]; n++)
                 exec_split[n] = mfree(exec_split[n]);
 
-        res = strv_join(exec_split, " ");
+        res = quote_command_line(exec_split, SHELL_ESCAPE_EMPTY);
         if (!res)
                 return log_oom();
 
@@ -476,6 +456,7 @@ int xdg_autostart_format_exec_start(
 }
 
 static int xdg_autostart_generate_desktop_condition(
+                const XdgAutostartService *service,
                 FILE *f,
                 const char *test_binary,
                 const char *condition) {
@@ -489,15 +470,20 @@ static int xdg_autostart_generate_desktop_condition(
                 r = find_executable(test_binary, &gnome_autostart_condition_path);
                 if (r < 0) {
                         log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
-                                       "%s not found: %m", test_binary);
+                                       "%s: ExecCondition executable %s not found, unit will not be started automatically: %m",
+                                       service->path, test_binary);
                         fprintf(f, "# ExecCondition using %s skipped due to missing binary.\n", test_binary);
-                        return r;
+                        return 0;
                 }
 
                 e_autostart_condition = cescape(condition);
                 if (!e_autostart_condition)
                         return log_oom();
 
+                log_debug("%s: ExecCondition converted to %s --condition \"%s\"%s",
+                          service->path, gnome_autostart_condition_path, e_autostart_condition,
+                          special_glyph(SPECIAL_GLYPH_ELLIPSIS));
+
                 fprintf(f,
                          "ExecCondition=%s --condition \"%s\"\n",
                          gnome_autostart_condition_path,
@@ -508,7 +494,7 @@ static int xdg_autostart_generate_desktop_condition(
 }
 
 int xdg_autostart_service_generate_unit(
-                XdgAutostartService *service,
+                const XdgAutostartService *service,
                 const char *dest) {
 
         _cleanup_free_ char *path_escaped = NULL, *exec_start = NULL, *unit = NULL;
@@ -519,52 +505,47 @@ int xdg_autostart_service_generate_unit(
 
         /* Nothing to do for hidden services. */
         if (service->hidden) {
-                log_debug("Not generating service for XDG autostart %s, it is hidden.", service->name);
+                log_debug("%s: not generating unit, entry is hidden.", service->path);
                 return 0;
         }
 
         if (service->systemd_skip) {
-                log_debug("Not generating service for XDG autostart %s, should be skipped by generator.", service->name);
+                log_debug("%s: not generating unit, marked as skipped by generator.", service->path);
                 return 0;
         }
 
         /* Nothing to do if type is not Application. */
         if (!streq_ptr(service->type, "Application")) {
-                log_debug("Not generating service for XDG autostart %s, only Type=Application is supported.", service->name);
+                log_debug("%s: not generating unit, Type=%s is not supported.", service->path, service->type);
                 return 0;
         }
 
         if (!service->exec_string) {
-                log_warning("Not generating service for XDG autostart %s, it is has no Exec= line.", service->name);
+                log_warning("%s: not generating unit, no Exec= line.", service->path);
                 return 0;
         }
 
-        /*
-         * The TryExec key cannot be checked properly from the systemd unit,
-         * it is trivial to check using find_executable though.
-         */
+        /* The TryExec key cannot be checked properly from the systemd unit, it is trivial to check using
+         * find_executable though. */
         if (service->try_exec) {
                 r = find_executable(service->try_exec, NULL);
                 if (r < 0) {
                         log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
-                                       "Not generating service for XDG autostart %s, could not find TryExec= binary %s: %m",
-                                       service->name, service->try_exec);
+                                       "%s: not generating unit, could not find TryExec= binary %s: %m",
+                                       service->path, service->try_exec);
                         return 0;
                 }
         }
 
         r = xdg_autostart_format_exec_start(service->exec_string, &exec_start);
         if (r < 0) {
-                log_warning_errno(r,
-                                  "Not generating service for XDG autostart %s, error parsing Exec= line: %m",
-                                  service->name);
+                log_warning_errno(r, "%s: not generating unit, error parsing Exec= line: %m", service->path);
                 return 0;
         }
 
         if (service->gnome_autostart_phase) {
                 /* There is no explicit value for the "Application" phase. */
-                log_debug("Not generating service for XDG autostart %s, startup phases are not supported.",
-                          service->name);
+                log_debug("%s: not generating unit, startup phases are not supported.", service->path);
                 return 0;
         }
 
@@ -578,7 +559,7 @@ int xdg_autostart_service_generate_unit(
 
         f = fopen(unit, "wxe");
         if (!f)
-                return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
+                return log_error_errno(errno, "%s: failed to create unit file %s: %m", service->path, unit);
 
         fprintf(f,
                 "# Automatically generated by systemd-xdg-autostart-generator\n\n"
@@ -605,6 +586,7 @@ int xdg_autostart_service_generate_unit(
         fprintf(f,
                 "\n[Service]\n"
                 "Type=exec\n"
+                "ExitType=cgroup\n"
                 "ExecStart=:%s\n"
                 "Restart=no\n"
                 "TimeoutSec=5s\n"
@@ -642,19 +624,19 @@ int xdg_autostart_service_generate_unit(
                         e_not_show_in);
         }
 
-        r = xdg_autostart_generate_desktop_condition(f,
+        r = xdg_autostart_generate_desktop_condition(service, f,
                                                      "gnome-systemd-autostart-condition",
                                                      service->autostart_condition);
         if (r < 0)
                 return r;
 
-        r = xdg_autostart_generate_desktop_condition(f,
+        r = xdg_autostart_generate_desktop_condition(service, f,
                                                      "kde-systemd-start-condition",
                                                      service->kde_autostart_condition);
         if (r < 0)
                 return r;
 
-        (void) generator_add_symlink(dest, "xdg-desktop-autostart.target", "wants", service->name);
-
-        return 0;
+        log_debug("%s: symlinking %s in xdg-desktop-autostart.target/.wants%s",
+                  service->path, service->name, special_glyph(SPECIAL_GLYPH_ELLIPSIS));
+        return generator_add_symlink(dest, "xdg-desktop-autostart.target", "wants", service->name);
 }