2020-11-09 05:23:58 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
2014-07-20 23:58:35 +02:00
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2018-05-15 20:17:34 +02:00
|
|
|
#include "all-units.h"
|
2015-10-26 17:30:56 +01:00
|
|
|
#include "analyze-verify.h"
|
2015-11-12 19:52:31 +01:00
|
|
|
#include "bus-error.h"
|
2014-07-20 23:58:35 +02:00
|
|
|
#include "bus-util.h"
|
|
|
|
#include "log.h"
|
2015-10-26 17:30:56 +01:00
|
|
|
#include "manager.h"
|
2014-07-21 00:23:53 +02:00
|
|
|
#include "pager.h"
|
2015-10-26 17:30:56 +01:00
|
|
|
#include "path-util.h"
|
|
|
|
#include "strv.h"
|
2015-12-13 15:04:09 +01:00
|
|
|
#include "unit-name.h"
|
|
|
|
|
|
|
|
static int prepare_filename(const char *filename, char **ret) {
|
|
|
|
int r;
|
|
|
|
const char *name;
|
|
|
|
_cleanup_free_ char *abspath = NULL;
|
|
|
|
_cleanup_free_ char *dir = NULL;
|
|
|
|
_cleanup_free_ char *with_instance = NULL;
|
|
|
|
char *c;
|
|
|
|
|
|
|
|
assert(filename);
|
|
|
|
assert(ret);
|
|
|
|
|
|
|
|
r = path_make_absolute_cwd(filename, &abspath);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
name = basename(abspath);
|
|
|
|
if (!unit_name_is_valid(name, UNIT_NAME_ANY))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (unit_name_is_valid(name, UNIT_NAME_TEMPLATE)) {
|
|
|
|
r = unit_name_replace_instance(name, "i", &with_instance);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
dir = dirname_malloc(abspath);
|
|
|
|
if (!dir)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2018-11-30 10:43:57 +01:00
|
|
|
c = path_join(dir, with_instance ?: name);
|
2015-12-13 15:04:09 +01:00
|
|
|
if (!c)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
*ret = c;
|
|
|
|
return 0;
|
|
|
|
}
|
2014-07-20 23:58:35 +02:00
|
|
|
|
|
|
|
static int generate_path(char **var, char **filenames) {
|
2016-09-25 15:55:26 +02:00
|
|
|
const char *old;
|
2014-07-20 23:58:35 +02:00
|
|
|
char **filename;
|
|
|
|
|
|
|
|
_cleanup_strv_free_ char **ans = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
STRV_FOREACH(filename, filenames) {
|
|
|
|
char *t;
|
|
|
|
|
|
|
|
t = dirname_malloc(*filename);
|
|
|
|
if (!t)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
r = strv_consume(&ans, t);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert_se(strv_uniq(ans));
|
|
|
|
|
2016-09-25 15:55:26 +02:00
|
|
|
/* First, prepend our directories. Second, if some path was specified, use that, and
|
|
|
|
* otherwise use the defaults. Any duplicates will be filtered out in path-lookup.c.
|
|
|
|
* Treat explicit empty path to mean that nothing should be appended.
|
|
|
|
*/
|
|
|
|
old = getenv("SYSTEMD_UNIT_PATH");
|
|
|
|
if (!streq_ptr(old, "")) {
|
|
|
|
if (!old)
|
|
|
|
old = ":";
|
|
|
|
|
|
|
|
r = strv_extend(&ans, old);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
2014-07-20 23:58:35 +02:00
|
|
|
|
|
|
|
*var = strv_join(ans, ":");
|
|
|
|
if (!*var)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int verify_socket(Unit *u) {
|
2020-05-29 14:24:12 +02:00
|
|
|
Unit *service;
|
2014-07-20 23:58:35 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(u);
|
|
|
|
|
|
|
|
if (u->type != UNIT_SOCKET)
|
|
|
|
return 0;
|
|
|
|
|
2020-05-29 14:24:12 +02:00
|
|
|
r = socket_load_service_unit(SOCKET(u), -1, &service);
|
2018-06-20 22:22:03 +02:00
|
|
|
if (r < 0)
|
2020-05-29 14:24:12 +02:00
|
|
|
return log_unit_error_errno(u, r, "service unit for the socket cannot be loaded: %m");
|
2014-07-20 23:58:35 +02:00
|
|
|
|
2020-05-29 14:24:12 +02:00
|
|
|
if (service->load_state != UNIT_LOADED)
|
|
|
|
return log_unit_error_errno(u, SYNTHETIC_ERRNO(ENOENT),
|
|
|
|
"service %s not loaded, socket cannot be started.", service->id);
|
2014-07-20 23:58:35 +02:00
|
|
|
|
2020-05-29 14:24:12 +02:00
|
|
|
log_unit_debug(u, "using service unit %s.", service->id);
|
2014-07-20 23:58:35 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-04-07 23:38:16 +02:00
|
|
|
int verify_executable(Unit *u, const ExecCommand *exec) {
|
2017-12-08 20:52:38 +01:00
|
|
|
if (!exec)
|
2014-07-20 23:58:35 +02:00
|
|
|
return 0;
|
|
|
|
|
2020-04-07 23:38:16 +02:00
|
|
|
if (exec->flags & EXEC_COMMAND_IGNORE_FAILURE)
|
|
|
|
return 0;
|
|
|
|
|
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
|
|
|
if (access(exec->path, X_OK) < 0)
|
|
|
|
return log_unit_error_errno(u, errno, "Command %s is not executable: %m", exec->path);
|
2014-07-20 23:58:35 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int verify_executables(Unit *u) {
|
|
|
|
ExecCommand *exec;
|
|
|
|
int r = 0, k;
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
assert(u);
|
|
|
|
|
|
|
|
exec = u->type == UNIT_SOCKET ? SOCKET(u)->control_command :
|
|
|
|
u->type == UNIT_MOUNT ? MOUNT(u)->control_command :
|
|
|
|
u->type == UNIT_SWAP ? SWAP(u)->control_command : NULL;
|
|
|
|
k = verify_executable(u, exec);
|
|
|
|
if (k < 0 && r == 0)
|
|
|
|
r = k;
|
|
|
|
|
|
|
|
if (u->type == UNIT_SERVICE)
|
|
|
|
for (i = 0; i < ELEMENTSOF(SERVICE(u)->exec_command); i++) {
|
|
|
|
k = verify_executable(u, SERVICE(u)->exec_command[i]);
|
|
|
|
if (k < 0 && r == 0)
|
|
|
|
r = k;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (u->type == UNIT_SOCKET)
|
|
|
|
for (i = 0; i < ELEMENTSOF(SOCKET(u)->exec_command); i++) {
|
|
|
|
k = verify_executable(u, SOCKET(u)->exec_command[i]);
|
|
|
|
if (k < 0 && r == 0)
|
|
|
|
r = k;
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2014-07-22 03:11:54 +02:00
|
|
|
static int verify_documentation(Unit *u, bool check_man) {
|
2014-07-21 00:23:53 +02:00
|
|
|
char **p;
|
|
|
|
int r = 0, k;
|
|
|
|
|
|
|
|
STRV_FOREACH(p, u->documentation) {
|
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
|
|
|
log_unit_debug(u, "Found documentation item: %s", *p);
|
|
|
|
|
2014-07-22 03:11:54 +02:00
|
|
|
if (check_man && startswith(*p, "man:")) {
|
2014-07-21 00:23:53 +02:00
|
|
|
k = show_man_page(*p + 4, true);
|
|
|
|
if (k != 0) {
|
|
|
|
if (k < 0)
|
2018-10-19 17:43:02 +02:00
|
|
|
log_unit_error_errno(u, k, "Can't show %s: %m", *p + 4);
|
2014-07-21 00:23:53 +02:00
|
|
|
else {
|
2018-10-19 17:43:02 +02:00
|
|
|
log_unit_error(u, "Command 'man %s' failed with code %d", *p + 4, k);
|
2014-07-21 00:23:53 +02:00
|
|
|
k = -ENOEXEC;
|
|
|
|
}
|
|
|
|
if (r == 0)
|
|
|
|
r = k;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check remote URLs? */
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2014-07-22 03:11:54 +02:00
|
|
|
static int verify_unit(Unit *u, bool check_man) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error err = SD_BUS_ERROR_NULL;
|
2014-07-20 23:58:35 +02:00
|
|
|
int r, k;
|
|
|
|
|
|
|
|
assert(u);
|
|
|
|
|
2017-12-15 11:09:00 +01:00
|
|
|
if (DEBUG_LOGGING)
|
2014-07-20 23:58:35 +02:00
|
|
|
unit_dump(u, stdout, "\t");
|
|
|
|
|
core,network: major per-object logging rework
This changes log_unit_info() (and friends) to take a real Unit* object
insted of just a unit name as parameter. The call will now prefix all
logged messages with the unit name, thus allowing the unit name to be
dropped from the various passed romat strings, simplifying invocations
drastically, and unifying log output across messages. Also, UNIT= vs.
USER_UNIT= is now derived from the Manager object attached to the Unit
object, instead of getpid(). This has the benefit of correcting the
field for --test runs.
Also contains a couple of other logging improvements:
- Drops a couple of strerror() invocations in favour of using %m.
- Not only .mount units now warn if a symlinks exist for the mount
point already, .automount units do that too, now.
- A few invocations of log_struct() that didn't actually pass any
additional structured data have been replaced by simpler invocations
of log_unit_info() and friends.
- For structured data a new LOG_UNIT_MESSAGE() macro has been added,
that works like LOG_MESSAGE() but prefixes the message with the unit
name. Similar, there's now LOG_LINK_MESSAGE() and
LOG_NETDEV_MESSAGE().
- For structured data new LOG_UNIT_ID(), LOG_LINK_INTERFACE(),
LOG_NETDEV_INTERFACE() macros have been added that generate the
necessary per object fields. The old log_unit_struct() call has been
removed in favour of these new macros used in raw log_struct()
invocations. In addition to removing one more function call this
allows generated structured log messages that contain two object
fields, as necessary for example for network interfaces that are
joined into another network interface, and whose messages shall be
indexed by both.
- The LOG_ERRNO() macro has been removed, in favour of
log_struct_errno(). The latter has the benefit of ensuring that %m in
format strings is properly resolved to the specified error number.
- A number of logging messages have been converted to use
log_unit_info() instead of log_info()
- The client code in sysv-generator no longer #includes core code from
src/core/.
- log_unit_full_errno() has been removed, log_unit_full() instead takes
an errno now, too.
- log_unit_info(), log_link_info(), log_netdev_info() and friends, now
avoid double evaluation of their parameters
2015-05-11 20:38:21 +02:00
|
|
|
log_unit_debug(u, "Creating %s/start job", u->id);
|
2019-03-22 20:57:30 +01:00
|
|
|
r = manager_add_job(u->manager, JOB_START, u, JOB_REPLACE, NULL, &err, NULL);
|
2014-07-20 23:58:35 +02:00
|
|
|
if (r < 0)
|
2015-11-12 19:52:31 +01:00
|
|
|
log_unit_error_errno(u, r, "Failed to create %s/start: %s", u->id, bus_error_message(&err, r));
|
2014-07-20 23:58:35 +02:00
|
|
|
|
|
|
|
k = verify_socket(u);
|
|
|
|
if (k < 0 && r == 0)
|
|
|
|
r = k;
|
|
|
|
|
|
|
|
k = verify_executables(u);
|
|
|
|
if (k < 0 && r == 0)
|
|
|
|
r = k;
|
|
|
|
|
2014-07-22 03:11:54 +02:00
|
|
|
k = verify_documentation(u, check_man);
|
2014-07-21 00:23:53 +02:00
|
|
|
if (k < 0 && r == 0)
|
|
|
|
r = k;
|
|
|
|
|
2014-07-20 23:58:35 +02:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2017-09-16 11:29:34 +02:00
|
|
|
int verify_units(char **filenames, UnitFileScope scope, bool check_man, bool run_generators) {
|
2018-10-09 16:15:54 +02:00
|
|
|
const ManagerTestRunFlags flags =
|
|
|
|
MANAGER_TEST_RUN_BASIC |
|
|
|
|
MANAGER_TEST_RUN_ENV_GENERATORS |
|
|
|
|
run_generators * MANAGER_TEST_RUN_GENERATORS;
|
2014-07-20 23:58:35 +02:00
|
|
|
|
2018-06-20 22:22:22 +02:00
|
|
|
_cleanup_(manager_freep) Manager *m = NULL;
|
|
|
|
Unit *units[strv_length(filenames)];
|
|
|
|
_cleanup_free_ char *var = NULL;
|
2020-08-25 09:10:15 +02:00
|
|
|
int r, k, i, count = 0;
|
2018-06-20 22:22:22 +02:00
|
|
|
char **filename;
|
|
|
|
|
2014-07-22 03:11:54 +02:00
|
|
|
if (strv_isempty(filenames))
|
|
|
|
return 0;
|
|
|
|
|
2014-07-20 23:58:35 +02:00
|
|
|
/* set the path */
|
|
|
|
r = generate_path(&var, filenames);
|
2014-11-28 18:23:20 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to generate unit load path: %m");
|
2014-07-20 23:58:35 +02:00
|
|
|
|
|
|
|
assert_se(set_unit_path(var) >= 0);
|
|
|
|
|
2017-09-16 11:29:34 +02:00
|
|
|
r = manager_new(scope, flags, &m);
|
2014-11-28 18:23:20 +01:00
|
|
|
if (r < 0)
|
2015-05-11 13:49:29 +02:00
|
|
|
return log_error_errno(r, "Failed to initialize manager: %m");
|
2014-07-20 23:58:35 +02:00
|
|
|
|
|
|
|
log_debug("Starting manager...");
|
|
|
|
|
2018-06-20 22:19:26 +02:00
|
|
|
r = manager_startup(m, NULL, NULL);
|
2018-06-20 22:22:22 +02:00
|
|
|
if (r < 0)
|
2018-10-09 17:16:08 +02:00
|
|
|
return r;
|
2014-07-20 23:58:35 +02:00
|
|
|
|
|
|
|
manager_clear_jobs(m);
|
|
|
|
|
|
|
|
log_debug("Loading remaining units from the command line...");
|
|
|
|
|
|
|
|
STRV_FOREACH(filename, filenames) {
|
2015-12-13 15:04:09 +01:00
|
|
|
_cleanup_free_ char *prepared = NULL;
|
2014-07-22 03:11:54 +02:00
|
|
|
|
2014-07-20 23:58:35 +02:00
|
|
|
log_debug("Handling %s...", *filename);
|
|
|
|
|
2015-12-13 15:04:09 +01:00
|
|
|
k = prepare_filename(*filename, &prepared);
|
|
|
|
if (k < 0) {
|
|
|
|
log_error_errno(k, "Failed to prepare filename %s: %m", *filename);
|
|
|
|
if (r == 0)
|
|
|
|
r = k;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-04-12 15:58:45 +02:00
|
|
|
k = manager_load_startable_unit_or_warn(m, NULL, prepared, &units[count]);
|
2019-11-13 12:30:58 +01:00
|
|
|
if (k < 0) {
|
|
|
|
if (r == 0)
|
|
|
|
r = k;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
count++;
|
2014-07-20 23:58:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++) {
|
2014-07-22 03:11:54 +02:00
|
|
|
k = verify_unit(units[i], check_man);
|
2014-07-20 23:58:35 +02:00
|
|
|
if (k < 0 && r == 0)
|
|
|
|
r = k;
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|