move more common files to shared/ and add them to shared.la
This commit is contained in:
@@ -0,0 +1,261 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "macro.h"
|
||||
#include "cgroup-util.h"
|
||||
#include "cgroup-show.h"
|
||||
|
||||
static int compare(const void *a, const void *b) {
|
||||
const pid_t *p = a, *q = b;
|
||||
|
||||
if (*p < *q)
|
||||
return -1;
|
||||
if (*p > *q)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned ilog10(unsigned long ul) {
|
||||
int n = 0;
|
||||
|
||||
while (ul > 0) {
|
||||
n++;
|
||||
ul /= 10;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigned n_columns, bool more, bool kernel_threads) {
|
||||
char *fn;
|
||||
FILE *f;
|
||||
size_t n = 0, n_allocated = 0;
|
||||
pid_t *pids = NULL;
|
||||
char *p;
|
||||
pid_t pid, biggest = 0;
|
||||
int r;
|
||||
|
||||
if (n_columns <= 0)
|
||||
n_columns = columns();
|
||||
|
||||
if (!prefix)
|
||||
prefix = "";
|
||||
|
||||
if ((r = cg_fix_path(path, &p)) < 0)
|
||||
return r;
|
||||
|
||||
r = asprintf(&fn, "%s/cgroup.procs", p);
|
||||
free(p);
|
||||
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
f = fopen(fn, "re");
|
||||
free(fn);
|
||||
|
||||
if (!f)
|
||||
return -errno;
|
||||
|
||||
while ((r = cg_read_pid(f, &pid)) > 0) {
|
||||
|
||||
if (!kernel_threads && is_kernel_thread(pid) > 0)
|
||||
continue;
|
||||
|
||||
if (n >= n_allocated) {
|
||||
pid_t *npids;
|
||||
|
||||
n_allocated = MAX(16U, n*2U);
|
||||
|
||||
if (!(npids = realloc(pids, sizeof(pid_t) * n_allocated))) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
pids = npids;
|
||||
}
|
||||
|
||||
assert(n < n_allocated);
|
||||
pids[n++] = pid;
|
||||
|
||||
if (pid > biggest)
|
||||
biggest = pid;
|
||||
}
|
||||
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
if (n > 0) {
|
||||
unsigned i, m;
|
||||
|
||||
/* Filter duplicates */
|
||||
m = 0;
|
||||
for (i = 0; i < n; i++) {
|
||||
unsigned j;
|
||||
|
||||
for (j = i+1; j < n; j++)
|
||||
if (pids[i] == pids[j])
|
||||
break;
|
||||
|
||||
if (j >= n)
|
||||
pids[m++] = pids[i];
|
||||
}
|
||||
n = m;
|
||||
|
||||
/* And sort */
|
||||
qsort(pids, n, sizeof(pid_t), compare);
|
||||
|
||||
if (n_columns > 8)
|
||||
n_columns -= 8;
|
||||
else
|
||||
n_columns = 20;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
char *t = NULL;
|
||||
|
||||
get_process_cmdline(pids[i], n_columns, true, &t);
|
||||
|
||||
printf("%s%s %*lu %s\n",
|
||||
prefix,
|
||||
(more || i < n-1) ? "\342\224\234" : "\342\224\224",
|
||||
(int) ilog10(biggest),
|
||||
(unsigned long) pids[i],
|
||||
strna(t));
|
||||
|
||||
free(t);
|
||||
}
|
||||
}
|
||||
|
||||
r = 0;
|
||||
|
||||
finish:
|
||||
free(pids);
|
||||
|
||||
if (f)
|
||||
fclose(f);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns, bool kernel_threads) {
|
||||
DIR *d;
|
||||
char *last = NULL;
|
||||
char *p1 = NULL, *p2 = NULL, *fn = NULL, *gn = NULL;
|
||||
bool shown_pids = false;
|
||||
int r;
|
||||
|
||||
if (n_columns <= 0)
|
||||
n_columns = columns();
|
||||
|
||||
if (!prefix)
|
||||
prefix = "";
|
||||
|
||||
if ((r = cg_fix_path(path, &fn)) < 0)
|
||||
return r;
|
||||
|
||||
if (!(d = opendir(fn))) {
|
||||
free(fn);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
while ((r = cg_read_subgroup(d, &gn)) > 0) {
|
||||
|
||||
if (!shown_pids) {
|
||||
show_cgroup_one_by_path(path, prefix, n_columns, true, kernel_threads);
|
||||
shown_pids = true;
|
||||
}
|
||||
|
||||
if (last) {
|
||||
printf("%s\342\224\234 %s\n", prefix, file_name_from_path(last));
|
||||
|
||||
if (!p1)
|
||||
if (!(p1 = strappend(prefix, "\342\224\202 "))) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
show_cgroup_by_path(last, p1, n_columns-2, kernel_threads);
|
||||
|
||||
free(last);
|
||||
last = NULL;
|
||||
}
|
||||
|
||||
r = asprintf(&last, "%s/%s", fn, gn);
|
||||
free(gn);
|
||||
|
||||
if (r < 0) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
if (!shown_pids)
|
||||
show_cgroup_one_by_path(path, prefix, n_columns, !!last, kernel_threads);
|
||||
|
||||
if (last) {
|
||||
printf("%s\342\224\224 %s\n", prefix, file_name_from_path(last));
|
||||
|
||||
if (!p2)
|
||||
if (!(p2 = strappend(prefix, " "))) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
show_cgroup_by_path(last, p2, n_columns-2, kernel_threads);
|
||||
}
|
||||
|
||||
r = 0;
|
||||
|
||||
finish:
|
||||
free(p1);
|
||||
free(p2);
|
||||
free(last);
|
||||
free(fn);
|
||||
|
||||
closedir(d);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads) {
|
||||
char *p;
|
||||
int r;
|
||||
|
||||
assert(controller);
|
||||
assert(path);
|
||||
|
||||
r = cg_get_path(controller, path, NULL, &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = show_cgroup_by_path(p, prefix, n_columns, kernel_threads);
|
||||
free(p);
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef foocgroupshowhfoo
|
||||
#define foocgroupshowhfoo
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
int show_cgroup_by_path(const char *path, const char *prefix, unsigned columns, bool kernel_threads);
|
||||
int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned columns, bool kernel_threads);
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,198 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef foodbuscommonhfoo
|
||||
#define foodbuscommonhfoo
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <dbus/dbus.h>
|
||||
|
||||
#ifndef DBUS_ERROR_UNKNOWN_OBJECT
|
||||
#define DBUS_ERROR_UNKNOWN_OBJECT "org.freedesktop.DBus.Error.UnknownObject"
|
||||
#endif
|
||||
|
||||
#ifndef DBUS_ERROR_UNKNOWN_INTERFACE
|
||||
#define DBUS_ERROR_UNKNOWN_INTERFACE "org.freedesktop.DBus.Error.UnknownInterface"
|
||||
#endif
|
||||
|
||||
#ifndef DBUS_ERROR_UNKNOWN_PROPERTY
|
||||
#define DBUS_ERROR_UNKNOWN_PROPERTY "org.freedesktop.DBus.Error.UnknownProperty"
|
||||
#endif
|
||||
|
||||
#ifndef DBUS_ERROR_PROPERTY_READ_ONLY
|
||||
#define DBUS_ERROR_PROPERTY_READ_ONLY "org.freedesktop.DBus.Error.PropertyReadOnly"
|
||||
#endif
|
||||
|
||||
#define BUS_PROPERTIES_INTERFACE \
|
||||
" <interface name=\"org.freedesktop.DBus.Properties\">\n" \
|
||||
" <method name=\"Get\">\n" \
|
||||
" <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n" \
|
||||
" <arg name=\"property\" direction=\"in\" type=\"s\"/>\n" \
|
||||
" <arg name=\"value\" direction=\"out\" type=\"v\"/>\n" \
|
||||
" </method>\n" \
|
||||
" <method name=\"GetAll\">\n" \
|
||||
" <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n" \
|
||||
" <arg name=\"properties\" direction=\"out\" type=\"a{sv}\"/>\n" \
|
||||
" </method>\n" \
|
||||
" <method name=\"Set\">\n" \
|
||||
" <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n" \
|
||||
" <arg name=\"property\" direction=\"in\" type=\"s\"/>\n" \
|
||||
" <arg name=\"value\" direction=\"in\" type=\"v\"/>\n" \
|
||||
" </method>\n" \
|
||||
" <signal name=\"PropertiesChanged\">\n" \
|
||||
" <arg type=\"s\" name=\"interface\"/>\n" \
|
||||
" <arg type=\"a{sv}\" name=\"changed_properties\"/>\n" \
|
||||
" <arg type=\"as\" name=\"invalidated_properties\"/>\n" \
|
||||
" </signal>\n" \
|
||||
" </interface>\n"
|
||||
|
||||
#define BUS_INTROSPECTABLE_INTERFACE \
|
||||
" <interface name=\"org.freedesktop.DBus.Introspectable\">\n" \
|
||||
" <method name=\"Introspect\">\n" \
|
||||
" <arg name=\"data\" type=\"s\" direction=\"out\"/>\n" \
|
||||
" </method>\n" \
|
||||
" </interface>\n"
|
||||
|
||||
#define BUS_PEER_INTERFACE \
|
||||
"<interface name=\"org.freedesktop.DBus.Peer\">\n" \
|
||||
" <method name=\"Ping\"/>\n" \
|
||||
" <method name=\"GetMachineId\">\n" \
|
||||
" <arg type=\"s\" name=\"machine_uuid\" direction=\"out\"/>\n" \
|
||||
" </method>\n" \
|
||||
"</interface>\n"
|
||||
|
||||
#define BUS_GENERIC_INTERFACES_LIST \
|
||||
"org.freedesktop.DBus.Properties\0" \
|
||||
"org.freedesktop.DBus.Introspectable\0" \
|
||||
"org.freedesktop.DBus.Peer\0"
|
||||
|
||||
int bus_check_peercred(DBusConnection *c);
|
||||
|
||||
int bus_connect(DBusBusType t, DBusConnection **_bus, bool *private_bus, DBusError *error);
|
||||
|
||||
int bus_connect_system_ssh(const char *user, const char *host, DBusConnection **_bus, DBusError *error);
|
||||
int bus_connect_system_polkit(DBusConnection **_bus, DBusError *error);
|
||||
|
||||
const char *bus_error_message(const DBusError *error);
|
||||
|
||||
typedef int (*BusPropertyCallback)(DBusMessageIter *iter, const char *property, void *data);
|
||||
typedef int (*BusPropertySetCallback)(DBusMessageIter *iter, const char *property, void *data);
|
||||
|
||||
typedef struct BusProperty {
|
||||
const char *property; /* name of the property */
|
||||
BusPropertyCallback append; /* Function that is called to serialize this property */
|
||||
const char *signature;
|
||||
const uint16_t offset; /* Offset from BusBoundProperties::base address to the property data.
|
||||
* uint16_t is sufficient, because we have no structs too big.
|
||||
* -Werror=overflow will catch it if this does not hold. */
|
||||
bool indirect; /* data is indirect, ie. not base+offset, but *(base+offset) */
|
||||
BusPropertySetCallback set; /* Optional: Function that is called to set this property */
|
||||
} BusProperty;
|
||||
|
||||
typedef struct BusBoundProperties {
|
||||
const char *interface; /* interface of the properties */
|
||||
const BusProperty *properties; /* array of properties, ended by a NULL-filled element */
|
||||
const void *const base; /* base pointer to which the offset must be added to reach data */
|
||||
} BusBoundProperties;
|
||||
|
||||
DBusHandlerResult bus_send_error_reply(
|
||||
DBusConnection *c,
|
||||
DBusMessage *message,
|
||||
DBusError *bus_error,
|
||||
int error);
|
||||
|
||||
DBusHandlerResult bus_default_message_handler(
|
||||
DBusConnection *c,
|
||||
DBusMessage *message,
|
||||
const char *introspection,
|
||||
const char *interfaces,
|
||||
const BusBoundProperties *bound_properties);
|
||||
|
||||
int bus_property_append_string(DBusMessageIter *i, const char *property, void *data);
|
||||
int bus_property_append_strv(DBusMessageIter *i, const char *property, void *data);
|
||||
int bus_property_append_bool(DBusMessageIter *i, const char *property, void *data);
|
||||
int bus_property_append_tristate_false(DBusMessageIter *i, const char *property, void *data);
|
||||
int bus_property_append_int32(DBusMessageIter *i, const char *property, void *data);
|
||||
int bus_property_append_uint32(DBusMessageIter *i, const char *property, void *data);
|
||||
int bus_property_append_uint64(DBusMessageIter *i, const char *property, void *data);
|
||||
int bus_property_append_size(DBusMessageIter *i, const char *property, void *data);
|
||||
int bus_property_append_ul(DBusMessageIter *i, const char *property, void *data);
|
||||
int bus_property_append_long(DBusMessageIter *i, const char *property, void *data);
|
||||
|
||||
#define bus_property_append_int bus_property_append_int32
|
||||
#define bus_property_append_pid bus_property_append_uint32
|
||||
#define bus_property_append_uid bus_property_append_uint32
|
||||
#define bus_property_append_gid bus_property_append_uint32
|
||||
#define bus_property_append_mode bus_property_append_uint32
|
||||
#define bus_property_append_unsigned bus_property_append_uint32
|
||||
#define bus_property_append_usec bus_property_append_uint64
|
||||
|
||||
#define DEFINE_BUS_PROPERTY_APPEND_ENUM(function,name,type) \
|
||||
int function(DBusMessageIter *i, const char *property, void *data) { \
|
||||
const char *value; \
|
||||
type *field = data; \
|
||||
\
|
||||
assert(i); \
|
||||
assert(property); \
|
||||
\
|
||||
value = name##_to_string(*field); \
|
||||
\
|
||||
if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &value)) \
|
||||
return -ENOMEM; \
|
||||
\
|
||||
return 0; \
|
||||
}
|
||||
|
||||
#define DEFINE_BUS_PROPERTY_SET_ENUM(function,name,type) \
|
||||
int function(DBusMessageIter *i, const char *property, void *data) { \
|
||||
const char *value; \
|
||||
type *field = data; \
|
||||
\
|
||||
assert(i); \
|
||||
assert(property); \
|
||||
\
|
||||
dbus_message_iter_get_basic(i, &value); \
|
||||
\
|
||||
*field = name##_from_string(value); \
|
||||
\
|
||||
return 0; \
|
||||
}
|
||||
|
||||
const char *bus_errno_to_dbus(int error);
|
||||
|
||||
DBusMessage* bus_properties_changed_new(const char *path, const char *interface, const char *properties);
|
||||
|
||||
uint32_t bus_flags_to_events(DBusWatch *bus_watch);
|
||||
unsigned bus_events_to_flags(uint32_t events);
|
||||
|
||||
int bus_parse_strv(DBusMessage *m, char ***_l);
|
||||
int bus_parse_strv_iter(DBusMessageIter *iter, char ***_l);
|
||||
|
||||
int bus_append_strv_iter(DBusMessageIter *iter, char **l);
|
||||
|
||||
int bus_iter_get_basic_and_next(DBusMessageIter *iter, int type, void *data, bool next);
|
||||
|
||||
int generic_print_property(const char *name, DBusMessageIter *iter, bool all);
|
||||
|
||||
void bus_async_unregister_and_exit(DBusConnection *bus, const char *name);
|
||||
|
||||
DBusHandlerResult bus_exit_idle_filter(DBusConnection *bus, DBusMessage *m, void *userdata);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,187 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "hostname-setup.h"
|
||||
#include "macro.h"
|
||||
#include "util.h"
|
||||
#include "log.h"
|
||||
|
||||
#if defined(TARGET_FEDORA) || defined(TARGET_ALTLINUX) || defined(TARGET_MANDRIVA) || defined(TARGET_MEEGO) || defined(TARGET_MAGEIA)
|
||||
#define FILENAME "/etc/sysconfig/network"
|
||||
#elif defined(TARGET_SUSE) || defined(TARGET_SLACKWARE)
|
||||
#define FILENAME "/etc/HOSTNAME"
|
||||
#elif defined(TARGET_ARCH)
|
||||
#define FILENAME "/etc/rc.conf"
|
||||
#elif defined(TARGET_GENTOO)
|
||||
#define FILENAME "/etc/conf.d/hostname"
|
||||
#endif
|
||||
|
||||
static int read_and_strip_hostname(const char *path, char **hn) {
|
||||
char *s;
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
assert(hn);
|
||||
|
||||
if ((r = read_one_line_file(path, &s)) < 0)
|
||||
return r;
|
||||
|
||||
hostname_cleanup(s);
|
||||
|
||||
if (isempty(s)) {
|
||||
free(s);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
*hn = s;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_distro_hostname(char **hn) {
|
||||
|
||||
#if defined(TARGET_FEDORA) || defined(TARGET_ARCH) || defined(TARGET_GENTOO) || defined(TARGET_ALTLINUX) || defined(TARGET_MANDRIVA) || defined(TARGET_MEEGO) || defined(TARGET_MAGEIA)
|
||||
int r;
|
||||
FILE *f;
|
||||
|
||||
assert(hn);
|
||||
|
||||
if (!(f = fopen(FILENAME, "re")))
|
||||
return -errno;
|
||||
|
||||
for (;;) {
|
||||
char line[LINE_MAX];
|
||||
char *s, *k;
|
||||
|
||||
if (!fgets(line, sizeof(line), f)) {
|
||||
if (feof(f))
|
||||
break;
|
||||
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
s = strstrip(line);
|
||||
|
||||
if (!startswith_no_case(s, "HOSTNAME="))
|
||||
continue;
|
||||
|
||||
if (!(k = strdup(s+9))) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
hostname_cleanup(k);
|
||||
|
||||
if (isempty(k)) {
|
||||
free(k);
|
||||
r = -ENOENT;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
*hn = k;
|
||||
r = 0;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = -ENOENT;
|
||||
|
||||
finish:
|
||||
fclose(f);
|
||||
return r;
|
||||
|
||||
#elif defined(TARGET_SUSE) || defined(TARGET_SLACKWARE)
|
||||
return read_and_strip_hostname(FILENAME, hn);
|
||||
#else
|
||||
return -ENOENT;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int read_hostname(char **hn) {
|
||||
int r;
|
||||
|
||||
assert(hn);
|
||||
|
||||
/* First, try to load the generic hostname configuration file,
|
||||
* that we support on all distributions */
|
||||
|
||||
if ((r = read_and_strip_hostname("/etc/hostname", hn)) < 0) {
|
||||
|
||||
if (r == -ENOENT)
|
||||
return read_distro_hostname(hn);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hostname_setup(void) {
|
||||
int r;
|
||||
char *b = NULL;
|
||||
const char *hn = NULL;
|
||||
|
||||
if ((r = read_hostname(&b)) < 0) {
|
||||
if (r == -ENOENT)
|
||||
log_info("No hostname configured.");
|
||||
else
|
||||
log_warning("Failed to read configured hostname: %s", strerror(-r));
|
||||
|
||||
hn = NULL;
|
||||
} else
|
||||
hn = b;
|
||||
|
||||
if (!hn) {
|
||||
/* Don't override the hostname if it is unset and not
|
||||
* explicitly configured */
|
||||
|
||||
char *old_hostname = NULL;
|
||||
|
||||
if ((old_hostname = gethostname_malloc())) {
|
||||
bool already_set;
|
||||
|
||||
already_set = old_hostname[0] != 0;
|
||||
free(old_hostname);
|
||||
|
||||
if (already_set)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
hn = "localhost";
|
||||
}
|
||||
|
||||
if (sethostname(hn, strlen(hn)) < 0) {
|
||||
log_warning("Failed to set hostname to <%s>: %m", hn);
|
||||
r = -errno;
|
||||
} else
|
||||
log_info("Set hostname to <%s>.", hn);
|
||||
|
||||
finish:
|
||||
free(b);
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef foohostnamesetuphfoo
|
||||
#define foohostnamesetuphfoo
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
int hostname_setup(void);
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,89 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef fooinstallhfoo
|
||||
#define fooinstallhfoo
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2011 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include "hashmap.h"
|
||||
|
||||
typedef enum UnitFileScope {
|
||||
UNIT_FILE_SYSTEM,
|
||||
UNIT_FILE_GLOBAL,
|
||||
UNIT_FILE_USER,
|
||||
_UNIT_FILE_SCOPE_MAX,
|
||||
_UNIT_FILE_SCOPE_INVALID = -1
|
||||
} UnitFileScope;
|
||||
|
||||
typedef enum UnitFileState {
|
||||
UNIT_FILE_ENABLED,
|
||||
UNIT_FILE_ENABLED_RUNTIME,
|
||||
UNIT_FILE_LINKED,
|
||||
UNIT_FILE_LINKED_RUNTIME,
|
||||
UNIT_FILE_MASKED,
|
||||
UNIT_FILE_MASKED_RUNTIME,
|
||||
UNIT_FILE_STATIC,
|
||||
UNIT_FILE_DISABLED,
|
||||
_UNIT_FILE_STATE_MAX,
|
||||
_UNIT_FILE_STATE_INVALID = -1
|
||||
} UnitFileState;
|
||||
|
||||
typedef enum UnitFileChangeType {
|
||||
UNIT_FILE_SYMLINK,
|
||||
UNIT_FILE_UNLINK,
|
||||
_UNIT_FILE_CHANGE_TYPE_MAX,
|
||||
_UNIT_FILE_CHANGE_TYPE_INVALID = -1
|
||||
} UnitFileChangeType;
|
||||
|
||||
typedef struct UnitFileChange {
|
||||
UnitFileChangeType type;
|
||||
char *path;
|
||||
char *source;
|
||||
} UnitFileChange;
|
||||
|
||||
typedef struct UnitFileList {
|
||||
char *path;
|
||||
UnitFileState state;
|
||||
} UnitFileList;
|
||||
|
||||
int unit_file_enable(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes);
|
||||
int unit_file_disable(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], UnitFileChange **changes, unsigned *n_changes);
|
||||
int unit_file_reenable(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes);
|
||||
int unit_file_link(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes);
|
||||
int unit_file_preset(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes);
|
||||
int unit_file_mask(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes);
|
||||
int unit_file_unmask(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], UnitFileChange **changes, unsigned *n_changes);
|
||||
|
||||
UnitFileState unit_file_get_state(UnitFileScope scope, const char *root_dir, const char *filename);
|
||||
|
||||
int unit_file_get_list(UnitFileScope scope, const char *root_dir, Hashmap *h);
|
||||
|
||||
void unit_file_list_free(Hashmap *h);
|
||||
void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes);
|
||||
|
||||
int unit_file_query_preset(UnitFileScope scope, const char *name);
|
||||
|
||||
const char *unit_file_state_to_string(UnitFileState s);
|
||||
UnitFileState unit_file_state_from_string(const char *s);
|
||||
|
||||
const char *unit_file_change_type_to_string(UnitFileChangeType s);
|
||||
UnitFileChangeType unit_file_change_type_from_string(const char *s);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,677 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2012 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <sys/poll.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "logs-show.h"
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
|
||||
#define PRINT_THRESHOLD 128
|
||||
|
||||
static bool contains_unprintable(const void *p, size_t l) {
|
||||
const char *j;
|
||||
|
||||
for (j = p; j < (const char *) p + l; j++)
|
||||
if (*j < ' ' || *j >= 127)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int parse_field(const void *data, size_t length, const char *field, char **target, size_t *target_size) {
|
||||
size_t fl, nl;
|
||||
void *buf;
|
||||
|
||||
assert(data);
|
||||
assert(field);
|
||||
assert(target);
|
||||
assert(target_size);
|
||||
|
||||
fl = strlen(field);
|
||||
if (length < fl)
|
||||
return 0;
|
||||
|
||||
if (memcmp(data, field, fl))
|
||||
return 0;
|
||||
|
||||
nl = length - fl;
|
||||
buf = malloc(nl+1);
|
||||
memcpy(buf, (const char*) data + fl, nl);
|
||||
((char*)buf)[nl] = 0;
|
||||
if (!buf) {
|
||||
log_error("Out of memory");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
free(*target);
|
||||
*target = buf;
|
||||
*target_size = nl;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool shall_print(bool show_all, char *p, size_t l) {
|
||||
if (show_all)
|
||||
return true;
|
||||
|
||||
if (l > PRINT_THRESHOLD)
|
||||
return false;
|
||||
|
||||
if (contains_unprintable(p, l))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int output_short(sd_journal *j, unsigned line, unsigned n_columns, bool show_all, bool monotonic_mode) {
|
||||
int r;
|
||||
const void *data;
|
||||
size_t length;
|
||||
size_t n = 0;
|
||||
char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *fake_pid = NULL, *message = NULL, *realtime = NULL, *monotonic = NULL;
|
||||
size_t hostname_len = 0, identifier_len = 0, comm_len = 0, pid_len = 0, fake_pid_len = 0, message_len = 0, realtime_len = 0, monotonic_len = 0;
|
||||
|
||||
assert(j);
|
||||
|
||||
SD_JOURNAL_FOREACH_DATA(j, data, length) {
|
||||
|
||||
r = parse_field(data, length, "_HOSTNAME=", &hostname, &hostname_len);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
else if (r > 0)
|
||||
continue;
|
||||
|
||||
r = parse_field(data, length, "SYSLOG_IDENTIFIER=", &identifier, &identifier_len);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
else if (r > 0)
|
||||
continue;
|
||||
|
||||
r = parse_field(data, length, "_COMM=", &comm, &comm_len);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
else if (r > 0)
|
||||
continue;
|
||||
|
||||
r = parse_field(data, length, "_PID=", &pid, &pid_len);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
else if (r > 0)
|
||||
continue;
|
||||
|
||||
r = parse_field(data, length, "SYSLOG_PID=", &fake_pid, &fake_pid_len);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
else if (r > 0)
|
||||
continue;
|
||||
|
||||
r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
else if (r > 0)
|
||||
continue;
|
||||
|
||||
r = parse_field(data, length, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
else if (r > 0)
|
||||
continue;
|
||||
|
||||
r = parse_field(data, length, "MESSAGE=", &message, &message_len);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (!message) {
|
||||
r = 0;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (monotonic_mode) {
|
||||
uint64_t t;
|
||||
sd_id128_t boot_id;
|
||||
|
||||
r = -ENOENT;
|
||||
|
||||
if (monotonic)
|
||||
r = safe_atou64(monotonic, &t);
|
||||
|
||||
if (r < 0)
|
||||
r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
|
||||
|
||||
if (r < 0) {
|
||||
log_error("Failed to get monotonic: %s", strerror(-r));
|
||||
goto finish;
|
||||
}
|
||||
|
||||
printf("[%5llu.%06llu]",
|
||||
(unsigned long long) (t / USEC_PER_SEC),
|
||||
(unsigned long long) (t % USEC_PER_SEC));
|
||||
|
||||
n += 1 + 5 + 1 + 6 + 1;
|
||||
|
||||
} else {
|
||||
char buf[64];
|
||||
uint64_t x;
|
||||
time_t t;
|
||||
struct tm tm;
|
||||
|
||||
r = -ENOENT;
|
||||
|
||||
if (realtime)
|
||||
r = safe_atou64(realtime, &x);
|
||||
|
||||
if (r < 0)
|
||||
r = sd_journal_get_realtime_usec(j, &x);
|
||||
|
||||
if (r < 0) {
|
||||
log_error("Failed to get realtime: %s", strerror(-r));
|
||||
goto finish;
|
||||
}
|
||||
|
||||
t = (time_t) (x / USEC_PER_SEC);
|
||||
if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm)) <= 0) {
|
||||
log_error("Failed to format time.");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
fputs(buf, stdout);
|
||||
n += strlen(buf);
|
||||
}
|
||||
|
||||
if (hostname && shall_print(show_all, hostname, hostname_len)) {
|
||||
printf(" %.*s", (int) hostname_len, hostname);
|
||||
n += hostname_len + 1;
|
||||
}
|
||||
|
||||
if (identifier && shall_print(show_all, identifier, identifier_len)) {
|
||||
printf(" %.*s", (int) identifier_len, identifier);
|
||||
n += identifier_len + 1;
|
||||
} else if (comm && shall_print(show_all, comm, comm_len)) {
|
||||
printf(" %.*s", (int) comm_len, comm);
|
||||
n += comm_len + 1;
|
||||
} else
|
||||
putchar(' ');
|
||||
|
||||
if (pid && shall_print(show_all, pid, pid_len)) {
|
||||
printf("[%.*s]", (int) pid_len, pid);
|
||||
n += pid_len + 2;
|
||||
} else if (fake_pid && shall_print(show_all, fake_pid, fake_pid_len)) {
|
||||
printf("[%.*s]", (int) fake_pid_len, fake_pid);
|
||||
n += fake_pid_len + 2;
|
||||
}
|
||||
|
||||
if (show_all)
|
||||
printf(": %.*s\n", (int) message_len, message);
|
||||
else if (contains_unprintable(message, message_len)) {
|
||||
char bytes[FORMAT_BYTES_MAX];
|
||||
printf(": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
|
||||
} else if (message_len + n < n_columns)
|
||||
printf(": %.*s\n", (int) message_len, message);
|
||||
else if (n < n_columns) {
|
||||
char *e;
|
||||
|
||||
e = ellipsize_mem(message, message_len, n_columns - n - 2, 90);
|
||||
|
||||
if (!e)
|
||||
printf(": %.*s\n", (int) message_len, message);
|
||||
else
|
||||
printf(": %s\n", e);
|
||||
|
||||
free(e);
|
||||
} else
|
||||
fputs("\n", stdout);
|
||||
|
||||
r = 0;
|
||||
|
||||
finish:
|
||||
free(hostname);
|
||||
free(identifier);
|
||||
free(comm);
|
||||
free(pid);
|
||||
free(fake_pid);
|
||||
free(message);
|
||||
free(monotonic);
|
||||
free(realtime);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int output_short_realtime(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) {
|
||||
return output_short(j, line, n_columns, show_all, false);
|
||||
}
|
||||
|
||||
static int output_short_monotonic(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) {
|
||||
return output_short(j, line, n_columns, show_all, true);
|
||||
}
|
||||
|
||||
static int output_verbose(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) {
|
||||
const void *data;
|
||||
size_t length;
|
||||
char *cursor;
|
||||
uint64_t realtime;
|
||||
char ts[FORMAT_TIMESTAMP_MAX];
|
||||
int r;
|
||||
|
||||
assert(j);
|
||||
|
||||
r = sd_journal_get_realtime_usec(j, &realtime);
|
||||
if (r < 0) {
|
||||
log_error("Failed to get realtime timestamp: %s", strerror(-r));
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_journal_get_cursor(j, &cursor);
|
||||
if (r < 0) {
|
||||
log_error("Failed to get cursor: %s", strerror(-r));
|
||||
return r;
|
||||
}
|
||||
|
||||
printf("%s [%s]\n",
|
||||
format_timestamp(ts, sizeof(ts), realtime),
|
||||
cursor);
|
||||
|
||||
free(cursor);
|
||||
|
||||
SD_JOURNAL_FOREACH_DATA(j, data, length) {
|
||||
if (!show_all && (length > PRINT_THRESHOLD ||
|
||||
contains_unprintable(data, length))) {
|
||||
const char *c;
|
||||
char bytes[FORMAT_BYTES_MAX];
|
||||
|
||||
c = memchr(data, '=', length);
|
||||
if (!c) {
|
||||
log_error("Invalid field.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
printf("\t%.*s=[%s blob data]\n",
|
||||
(int) (c - (const char*) data),
|
||||
(const char*) data,
|
||||
format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1));
|
||||
} else
|
||||
printf("\t%.*s\n", (int) length, (const char*) data);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int output_export(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) {
|
||||
sd_id128_t boot_id;
|
||||
char sid[33];
|
||||
int r;
|
||||
usec_t realtime, monotonic;
|
||||
char *cursor;
|
||||
const void *data;
|
||||
size_t length;
|
||||
|
||||
assert(j);
|
||||
|
||||
r = sd_journal_get_realtime_usec(j, &realtime);
|
||||
if (r < 0) {
|
||||
log_error("Failed to get realtime timestamp: %s", strerror(-r));
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
|
||||
if (r < 0) {
|
||||
log_error("Failed to get monotonic timestamp: %s", strerror(-r));
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_journal_get_cursor(j, &cursor);
|
||||
if (r < 0) {
|
||||
log_error("Failed to get cursor: %s", strerror(-r));
|
||||
return r;
|
||||
}
|
||||
|
||||
printf("__CURSOR=%s\n"
|
||||
"__REALTIME_TIMESTAMP=%llu\n"
|
||||
"__MONOTONIC_TIMESTAMP=%llu\n"
|
||||
"_BOOT_ID=%s\n",
|
||||
cursor,
|
||||
(unsigned long long) realtime,
|
||||
(unsigned long long) monotonic,
|
||||
sd_id128_to_string(boot_id, sid));
|
||||
|
||||
free(cursor);
|
||||
|
||||
SD_JOURNAL_FOREACH_DATA(j, data, length) {
|
||||
|
||||
/* We already printed the boot id, from the data in
|
||||
* the header, hence let's suppress it here */
|
||||
if (length >= 9 &&
|
||||
memcmp(data, "_BOOT_ID=", 9) == 0)
|
||||
continue;
|
||||
|
||||
if (contains_unprintable(data, length)) {
|
||||
const char *c;
|
||||
uint64_t le64;
|
||||
|
||||
c = memchr(data, '=', length);
|
||||
if (!c) {
|
||||
log_error("Invalid field.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fwrite(data, c - (const char*) data, 1, stdout);
|
||||
fputc('\n', stdout);
|
||||
le64 = htole64(length - (c - (const char*) data) - 1);
|
||||
fwrite(&le64, sizeof(le64), 1, stdout);
|
||||
fwrite(c + 1, length - (c - (const char*) data) - 1, 1, stdout);
|
||||
} else
|
||||
fwrite(data, length, 1, stdout);
|
||||
|
||||
fputc('\n', stdout);
|
||||
}
|
||||
|
||||
fputc('\n', stdout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void json_escape(const char* p, size_t l) {
|
||||
|
||||
if (contains_unprintable(p, l)) {
|
||||
bool not_first = false;
|
||||
|
||||
fputs("[ ", stdout);
|
||||
|
||||
while (l > 0) {
|
||||
if (not_first)
|
||||
printf(", %u", (uint8_t) *p);
|
||||
else {
|
||||
not_first = true;
|
||||
printf("%u", (uint8_t) *p);
|
||||
}
|
||||
|
||||
p++;
|
||||
l--;
|
||||
}
|
||||
|
||||
fputs(" ]", stdout);
|
||||
} else {
|
||||
fputc('\"', stdout);
|
||||
|
||||
while (l > 0) {
|
||||
if (*p == '"' || *p == '\\') {
|
||||
fputc('\\', stdout);
|
||||
fputc(*p, stdout);
|
||||
} else
|
||||
fputc(*p, stdout);
|
||||
|
||||
p++;
|
||||
l--;
|
||||
}
|
||||
|
||||
fputc('\"', stdout);
|
||||
}
|
||||
}
|
||||
|
||||
static int output_json(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) {
|
||||
uint64_t realtime, monotonic;
|
||||
char *cursor;
|
||||
const void *data;
|
||||
size_t length;
|
||||
sd_id128_t boot_id;
|
||||
char sid[33];
|
||||
int r;
|
||||
|
||||
assert(j);
|
||||
|
||||
r = sd_journal_get_realtime_usec(j, &realtime);
|
||||
if (r < 0) {
|
||||
log_error("Failed to get realtime timestamp: %s", strerror(-r));
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
|
||||
if (r < 0) {
|
||||
log_error("Failed to get monotonic timestamp: %s", strerror(-r));
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_journal_get_cursor(j, &cursor);
|
||||
if (r < 0) {
|
||||
log_error("Failed to get cursor: %s", strerror(-r));
|
||||
return r;
|
||||
}
|
||||
|
||||
if (line == 1)
|
||||
fputc('\n', stdout);
|
||||
else
|
||||
fputs(",\n", stdout);
|
||||
|
||||
printf("{\n"
|
||||
"\t\"__CURSOR\" : \"%s\",\n"
|
||||
"\t\"__REALTIME_TIMESTAMP\" : \"%llu\",\n"
|
||||
"\t\"__MONOTONIC_TIMESTAMP\" : \"%llu\",\n"
|
||||
"\t\"_BOOT_ID\" : \"%s\"",
|
||||
cursor,
|
||||
(unsigned long long) realtime,
|
||||
(unsigned long long) monotonic,
|
||||
sd_id128_to_string(boot_id, sid));
|
||||
|
||||
free(cursor);
|
||||
|
||||
SD_JOURNAL_FOREACH_DATA(j, data, length) {
|
||||
const char *c;
|
||||
|
||||
/* We already printed the boot id, from the data in
|
||||
* the header, hence let's suppress it here */
|
||||
if (length >= 9 &&
|
||||
memcmp(data, "_BOOT_ID=", 9) == 0)
|
||||
continue;
|
||||
|
||||
c = memchr(data, '=', length);
|
||||
if (!c) {
|
||||
log_error("Invalid field.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fputs(",\n\t", stdout);
|
||||
json_escape(data, c - (const char*) data);
|
||||
fputs(" : ", stdout);
|
||||
json_escape(c + 1, length - (c - (const char*) data) - 1);
|
||||
}
|
||||
|
||||
fputs("\n}", stdout);
|
||||
fflush(stdout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int output_cat(sd_journal *j, unsigned line, unsigned n_columns, bool show_all) {
|
||||
const void *data;
|
||||
size_t l;
|
||||
int r;
|
||||
|
||||
assert(j);
|
||||
|
||||
r = sd_journal_get_data(j, "MESSAGE", &data, &l);
|
||||
if (r < 0) {
|
||||
log_error("Failed to get data: %s", strerror(-r));
|
||||
return r;
|
||||
}
|
||||
|
||||
assert(l >= 8);
|
||||
|
||||
fwrite((const char*) data + 8, 1, l - 8, stdout);
|
||||
putchar('\n');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int (*output_funcs[_OUTPUT_MODE_MAX])(sd_journal*j, unsigned line, unsigned n_columns, bool show_all) = {
|
||||
[OUTPUT_SHORT] = output_short_realtime,
|
||||
[OUTPUT_SHORT_MONOTONIC] = output_short_monotonic,
|
||||
[OUTPUT_VERBOSE] = output_verbose,
|
||||
[OUTPUT_EXPORT] = output_export,
|
||||
[OUTPUT_JSON] = output_json,
|
||||
[OUTPUT_CAT] = output_cat
|
||||
};
|
||||
|
||||
int output_journal(sd_journal *j, OutputMode mode, unsigned line, unsigned n_columns, bool show_all) {
|
||||
assert(mode >= 0);
|
||||
assert(mode < _OUTPUT_MODE_MAX);
|
||||
|
||||
if (n_columns <= 0)
|
||||
n_columns = columns();
|
||||
|
||||
return output_funcs[mode](j, line, n_columns, show_all);
|
||||
}
|
||||
|
||||
int show_journal_by_unit(
|
||||
const char *unit,
|
||||
OutputMode mode,
|
||||
unsigned n_columns,
|
||||
usec_t not_before,
|
||||
unsigned how_many,
|
||||
bool show_all,
|
||||
bool follow) {
|
||||
|
||||
char *m = NULL;
|
||||
sd_journal *j;
|
||||
int r;
|
||||
int fd;
|
||||
unsigned line = 0;
|
||||
bool need_seek = false;
|
||||
|
||||
assert(mode >= 0);
|
||||
assert(mode < _OUTPUT_MODE_MAX);
|
||||
assert(unit);
|
||||
|
||||
if (!endswith(unit, ".service") &&
|
||||
!endswith(unit, ".socket") &&
|
||||
!endswith(unit, ".mount") &&
|
||||
!endswith(unit, ".swap"))
|
||||
return 0;
|
||||
|
||||
if (how_many <= 0)
|
||||
return 0;
|
||||
|
||||
if (asprintf(&m, "_SYSTEMD_UNIT=%s", unit) < 0) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM_ONLY);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
fd = sd_journal_get_fd(j);
|
||||
if (fd < 0)
|
||||
goto finish;
|
||||
|
||||
r = sd_journal_add_match(j, m, strlen(m));
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
r = sd_journal_seek_tail(j);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
r = sd_journal_previous_skip(j, how_many);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
if (mode == OUTPUT_JSON) {
|
||||
fputc('[', stdout);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
for (;;) {
|
||||
usec_t usec;
|
||||
|
||||
if (need_seek) {
|
||||
r = sd_journal_next(j);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
need_seek = true;
|
||||
|
||||
if (not_before > 0) {
|
||||
r = sd_journal_get_monotonic_usec(j, &usec, NULL);
|
||||
|
||||
/* -ESTALE is returned if the
|
||||
timestamp is not from this boot */
|
||||
if (r == -ESTALE)
|
||||
continue;
|
||||
else if (r < 0)
|
||||
goto finish;
|
||||
|
||||
if (usec < not_before)
|
||||
continue;
|
||||
}
|
||||
|
||||
line ++;
|
||||
|
||||
r = output_journal(j, mode, line, n_columns, show_all);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (!follow)
|
||||
break;
|
||||
|
||||
r = fd_wait_for_event(fd, POLLIN, (usec_t) -1);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
r = sd_journal_process(j);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
}
|
||||
|
||||
if (mode == OUTPUT_JSON)
|
||||
fputs("\n]\n", stdout);
|
||||
|
||||
finish:
|
||||
if (m)
|
||||
free(m);
|
||||
|
||||
if (j)
|
||||
sd_journal_close(j);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
|
||||
[OUTPUT_SHORT] = "short",
|
||||
[OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
|
||||
[OUTPUT_VERBOSE] = "verbose",
|
||||
[OUTPUT_EXPORT] = "export",
|
||||
[OUTPUT_JSON] = "json",
|
||||
[OUTPUT_CAT] = "cat"
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);
|
||||
@@ -0,0 +1,56 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef foologsshowhfoo
|
||||
#define foologsshowhfoo
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2012 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <systemd/sd-journal.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
typedef enum OutputMode {
|
||||
OUTPUT_SHORT,
|
||||
OUTPUT_SHORT_MONOTONIC,
|
||||
OUTPUT_VERBOSE,
|
||||
OUTPUT_EXPORT,
|
||||
OUTPUT_JSON,
|
||||
OUTPUT_CAT,
|
||||
_OUTPUT_MODE_MAX,
|
||||
_OUTPUT_MODE_INVALID = -1
|
||||
} OutputMode;
|
||||
|
||||
int output_journal(sd_journal *j, OutputMode mode, unsigned line, unsigned n_columns, bool show_all);
|
||||
|
||||
int show_journal_by_unit(
|
||||
const char *unit,
|
||||
OutputMode mode,
|
||||
unsigned n_columns,
|
||||
usec_t not_before,
|
||||
unsigned how_many,
|
||||
bool show_all,
|
||||
bool follow);
|
||||
|
||||
const char* output_mode_to_string(OutputMode m);
|
||||
OutputMode output_mode_from_string(const char *s);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,274 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <asm/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "macro.h"
|
||||
#include "loopback-setup.h"
|
||||
#include "socket-util.h"
|
||||
|
||||
#define NLMSG_TAIL(nmsg) \
|
||||
((struct rtattr *) (((uint8_t*) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
|
||||
|
||||
static int add_rtattr(struct nlmsghdr *n, size_t max_length, int type, const void *data, size_t data_length) {
|
||||
size_t length;
|
||||
struct rtattr *rta;
|
||||
|
||||
length = RTA_LENGTH(data_length);
|
||||
|
||||
if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(length) > max_length)
|
||||
return -E2BIG;
|
||||
|
||||
rta = NLMSG_TAIL(n);
|
||||
rta->rta_type = type;
|
||||
rta->rta_len = length;
|
||||
memcpy(RTA_DATA(rta), data, data_length);
|
||||
n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t sendto_loop(int fd, const void *buf, size_t buf_len, int flags, const struct sockaddr *sa, socklen_t sa_len) {
|
||||
|
||||
for (;;) {
|
||||
ssize_t l;
|
||||
|
||||
if ((l = sendto(fd, buf, buf_len, flags, sa, sa_len)) >= 0)
|
||||
return l;
|
||||
|
||||
if (errno != EINTR)
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t recvfrom_loop(int fd, void *buf, size_t buf_len, int flags, struct sockaddr *sa, socklen_t *sa_len) {
|
||||
|
||||
for (;;) {
|
||||
ssize_t l;
|
||||
|
||||
if ((l = recvfrom(fd, buf, buf_len, flags, sa, sa_len)) >= 0)
|
||||
return l;
|
||||
|
||||
if (errno != EINTR)
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
|
||||
static int add_adresses(int fd, int if_loopback, unsigned *requests) {
|
||||
union {
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_nl nl;
|
||||
} sa;
|
||||
union {
|
||||
struct nlmsghdr header;
|
||||
uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
|
||||
NLMSG_ALIGN(sizeof(struct ifaddrmsg)) +
|
||||
RTA_LENGTH(sizeof(struct in6_addr))];
|
||||
} request;
|
||||
|
||||
struct ifaddrmsg *ifaddrmsg;
|
||||
uint32_t ipv4_address = htonl(INADDR_LOOPBACK);
|
||||
int r;
|
||||
|
||||
zero(request);
|
||||
|
||||
request.header.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
|
||||
request.header.nlmsg_type = RTM_NEWADDR;
|
||||
request.header.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_ACK;
|
||||
request.header.nlmsg_seq = *requests + 1;
|
||||
|
||||
ifaddrmsg = NLMSG_DATA(&request.header);
|
||||
ifaddrmsg->ifa_family = AF_INET;
|
||||
ifaddrmsg->ifa_prefixlen = 8;
|
||||
ifaddrmsg->ifa_flags = IFA_F_PERMANENT;
|
||||
ifaddrmsg->ifa_scope = RT_SCOPE_HOST;
|
||||
ifaddrmsg->ifa_index = if_loopback;
|
||||
|
||||
if ((r = add_rtattr(&request.header, sizeof(request), IFA_LOCAL, &ipv4_address, sizeof(ipv4_address))) < 0)
|
||||
return r;
|
||||
|
||||
zero(sa);
|
||||
sa.nl.nl_family = AF_NETLINK;
|
||||
|
||||
if (sendto_loop(fd, &request, request.header.nlmsg_len, 0, &sa.sa, sizeof(sa)) < 0)
|
||||
return -errno;
|
||||
(*requests)++;
|
||||
|
||||
if (!socket_ipv6_is_supported())
|
||||
return 0;
|
||||
|
||||
request.header.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
|
||||
request.header.nlmsg_seq = *requests + 1;
|
||||
|
||||
ifaddrmsg->ifa_family = AF_INET6;
|
||||
ifaddrmsg->ifa_prefixlen = 128;
|
||||
|
||||
if ((r = add_rtattr(&request.header, sizeof(request), IFA_LOCAL, &in6addr_loopback, sizeof(in6addr_loopback))) < 0)
|
||||
return r;
|
||||
|
||||
if (sendto_loop(fd, &request, request.header.nlmsg_len, 0, &sa.sa, sizeof(sa)) < 0)
|
||||
return -errno;
|
||||
(*requests)++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int start_interface(int fd, int if_loopback, unsigned *requests) {
|
||||
union {
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_nl nl;
|
||||
} sa;
|
||||
union {
|
||||
struct nlmsghdr header;
|
||||
uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
|
||||
NLMSG_ALIGN(sizeof(struct ifinfomsg))];
|
||||
} request;
|
||||
|
||||
struct ifinfomsg *ifinfomsg;
|
||||
|
||||
zero(request);
|
||||
|
||||
request.header.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
|
||||
request.header.nlmsg_type = RTM_NEWLINK;
|
||||
request.header.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
|
||||
request.header.nlmsg_seq = *requests + 1;
|
||||
|
||||
ifinfomsg = NLMSG_DATA(&request.header);
|
||||
ifinfomsg->ifi_family = AF_UNSPEC;
|
||||
ifinfomsg->ifi_index = if_loopback;
|
||||
ifinfomsg->ifi_flags = IFF_UP;
|
||||
ifinfomsg->ifi_change = IFF_UP;
|
||||
|
||||
zero(sa);
|
||||
sa.nl.nl_family = AF_NETLINK;
|
||||
|
||||
if (sendto_loop(fd, &request, request.header.nlmsg_len, 0, &sa.sa, sizeof(sa)) < 0)
|
||||
return -errno;
|
||||
|
||||
(*requests)++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_response(int fd, unsigned requests_max) {
|
||||
union {
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_nl nl;
|
||||
} sa;
|
||||
union {
|
||||
struct nlmsghdr header;
|
||||
uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
|
||||
NLMSG_ALIGN(sizeof(struct nlmsgerr))];
|
||||
} response;
|
||||
|
||||
ssize_t l;
|
||||
socklen_t sa_len = sizeof(sa);
|
||||
struct nlmsgerr *nlmsgerr;
|
||||
|
||||
if ((l = recvfrom_loop(fd, &response, sizeof(response), 0, &sa.sa, &sa_len)) < 0)
|
||||
return -errno;
|
||||
|
||||
if (sa_len != sizeof(sa.nl) ||
|
||||
sa.nl.nl_family != AF_NETLINK)
|
||||
return -EIO;
|
||||
|
||||
if (sa.nl.nl_pid != 0)
|
||||
return 0;
|
||||
|
||||
if ((size_t) l < sizeof(struct nlmsghdr))
|
||||
return -EIO;
|
||||
|
||||
if (response.header.nlmsg_type != NLMSG_ERROR ||
|
||||
(pid_t) response.header.nlmsg_pid != getpid() ||
|
||||
response.header.nlmsg_seq >= requests_max)
|
||||
return 0;
|
||||
|
||||
if ((size_t) l < NLMSG_LENGTH(sizeof(struct nlmsgerr)) ||
|
||||
response.header.nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
|
||||
return -EIO;
|
||||
|
||||
nlmsgerr = NLMSG_DATA(&response.header);
|
||||
|
||||
if (nlmsgerr->error < 0 && nlmsgerr->error != -EEXIST) {
|
||||
log_warning("Netlink failure for request %i: %s", response.header.nlmsg_seq, strerror(-nlmsgerr->error));
|
||||
return nlmsgerr->error;
|
||||
}
|
||||
|
||||
return response.header.nlmsg_seq;
|
||||
}
|
||||
|
||||
int loopback_setup(void) {
|
||||
int r, if_loopback;
|
||||
union {
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_nl nl;
|
||||
struct sockaddr_storage storage;
|
||||
} sa;
|
||||
unsigned requests = 0, i;
|
||||
int fd;
|
||||
|
||||
errno = 0;
|
||||
if ((if_loopback = (int) if_nametoindex("lo")) <= 0)
|
||||
return errno ? -errno : -ENODEV;
|
||||
|
||||
if ((fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0)
|
||||
return -errno;
|
||||
|
||||
zero(sa);
|
||||
sa.nl.nl_family = AF_NETLINK;
|
||||
|
||||
if (bind(fd, &sa.sa, sizeof(sa)) < 0) {
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if ((r = add_adresses(fd, if_loopback, &requests)) < 0)
|
||||
goto finish;
|
||||
|
||||
if ((r = start_interface(fd, if_loopback, &requests)) < 0)
|
||||
goto finish;
|
||||
|
||||
for (i = 0; i < requests; i++) {
|
||||
if ((r = read_response(fd, requests)) < 0)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = 0;
|
||||
|
||||
finish:
|
||||
if (r < 0)
|
||||
log_warning("Failed to configure loopback device: %s", strerror(-r));
|
||||
|
||||
if (fd >= 0)
|
||||
close_nointr_nofail(fd);
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef fooloopbacksetuphfoo
|
||||
#define fooloopbacksetuphfoo
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
int loopback_setup(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,265 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include <systemd/sd-id128.h>
|
||||
|
||||
#include "machine-id-setup.h"
|
||||
#include "macro.h"
|
||||
#include "util.h"
|
||||
#include "mkdir.h"
|
||||
#include "log.h"
|
||||
#include "virt.h"
|
||||
|
||||
static int shorten_uuid(char destination[36], const char *source) {
|
||||
unsigned i, j;
|
||||
|
||||
for (i = 0, j = 0; i < 36 && j < 32; i++) {
|
||||
int t;
|
||||
|
||||
t = unhexchar(source[i]);
|
||||
if (t < 0)
|
||||
continue;
|
||||
|
||||
destination[j++] = hexchar(t);
|
||||
}
|
||||
|
||||
if (i == 36 && j == 32) {
|
||||
destination[32] = '\n';
|
||||
destination[33] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int generate(char id[34]) {
|
||||
int fd, r;
|
||||
unsigned char *p;
|
||||
sd_id128_t buf;
|
||||
char *q;
|
||||
ssize_t k;
|
||||
const char *vm_id;
|
||||
|
||||
assert(id);
|
||||
|
||||
/* First, try reading the D-Bus machine id, unless it is a symlink */
|
||||
fd = open("/var/lib/dbus/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
|
||||
if (fd >= 0) {
|
||||
|
||||
k = loop_read(fd, id, 32, false);
|
||||
close_nointr_nofail(fd);
|
||||
|
||||
if (k >= 32) {
|
||||
id[32] = '\n';
|
||||
id[33] = 0;
|
||||
|
||||
log_info("Initializing machine ID from D-Bus machine ID.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* If that didn't work, see if we are running in qemu/kvm and a
|
||||
* machine ID was passed in via -uuid on the qemu/kvm command
|
||||
* line */
|
||||
|
||||
r = detect_vm(&vm_id);
|
||||
if (r > 0 && streq(vm_id, "kvm")) {
|
||||
char uuid[37];
|
||||
|
||||
fd = open("/sys/class/dmi/id/product_uuid", O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
|
||||
if (fd >= 0) {
|
||||
k = loop_read(fd, uuid, 36, false);
|
||||
close_nointr_nofail(fd);
|
||||
|
||||
if (k >= 36) {
|
||||
r = shorten_uuid(id, uuid);
|
||||
if (r >= 0) {
|
||||
log_info("Initializing machine ID from KVM UUID");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If that didn't work either, see if we are running in a
|
||||
* container, and a machine ID was passed in via
|
||||
* $container_uuid the way libvirt/LXC does it */
|
||||
|
||||
r = detect_container(NULL);
|
||||
if (r > 0) {
|
||||
FILE *f;
|
||||
|
||||
f = fopen("/proc/1/environ", "re");
|
||||
if (f) {
|
||||
bool done = false;
|
||||
|
||||
do {
|
||||
char line[LINE_MAX];
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < sizeof(line)-1; i++) {
|
||||
int c;
|
||||
|
||||
c = getc(f);
|
||||
if (_unlikely_(c == EOF)) {
|
||||
done = true;
|
||||
break;
|
||||
} else if (c == 0)
|
||||
break;
|
||||
|
||||
line[i] = c;
|
||||
}
|
||||
line[i] = 0;
|
||||
|
||||
if (startswith(line, "container_uuid=") &&
|
||||
strlen(line + 15) >= 36) {
|
||||
r = shorten_uuid(id, line + 15);
|
||||
if (r >= 0) {
|
||||
log_info("Initializing machine ID from container UUID");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
} while (!done);
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
/* If that didn't work, generate a random machine id */
|
||||
r = sd_id128_randomize(&buf);
|
||||
if (r < 0) {
|
||||
log_error("Failed to open /dev/urandom: %s", strerror(-r));
|
||||
return r;
|
||||
}
|
||||
|
||||
for (p = buf.bytes, q = id; p < buf.bytes + sizeof(buf); p++, q += 2) {
|
||||
q[0] = hexchar(*p >> 4);
|
||||
q[1] = hexchar(*p & 15);
|
||||
}
|
||||
|
||||
id[32] = '\n';
|
||||
id[33] = 0;
|
||||
|
||||
log_info("Initializing machine ID from random generator.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int machine_id_setup(void) {
|
||||
int fd, r;
|
||||
bool writable;
|
||||
struct stat st;
|
||||
char id[34]; /* 32 + \n + \0 */
|
||||
mode_t m;
|
||||
|
||||
m = umask(0000);
|
||||
|
||||
/* We create this 0444, to indicate that this isn't really
|
||||
* something you should ever modify. Of course, since the file
|
||||
* will be owned by root it doesn't matter much, but maybe
|
||||
* people look. */
|
||||
|
||||
fd = open("/etc/machine-id", O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY, 0444);
|
||||
if (fd >= 0)
|
||||
writable = true;
|
||||
else {
|
||||
fd = open("/etc/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
||||
if (fd < 0) {
|
||||
umask(m);
|
||||
log_error("Cannot open /etc/machine-id: %m");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
writable = false;
|
||||
}
|
||||
|
||||
umask(m);
|
||||
|
||||
if (fstat(fd, &st) < 0) {
|
||||
log_error("fstat() failed: %m");
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (S_ISREG(st.st_mode)) {
|
||||
if (loop_read(fd, id, 32, false) >= 32) {
|
||||
r = 0;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
/* Hmm, so, the id currently stored is not useful, then let's
|
||||
* generate one */
|
||||
|
||||
r = generate(id);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
if (S_ISREG(st.st_mode) && writable) {
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
|
||||
if (loop_write(fd, id, 33, false) == 33) {
|
||||
r = 0;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
close_nointr_nofail(fd);
|
||||
fd = -1;
|
||||
|
||||
/* Hmm, we couldn't write it? So let's write it to
|
||||
* /run/machine-id as a replacement */
|
||||
|
||||
m = umask(0022);
|
||||
r = write_one_line_file("/run/machine-id", id);
|
||||
umask(m);
|
||||
|
||||
if (r < 0) {
|
||||
log_error("Cannot write /run/machine-id: %s", strerror(-r));
|
||||
|
||||
unlink("/run/machine-id");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
/* And now, let's mount it over */
|
||||
r = mount("/run/machine-id", "/etc/machine-id", "bind", MS_BIND|MS_RDONLY, NULL) < 0 ? -errno : 0;
|
||||
if (r < 0) {
|
||||
unlink("/run/machine-id");
|
||||
log_error("Failed to mount /etc/machine-id: %s", strerror(-r));
|
||||
} else
|
||||
log_info("Installed transient /etc/machine-id file.");
|
||||
|
||||
finish:
|
||||
|
||||
if (fd >= 0)
|
||||
close_nointr_nofail(fd);
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef foomachineidsetuphfoo
|
||||
#define foomachineidsetuphfoo
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
int machine_id_setup(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,423 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <sys/mount.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libgen.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <ftw.h>
|
||||
|
||||
#include "mount-setup.h"
|
||||
#include "log.h"
|
||||
#include "macro.h"
|
||||
#include "util.h"
|
||||
#include "label.h"
|
||||
#include "set.h"
|
||||
#include "strv.h"
|
||||
#include "mkdir.h"
|
||||
|
||||
#ifndef TTY_GID
|
||||
#define TTY_GID 5
|
||||
#endif
|
||||
|
||||
typedef struct MountPoint {
|
||||
const char *what;
|
||||
const char *where;
|
||||
const char *type;
|
||||
const char *options;
|
||||
unsigned long flags;
|
||||
bool fatal;
|
||||
} MountPoint;
|
||||
|
||||
/* The first three entries we might need before SELinux is up. The
|
||||
* fourth (securityfs) is needed by IMA to load a custom policy. The
|
||||
* other ones we can delay until SELinux and IMA are loaded. */
|
||||
#define N_EARLY_MOUNT 4
|
||||
|
||||
static const MountPoint mount_table[] = {
|
||||
{ "proc", "/proc", "proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
|
||||
{ "sysfs", "/sys", "sysfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
|
||||
{ "devtmpfs", "/dev", "devtmpfs", "mode=755", MS_NOSUID|MS_STRICTATIME, true },
|
||||
{ "securityfs", "/sys/kernel/security", "securityfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, false },
|
||||
{ "tmpfs", "/dev/shm", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME, true },
|
||||
{ "devpts", "/dev/pts", "devpts", "mode=620,gid=" STRINGIFY(TTY_GID), MS_NOSUID|MS_NOEXEC, false },
|
||||
{ "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME, true },
|
||||
{ "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME, false },
|
||||
{ "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV, false },
|
||||
};
|
||||
|
||||
/* These are API file systems that might be mounted by other software,
|
||||
* we just list them here so that we know that we should ignore them */
|
||||
|
||||
static const char * const ignore_paths[] = {
|
||||
"/sys/fs/selinux",
|
||||
"/selinux",
|
||||
"/proc/bus/usb"
|
||||
};
|
||||
|
||||
bool mount_point_is_api(const char *path) {
|
||||
unsigned i;
|
||||
|
||||
/* Checks if this mount point is considered "API", and hence
|
||||
* should be ignored */
|
||||
|
||||
for (i = 0; i < ELEMENTSOF(mount_table); i ++)
|
||||
if (path_equal(path, mount_table[i].where))
|
||||
return true;
|
||||
|
||||
return path_startswith(path, "/sys/fs/cgroup/");
|
||||
}
|
||||
|
||||
bool mount_point_ignore(const char *path) {
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < ELEMENTSOF(ignore_paths); i++)
|
||||
if (path_equal(path, ignore_paths[i]))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int mount_one(const MountPoint *p, bool relabel) {
|
||||
int r;
|
||||
|
||||
assert(p);
|
||||
|
||||
/* Relabel first, just in case */
|
||||
if (relabel)
|
||||
label_fix(p->where, true);
|
||||
|
||||
if ((r = path_is_mount_point(p->where, true)) < 0)
|
||||
return r;
|
||||
|
||||
if (r > 0)
|
||||
return 0;
|
||||
|
||||
/* The access mode here doesn't really matter too much, since
|
||||
* the mounted file system will take precedence anyway. */
|
||||
mkdir_p(p->where, 0755);
|
||||
|
||||
log_debug("Mounting %s to %s of type %s with options %s.",
|
||||
p->what,
|
||||
p->where,
|
||||
p->type,
|
||||
strna(p->options));
|
||||
|
||||
if (mount(p->what,
|
||||
p->where,
|
||||
p->type,
|
||||
p->flags,
|
||||
p->options) < 0) {
|
||||
log_error("Failed to mount %s: %s", p->where, strerror(errno));
|
||||
return p->fatal ? -errno : 0;
|
||||
}
|
||||
|
||||
/* Relabel again, since we now mounted something fresh here */
|
||||
if (relabel)
|
||||
label_fix(p->where, false);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int mount_setup_early(void) {
|
||||
unsigned i;
|
||||
int r = 0;
|
||||
|
||||
assert_cc(N_EARLY_MOUNT <= ELEMENTSOF(mount_table));
|
||||
|
||||
/* Do a minimal mount of /proc and friends to enable the most
|
||||
* basic stuff, such as SELinux */
|
||||
for (i = 0; i < N_EARLY_MOUNT; i ++) {
|
||||
int j;
|
||||
|
||||
j = mount_one(mount_table + i, false);
|
||||
if (r == 0)
|
||||
r = j;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int mount_cgroup_controllers(char ***join_controllers) {
|
||||
int r;
|
||||
FILE *f;
|
||||
char buf[LINE_MAX];
|
||||
Set *controllers;
|
||||
|
||||
/* Mount all available cgroup controllers that are built into the kernel. */
|
||||
|
||||
f = fopen("/proc/cgroups", "re");
|
||||
if (!f) {
|
||||
log_error("Failed to enumerate cgroup controllers: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
controllers = set_new(string_hash_func, string_compare_func);
|
||||
if (!controllers) {
|
||||
r = -ENOMEM;
|
||||
log_error("Failed to allocate controller set.");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
/* Ignore the header line */
|
||||
(void) fgets(buf, sizeof(buf), f);
|
||||
|
||||
for (;;) {
|
||||
char *controller;
|
||||
int enabled = 0;
|
||||
|
||||
if (fscanf(f, "%ms %*i %*i %i", &controller, &enabled) != 2) {
|
||||
|
||||
if (feof(f))
|
||||
break;
|
||||
|
||||
log_error("Failed to parse /proc/cgroups.");
|
||||
r = -EIO;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (!enabled) {
|
||||
free(controller);
|
||||
continue;
|
||||
}
|
||||
|
||||
r = set_put(controllers, controller);
|
||||
if (r < 0) {
|
||||
log_error("Failed to add controller to set.");
|
||||
free(controller);
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
MountPoint p;
|
||||
char *controller, *where, *options;
|
||||
char ***k = NULL;
|
||||
|
||||
controller = set_steal_first(controllers);
|
||||
if (!controller)
|
||||
break;
|
||||
|
||||
if (join_controllers)
|
||||
for (k = join_controllers; *k; k++)
|
||||
if (strv_find(*k, controller))
|
||||
break;
|
||||
|
||||
if (k && *k) {
|
||||
char **i, **j;
|
||||
|
||||
for (i = *k, j = *k; *i; i++) {
|
||||
|
||||
if (!streq(*i, controller)) {
|
||||
char *t;
|
||||
|
||||
t = set_remove(controllers, *i);
|
||||
if (!t) {
|
||||
free(*i);
|
||||
continue;
|
||||
}
|
||||
free(t);
|
||||
}
|
||||
|
||||
*(j++) = *i;
|
||||
}
|
||||
|
||||
*j = NULL;
|
||||
|
||||
options = strv_join(*k, ",");
|
||||
if (!options) {
|
||||
log_error("Failed to join options");
|
||||
free(controller);
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
} else {
|
||||
options = controller;
|
||||
controller = NULL;
|
||||
}
|
||||
|
||||
where = strappend("/sys/fs/cgroup/", options);
|
||||
if (!where) {
|
||||
log_error("Failed to build path");
|
||||
free(options);
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
zero(p);
|
||||
p.what = "cgroup";
|
||||
p.where = where;
|
||||
p.type = "cgroup";
|
||||
p.options = options;
|
||||
p.flags = MS_NOSUID|MS_NOEXEC|MS_NODEV;
|
||||
p.fatal = false;
|
||||
|
||||
r = mount_one(&p, true);
|
||||
free(controller);
|
||||
free(where);
|
||||
|
||||
if (r < 0) {
|
||||
free(options);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (r > 0 && k && *k) {
|
||||
char **i;
|
||||
|
||||
for (i = *k; *i; i++) {
|
||||
char *t;
|
||||
|
||||
t = strappend("/sys/fs/cgroup/", *i);
|
||||
if (!t) {
|
||||
log_error("Failed to build path");
|
||||
r = -ENOMEM;
|
||||
free(options);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = symlink(options, t);
|
||||
free(t);
|
||||
|
||||
if (r < 0 && errno != EEXIST) {
|
||||
log_error("Failed to create symlink: %m");
|
||||
r = -errno;
|
||||
free(options);
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(options);
|
||||
}
|
||||
|
||||
r = 0;
|
||||
|
||||
finish:
|
||||
set_free_free(controllers);
|
||||
|
||||
fclose(f);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int symlink_and_label(const char *old_path, const char *new_path) {
|
||||
int r;
|
||||
|
||||
assert(old_path);
|
||||
assert(new_path);
|
||||
|
||||
if ((r = label_symlinkfile_set(new_path)) < 0)
|
||||
return r;
|
||||
|
||||
if (symlink(old_path, new_path) < 0)
|
||||
r = -errno;
|
||||
|
||||
label_file_clear();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int nftw_cb(
|
||||
const char *fpath,
|
||||
const struct stat *sb,
|
||||
int tflag,
|
||||
struct FTW *ftwbuf) {
|
||||
|
||||
/* No need to label /dev twice in a row... */
|
||||
if (_unlikely_(ftwbuf->level == 0))
|
||||
return FTW_CONTINUE;
|
||||
|
||||
label_fix(fpath, true);
|
||||
|
||||
/* /run/initramfs is static data and big, no need to
|
||||
* dynamically relabel its contents at boot... */
|
||||
if (_unlikely_(ftwbuf->level == 1 &&
|
||||
tflag == FTW_D &&
|
||||
streq(fpath, "/run/initramfs")))
|
||||
return FTW_SKIP_SUBTREE;
|
||||
|
||||
return FTW_CONTINUE;
|
||||
};
|
||||
|
||||
int mount_setup(bool loaded_policy) {
|
||||
|
||||
static const char symlinks[] =
|
||||
"/proc/kcore\0" "/dev/core\0"
|
||||
"/proc/self/fd\0" "/dev/fd\0"
|
||||
"/proc/self/fd/0\0" "/dev/stdin\0"
|
||||
"/proc/self/fd/1\0" "/dev/stdout\0"
|
||||
"/proc/self/fd/2\0" "/dev/stderr\0";
|
||||
|
||||
static const char relabel[] =
|
||||
"/run/initramfs/root-fsck\0"
|
||||
"/run/initramfs/shutdown\0";
|
||||
|
||||
int r;
|
||||
unsigned i;
|
||||
const char *j, *k;
|
||||
|
||||
for (i = 0; i < ELEMENTSOF(mount_table); i ++) {
|
||||
r = mount_one(mount_table + i, true);
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Nodes in devtmpfs and /run need to be manually updated for
|
||||
* the appropriate labels, after mounting. The other virtual
|
||||
* API file systems like /sys and /proc do not need that, they
|
||||
* use the same label for all their files. */
|
||||
if (loaded_policy) {
|
||||
usec_t before_relabel, after_relabel;
|
||||
char timespan[FORMAT_TIMESPAN_MAX];
|
||||
|
||||
before_relabel = now(CLOCK_MONOTONIC);
|
||||
|
||||
nftw("/dev", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
|
||||
nftw("/run", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
|
||||
|
||||
/* Explicitly relabel these */
|
||||
NULSTR_FOREACH(j, relabel)
|
||||
label_fix(j, true);
|
||||
|
||||
after_relabel = now(CLOCK_MONOTONIC);
|
||||
|
||||
log_info("Relabelled /dev and /run in %s.",
|
||||
format_timespan(timespan, sizeof(timespan), after_relabel - before_relabel));
|
||||
}
|
||||
|
||||
/* Create a few default symlinks, which are normally created
|
||||
* by udevd, but some scripts might need them before we start
|
||||
* udevd. */
|
||||
NULSTR_FOREACH_PAIR(j, k, symlinks)
|
||||
symlink_and_label(j, k);
|
||||
|
||||
/* Create a few directories we always want around */
|
||||
label_mkdir("/run/systemd", 0755);
|
||||
label_mkdir("/run/systemd/system", 0755);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef foomountsetuphfoo
|
||||
#define foomountsetuphfoo
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
int mount_setup_early(void);
|
||||
|
||||
int mount_setup(bool loaded_policy);
|
||||
|
||||
int mount_cgroup_controllers(char ***join_controllers);
|
||||
|
||||
bool mount_point_is_api(const char *path);
|
||||
bool mount_point_ignore(const char *path);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,348 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "mkdir.h"
|
||||
#include "strv.h"
|
||||
|
||||
#include "path-lookup.h"
|
||||
|
||||
int user_config_home(char **config_home) {
|
||||
const char *e;
|
||||
|
||||
if ((e = getenv("XDG_CONFIG_HOME"))) {
|
||||
if (asprintf(config_home, "%s/systemd/user", e) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
return 1;
|
||||
} else {
|
||||
const char *home;
|
||||
|
||||
if ((home = getenv("HOME"))) {
|
||||
if (asprintf(config_home, "%s/.config/systemd/user", home) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char** user_dirs(void) {
|
||||
const char * const config_unit_paths[] = {
|
||||
USER_CONFIG_UNIT_PATH,
|
||||
"/etc/systemd/user",
|
||||
"/run/systemd/user",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char * const data_unit_paths[] = {
|
||||
"/usr/local/lib/systemd/user",
|
||||
"/usr/local/share/systemd/user",
|
||||
USER_DATA_UNIT_PATH,
|
||||
"/usr/lib/systemd/user",
|
||||
"/usr/share/systemd/user",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char *home, *e;
|
||||
char *config_home = NULL, *data_home = NULL;
|
||||
char **config_dirs = NULL, **data_dirs = NULL;
|
||||
char **r = NULL, **t;
|
||||
|
||||
/* Implement the mechanisms defined in
|
||||
*
|
||||
* http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
|
||||
*
|
||||
* We look in both the config and the data dirs because we
|
||||
* want to encourage that distributors ship their unit files
|
||||
* as data, and allow overriding as configuration.
|
||||
*/
|
||||
|
||||
if (user_config_home(&config_home) < 0)
|
||||
goto fail;
|
||||
|
||||
home = getenv("HOME");
|
||||
|
||||
if ((e = getenv("XDG_CONFIG_DIRS")))
|
||||
if (!(config_dirs = strv_split(e, ":")))
|
||||
goto fail;
|
||||
|
||||
/* We don't treat /etc/xdg/systemd here as the spec
|
||||
* suggests because we assume that that is a link to
|
||||
* /etc/systemd/ anyway. */
|
||||
|
||||
if ((e = getenv("XDG_DATA_HOME"))) {
|
||||
if (asprintf(&data_home, "%s/systemd/user", e) < 0)
|
||||
goto fail;
|
||||
|
||||
} else if (home) {
|
||||
if (asprintf(&data_home, "%s/.local/share/systemd/user", home) < 0)
|
||||
goto fail;
|
||||
|
||||
/* There is really no need for two unit dirs in $HOME,
|
||||
* except to be fully compliant with the XDG spec. We
|
||||
* now try to link the two dirs, so that we can
|
||||
* minimize disk seeks a little. Further down we'll
|
||||
* then filter out this link, if it is actually is
|
||||
* one. */
|
||||
|
||||
mkdir_parents(data_home, 0777);
|
||||
(void) symlink("../../../.config/systemd/user", data_home);
|
||||
}
|
||||
|
||||
if ((e = getenv("XDG_DATA_DIRS")))
|
||||
data_dirs = strv_split(e, ":");
|
||||
else
|
||||
data_dirs = strv_new("/usr/local/share",
|
||||
"/usr/share",
|
||||
NULL);
|
||||
|
||||
if (!data_dirs)
|
||||
goto fail;
|
||||
|
||||
/* Now merge everything we found. */
|
||||
if (config_home) {
|
||||
if (!(t = strv_append(r, config_home)))
|
||||
goto fail;
|
||||
strv_free(r);
|
||||
r = t;
|
||||
}
|
||||
|
||||
if (!strv_isempty(config_dirs)) {
|
||||
if (!(t = strv_merge_concat(r, config_dirs, "/systemd/user")))
|
||||
goto finish;
|
||||
strv_free(r);
|
||||
r = t;
|
||||
}
|
||||
|
||||
if (!(t = strv_merge(r, (char**) config_unit_paths)))
|
||||
goto fail;
|
||||
strv_free(r);
|
||||
r = t;
|
||||
|
||||
if (data_home) {
|
||||
if (!(t = strv_append(r, data_home)))
|
||||
goto fail;
|
||||
strv_free(r);
|
||||
r = t;
|
||||
}
|
||||
|
||||
if (!strv_isempty(data_dirs)) {
|
||||
if (!(t = strv_merge_concat(r, data_dirs, "/systemd/user")))
|
||||
goto fail;
|
||||
strv_free(r);
|
||||
r = t;
|
||||
}
|
||||
|
||||
if (!(t = strv_merge(r, (char**) data_unit_paths)))
|
||||
goto fail;
|
||||
strv_free(r);
|
||||
r = t;
|
||||
|
||||
if (!strv_path_make_absolute_cwd(r))
|
||||
goto fail;
|
||||
|
||||
finish:
|
||||
free(config_home);
|
||||
strv_free(config_dirs);
|
||||
free(data_home);
|
||||
strv_free(data_dirs);
|
||||
|
||||
return r;
|
||||
|
||||
fail:
|
||||
strv_free(r);
|
||||
r = NULL;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
int lookup_paths_init(LookupPaths *p, ManagerRunningAs running_as, bool personal) {
|
||||
const char *e;
|
||||
char *t;
|
||||
|
||||
assert(p);
|
||||
|
||||
/* First priority is whatever has been passed to us via env
|
||||
* vars */
|
||||
if ((e = getenv("SYSTEMD_UNIT_PATH")))
|
||||
if (!(p->unit_path = split_path_and_make_absolute(e)))
|
||||
return -ENOMEM;
|
||||
|
||||
if (strv_isempty(p->unit_path)) {
|
||||
|
||||
/* Nothing is set, so let's figure something out. */
|
||||
strv_free(p->unit_path);
|
||||
|
||||
if (running_as == MANAGER_USER) {
|
||||
|
||||
if (personal)
|
||||
p->unit_path = user_dirs();
|
||||
else
|
||||
p->unit_path = strv_new(
|
||||
/* If you modify this you also want to modify
|
||||
* systemduserunitpath= in systemd.pc.in, and
|
||||
* the arrays in user_dirs() above! */
|
||||
USER_CONFIG_UNIT_PATH,
|
||||
"/etc/systemd/user",
|
||||
"/run/systemd/user",
|
||||
"/usr/local/lib/systemd/user",
|
||||
"/usr/local/share/systemd/user",
|
||||
USER_DATA_UNIT_PATH,
|
||||
"/usr/lib/systemd/user",
|
||||
"/usr/share/systemd/user",
|
||||
NULL);
|
||||
|
||||
if (!p->unit_path)
|
||||
return -ENOMEM;
|
||||
|
||||
} else
|
||||
if (!(p->unit_path = strv_new(
|
||||
/* If you modify this you also want to modify
|
||||
* systemdsystemunitpath= in systemd.pc.in! */
|
||||
SYSTEM_CONFIG_UNIT_PATH,
|
||||
"/etc/systemd/system",
|
||||
"/run/systemd/system",
|
||||
"/usr/local/lib/systemd/system",
|
||||
SYSTEM_DATA_UNIT_PATH,
|
||||
"/usr/lib/systemd/system",
|
||||
#ifdef HAVE_SPLIT_USR
|
||||
"/lib/systemd/system",
|
||||
#endif
|
||||
NULL)))
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (p->unit_path)
|
||||
if (!strv_path_canonicalize(p->unit_path))
|
||||
return -ENOMEM;
|
||||
|
||||
strv_uniq(p->unit_path);
|
||||
strv_path_remove_empty(p->unit_path);
|
||||
|
||||
if (!strv_isempty(p->unit_path)) {
|
||||
|
||||
if (!(t = strv_join(p->unit_path, "\n\t")))
|
||||
return -ENOMEM;
|
||||
log_debug("Looking for unit files in:\n\t%s", t);
|
||||
free(t);
|
||||
} else {
|
||||
log_debug("Ignoring unit files.");
|
||||
strv_free(p->unit_path);
|
||||
p->unit_path = NULL;
|
||||
}
|
||||
|
||||
if (running_as == MANAGER_SYSTEM) {
|
||||
#ifdef HAVE_SYSV_COMPAT
|
||||
/* /etc/init.d/ compatibility does not matter to users */
|
||||
|
||||
if ((e = getenv("SYSTEMD_SYSVINIT_PATH")))
|
||||
if (!(p->sysvinit_path = split_path_and_make_absolute(e)))
|
||||
return -ENOMEM;
|
||||
|
||||
if (strv_isempty(p->sysvinit_path)) {
|
||||
strv_free(p->sysvinit_path);
|
||||
|
||||
if (!(p->sysvinit_path = strv_new(
|
||||
SYSTEM_SYSVINIT_PATH, /* /etc/init.d/ */
|
||||
NULL)))
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if ((e = getenv("SYSTEMD_SYSVRCND_PATH")))
|
||||
if (!(p->sysvrcnd_path = split_path_and_make_absolute(e)))
|
||||
return -ENOMEM;
|
||||
|
||||
if (strv_isempty(p->sysvrcnd_path)) {
|
||||
strv_free(p->sysvrcnd_path);
|
||||
|
||||
if (!(p->sysvrcnd_path = strv_new(
|
||||
SYSTEM_SYSVRCND_PATH, /* /etc/rcN.d/ */
|
||||
NULL)))
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (p->sysvinit_path)
|
||||
if (!strv_path_canonicalize(p->sysvinit_path))
|
||||
return -ENOMEM;
|
||||
|
||||
if (p->sysvrcnd_path)
|
||||
if (!strv_path_canonicalize(p->sysvrcnd_path))
|
||||
return -ENOMEM;
|
||||
|
||||
strv_uniq(p->sysvinit_path);
|
||||
strv_uniq(p->sysvrcnd_path);
|
||||
|
||||
strv_path_remove_empty(p->sysvinit_path);
|
||||
strv_path_remove_empty(p->sysvrcnd_path);
|
||||
|
||||
if (!strv_isempty(p->sysvinit_path)) {
|
||||
|
||||
if (!(t = strv_join(p->sysvinit_path, "\n\t")))
|
||||
return -ENOMEM;
|
||||
|
||||
log_debug("Looking for SysV init scripts in:\n\t%s", t);
|
||||
free(t);
|
||||
} else {
|
||||
log_debug("Ignoring SysV init scripts.");
|
||||
strv_free(p->sysvinit_path);
|
||||
p->sysvinit_path = NULL;
|
||||
}
|
||||
|
||||
if (!strv_isempty(p->sysvrcnd_path)) {
|
||||
|
||||
if (!(t = strv_join(p->sysvrcnd_path, "\n\t")))
|
||||
return -ENOMEM;
|
||||
|
||||
log_debug("Looking for SysV rcN.d links in:\n\t%s", t);
|
||||
free(t);
|
||||
} else {
|
||||
log_debug("Ignoring SysV rcN.d links.");
|
||||
strv_free(p->sysvrcnd_path);
|
||||
p->sysvrcnd_path = NULL;
|
||||
}
|
||||
#else
|
||||
log_debug("Disabled SysV init scripts and rcN.d links support");
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void lookup_paths_free(LookupPaths *p) {
|
||||
assert(p);
|
||||
|
||||
strv_free(p->unit_path);
|
||||
p->unit_path = NULL;
|
||||
|
||||
#ifdef HAVE_SYSV_COMPAT
|
||||
strv_free(p->sysvinit_path);
|
||||
strv_free(p->sysvrcnd_path);
|
||||
p->sysvinit_path = p->sysvrcnd_path = NULL;
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef foopathlookuphfoo
|
||||
#define foopathlookuphfoo
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
typedef struct LookupPaths {
|
||||
char **unit_path;
|
||||
#ifdef HAVE_SYSV_COMPAT
|
||||
char **sysvinit_path;
|
||||
char **sysvrcnd_path;
|
||||
#endif
|
||||
} LookupPaths;
|
||||
|
||||
#include "manager.h"
|
||||
|
||||
int user_config_home(char **config_home);
|
||||
|
||||
int lookup_paths_init(LookupPaths *p, ManagerRunningAs running_as, bool personal);
|
||||
void lookup_paths_free(LookupPaths *p);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,67 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2011 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
#include "spawn-ask-password-agent.h"
|
||||
|
||||
static pid_t agent_pid = 0;
|
||||
|
||||
int ask_password_agent_open(void) {
|
||||
int r;
|
||||
|
||||
if (agent_pid > 0)
|
||||
return 0;
|
||||
|
||||
/* We check STDIN here, not STDOUT, since this is about input,
|
||||
* not output */
|
||||
if (!isatty(STDIN_FILENO))
|
||||
return 0;
|
||||
|
||||
r = fork_agent(&agent_pid,
|
||||
NULL, 0,
|
||||
SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH,
|
||||
SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, "--watch", NULL);
|
||||
if (r < 0)
|
||||
log_error("Failed to fork TTY ask password agent: %s", strerror(-r));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void ask_password_agent_close(void) {
|
||||
|
||||
if (agent_pid <= 0)
|
||||
return;
|
||||
|
||||
/* Inform agent that we are done */
|
||||
kill(agent_pid, SIGTERM);
|
||||
kill(agent_pid, SIGCONT);
|
||||
wait_for_terminate(agent_pid, NULL);
|
||||
agent_pid = 0;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef foospawnaskpasswordagenthfoo
|
||||
#define foospawnaskpasswordagenthfoo
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2011 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
int ask_password_agent_open(void);
|
||||
void ask_password_agent_close(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,86 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2011 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/poll.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
#include "spawn-polkit-agent.h"
|
||||
|
||||
static pid_t agent_pid = 0;
|
||||
|
||||
int polkit_agent_open(void) {
|
||||
int r;
|
||||
int pipe_fd[2];
|
||||
char notify_fd[10 + 1];
|
||||
|
||||
if (agent_pid > 0)
|
||||
return 0;
|
||||
|
||||
/* We check STDIN here, not STDOUT, since this is about input,
|
||||
* not output */
|
||||
if (!isatty(STDIN_FILENO))
|
||||
return 0;
|
||||
|
||||
if (pipe2(pipe_fd, 0) < 0)
|
||||
return -errno;
|
||||
|
||||
snprintf(notify_fd, sizeof(notify_fd), "%i", pipe_fd[1]);
|
||||
char_array_0(notify_fd);
|
||||
|
||||
r = fork_agent(&agent_pid,
|
||||
&pipe_fd[1], 1,
|
||||
POLKIT_AGENT_BINARY_PATH,
|
||||
POLKIT_AGENT_BINARY_PATH, "--notify-fd", notify_fd, NULL);
|
||||
|
||||
/* Close the writing side, because that's the one for the agent */
|
||||
close_nointr_nofail(pipe_fd[1]);
|
||||
|
||||
if (r < 0)
|
||||
log_error("Failed to fork TTY ask password agent: %s", strerror(-r));
|
||||
else
|
||||
/* Wait until the agent closes the fd */
|
||||
fd_wait_for_event(pipe_fd[0], POLLHUP, (usec_t) -1);
|
||||
|
||||
close_nointr_nofail(pipe_fd[0]);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void polkit_agent_close(void) {
|
||||
|
||||
if (agent_pid <= 0)
|
||||
return;
|
||||
|
||||
/* Inform agent that we are done */
|
||||
kill(agent_pid, SIGTERM);
|
||||
kill(agent_pid, SIGCONT);
|
||||
wait_for_terminate(agent_pid, NULL);
|
||||
agent_pid = 0;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef foospawnpolkitagenthfoo
|
||||
#define foospawnpolkitagenthfoo
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2012 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
int polkit_agent_open(void);
|
||||
void polkit_agent_close(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,108 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "macro.h"
|
||||
#include "util.h"
|
||||
#include "specifier.h"
|
||||
|
||||
/*
|
||||
* Generic infrastructure for replacing %x style specifiers in
|
||||
* strings. Will call a callback for each replacement.
|
||||
*
|
||||
*/
|
||||
|
||||
char *specifier_printf(const char *text, const Specifier table[], void *userdata) {
|
||||
char *r, *t;
|
||||
const char *f;
|
||||
bool percent = false;
|
||||
size_t l;
|
||||
|
||||
assert(text);
|
||||
assert(table);
|
||||
|
||||
l = strlen(text);
|
||||
if (!(r = new(char, l+1)))
|
||||
return NULL;
|
||||
|
||||
t = r;
|
||||
|
||||
for (f = text; *f; f++, l--) {
|
||||
|
||||
if (percent) {
|
||||
if (*f == '%')
|
||||
*(t++) = '%';
|
||||
else {
|
||||
const Specifier *i;
|
||||
|
||||
for (i = table; i->specifier; i++)
|
||||
if (i->specifier == *f)
|
||||
break;
|
||||
|
||||
if (i->lookup) {
|
||||
char *n, *w;
|
||||
size_t k, j;
|
||||
|
||||
if (!(w = i->lookup(i->specifier, i->data, userdata))) {
|
||||
free(r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
j = t - r;
|
||||
k = strlen(w);
|
||||
|
||||
if (!(n = new(char, j + k + l + 1))) {
|
||||
free(r);
|
||||
free(w);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(n, r, j);
|
||||
memcpy(n + j, w, k);
|
||||
|
||||
free(r);
|
||||
free(w);
|
||||
|
||||
r = n;
|
||||
t = n + j + k;
|
||||
} else {
|
||||
*(t++) = '%';
|
||||
*(t++) = *f;
|
||||
}
|
||||
}
|
||||
|
||||
percent = false;
|
||||
} else if (*f == '%')
|
||||
percent = true;
|
||||
else
|
||||
*(t++) = *f;
|
||||
}
|
||||
|
||||
*t = 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Generic handler for simple string replacements */
|
||||
|
||||
char* specifier_string(char specifier, void *data, void *userdata) {
|
||||
return strdup(strempty(data));
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef foospecifierhfoo
|
||||
#define foospecifierhfoo
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
typedef char* (*SpecifierCallback)(char specifier, void *data, void *userdata);
|
||||
|
||||
typedef struct Specifier {
|
||||
const char specifier;
|
||||
const SpecifierCallback lookup;
|
||||
void *data;
|
||||
} Specifier;
|
||||
|
||||
char *specifier_printf(const char *text, const Specifier table[], void *userdata);
|
||||
|
||||
char* specifier_string(char specifier, void *data, void *userdata);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,644 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 ProFUSION embedded systems
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/swap.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/loop.h>
|
||||
#include <linux/dm-ioctl.h>
|
||||
#include <libudev.h>
|
||||
|
||||
#include "list.h"
|
||||
#include "mount-setup.h"
|
||||
#include "umount.h"
|
||||
#include "util.h"
|
||||
|
||||
typedef struct MountPoint {
|
||||
char *path;
|
||||
dev_t devnum;
|
||||
bool skip_ro;
|
||||
LIST_FIELDS (struct MountPoint, mount_point);
|
||||
} MountPoint;
|
||||
|
||||
static void mount_point_free(MountPoint **head, MountPoint *m) {
|
||||
assert(head);
|
||||
assert(m);
|
||||
|
||||
LIST_REMOVE(MountPoint, mount_point, *head, m);
|
||||
|
||||
free(m->path);
|
||||
free(m);
|
||||
}
|
||||
|
||||
static void mount_points_list_free(MountPoint **head) {
|
||||
assert(head);
|
||||
|
||||
while (*head)
|
||||
mount_point_free(head, *head);
|
||||
}
|
||||
|
||||
static int mount_points_list_get(MountPoint **head) {
|
||||
FILE *proc_self_mountinfo;
|
||||
char *path, *p;
|
||||
unsigned int i;
|
||||
int r;
|
||||
|
||||
assert(head);
|
||||
|
||||
if (!(proc_self_mountinfo = fopen("/proc/self/mountinfo", "re")))
|
||||
return -errno;
|
||||
|
||||
for (i = 1;; i++) {
|
||||
int k;
|
||||
MountPoint *m;
|
||||
char *root;
|
||||
bool skip_ro;
|
||||
|
||||
path = p = NULL;
|
||||
|
||||
if ((k = fscanf(proc_self_mountinfo,
|
||||
"%*s " /* (1) mount id */
|
||||
"%*s " /* (2) parent id */
|
||||
"%*s " /* (3) major:minor */
|
||||
"%ms " /* (4) root */
|
||||
"%ms " /* (5) mount point */
|
||||
"%*s" /* (6) mount options */
|
||||
"%*[^-]" /* (7) optional fields */
|
||||
"- " /* (8) separator */
|
||||
"%*s " /* (9) file system type */
|
||||
"%*s" /* (10) mount source */
|
||||
"%*s" /* (11) mount options 2 */
|
||||
"%*[^\n]", /* some rubbish at the end */
|
||||
&root,
|
||||
&path)) != 2) {
|
||||
if (k == EOF)
|
||||
break;
|
||||
|
||||
log_warning("Failed to parse /proc/self/mountinfo:%u.", i);
|
||||
|
||||
free(path);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If we encounter a bind mount, don't try to remount
|
||||
* the source dir too early */
|
||||
skip_ro = !streq(root, "/");
|
||||
free(root);
|
||||
|
||||
p = cunescape(path);
|
||||
free(path);
|
||||
|
||||
if (!p) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (mount_point_is_api(p) || mount_point_ignore(p)) {
|
||||
free(p);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(m = new0(MountPoint, 1))) {
|
||||
free(p);
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
m->path = p;
|
||||
m->skip_ro = skip_ro;
|
||||
LIST_PREPEND(MountPoint, mount_point, *head, m);
|
||||
}
|
||||
|
||||
r = 0;
|
||||
|
||||
finish:
|
||||
fclose(proc_self_mountinfo);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int swap_list_get(MountPoint **head) {
|
||||
FILE *proc_swaps;
|
||||
unsigned int i;
|
||||
int r;
|
||||
|
||||
assert(head);
|
||||
|
||||
if (!(proc_swaps = fopen("/proc/swaps", "re")))
|
||||
return (errno == ENOENT) ? 0 : -errno;
|
||||
|
||||
(void) fscanf(proc_swaps, "%*s %*s %*s %*s %*s\n");
|
||||
|
||||
for (i = 2;; i++) {
|
||||
MountPoint *swap;
|
||||
char *dev = NULL, *d;
|
||||
int k;
|
||||
|
||||
if ((k = fscanf(proc_swaps,
|
||||
"%ms " /* device/file */
|
||||
"%*s " /* type of swap */
|
||||
"%*s " /* swap size */
|
||||
"%*s " /* used */
|
||||
"%*s\n", /* priority */
|
||||
&dev)) != 1) {
|
||||
|
||||
if (k == EOF)
|
||||
break;
|
||||
|
||||
log_warning("Failed to parse /proc/swaps:%u.", i);
|
||||
|
||||
free(dev);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (endswith(dev, "(deleted)")) {
|
||||
free(dev);
|
||||
continue;
|
||||
}
|
||||
|
||||
d = cunescape(dev);
|
||||
free(dev);
|
||||
|
||||
if (!d) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (!(swap = new0(MountPoint, 1))) {
|
||||
free(d);
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
swap->path = d;
|
||||
LIST_PREPEND(MountPoint, mount_point, *head, swap);
|
||||
}
|
||||
|
||||
r = 0;
|
||||
|
||||
finish:
|
||||
fclose(proc_swaps);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int loopback_list_get(MountPoint **head) {
|
||||
int r;
|
||||
struct udev *udev;
|
||||
struct udev_enumerate *e = NULL;
|
||||
struct udev_list_entry *item = NULL, *first = NULL;
|
||||
|
||||
assert(head);
|
||||
|
||||
if (!(udev = udev_new())) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (!(e = udev_enumerate_new(udev))) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (udev_enumerate_add_match_subsystem(e, "block") < 0 ||
|
||||
udev_enumerate_add_match_sysname(e, "loop*") < 0) {
|
||||
r = -EIO;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (udev_enumerate_scan_devices(e) < 0) {
|
||||
r = -EIO;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
first = udev_enumerate_get_list_entry(e);
|
||||
udev_list_entry_foreach(item, first) {
|
||||
MountPoint *lb;
|
||||
struct udev_device *d;
|
||||
char *loop;
|
||||
const char *dn;
|
||||
|
||||
if (!(d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)))) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (!(dn = udev_device_get_devnode(d))) {
|
||||
udev_device_unref(d);
|
||||
continue;
|
||||
}
|
||||
|
||||
loop = strdup(dn);
|
||||
udev_device_unref(d);
|
||||
|
||||
if (!loop) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (!(lb = new0(MountPoint, 1))) {
|
||||
free(loop);
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
lb->path = loop;
|
||||
LIST_PREPEND(MountPoint, mount_point, *head, lb);
|
||||
}
|
||||
|
||||
r = 0;
|
||||
|
||||
finish:
|
||||
if (e)
|
||||
udev_enumerate_unref(e);
|
||||
|
||||
if (udev)
|
||||
udev_unref(udev);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int dm_list_get(MountPoint **head) {
|
||||
int r;
|
||||
struct udev *udev;
|
||||
struct udev_enumerate *e = NULL;
|
||||
struct udev_list_entry *item = NULL, *first = NULL;
|
||||
|
||||
assert(head);
|
||||
|
||||
if (!(udev = udev_new())) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (!(e = udev_enumerate_new(udev))) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (udev_enumerate_add_match_subsystem(e, "block") < 0 ||
|
||||
udev_enumerate_add_match_sysname(e, "dm-*") < 0) {
|
||||
r = -EIO;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (udev_enumerate_scan_devices(e) < 0) {
|
||||
r = -EIO;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
first = udev_enumerate_get_list_entry(e);
|
||||
|
||||
udev_list_entry_foreach(item, first) {
|
||||
MountPoint *m;
|
||||
struct udev_device *d;
|
||||
dev_t devnum;
|
||||
char *node;
|
||||
const char *dn;
|
||||
|
||||
if (!(d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)))) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
devnum = udev_device_get_devnum(d);
|
||||
dn = udev_device_get_devnode(d);
|
||||
|
||||
if (major(devnum) == 0 || !dn) {
|
||||
udev_device_unref(d);
|
||||
continue;
|
||||
}
|
||||
|
||||
node = strdup(dn);
|
||||
udev_device_unref(d);
|
||||
|
||||
if (!node) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (!(m = new(MountPoint, 1))) {
|
||||
free(node);
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
m->path = node;
|
||||
m->devnum = devnum;
|
||||
LIST_PREPEND(MountPoint, mount_point, *head, m);
|
||||
}
|
||||
|
||||
r = 0;
|
||||
|
||||
finish:
|
||||
if (e)
|
||||
udev_enumerate_unref(e);
|
||||
|
||||
if (udev)
|
||||
udev_unref(udev);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int delete_loopback(const char *device) {
|
||||
int fd, r;
|
||||
|
||||
if ((fd = open(device, O_RDONLY|O_CLOEXEC)) < 0)
|
||||
return errno == ENOENT ? 0 : -errno;
|
||||
|
||||
r = ioctl(fd, LOOP_CLR_FD, 0);
|
||||
close_nointr_nofail(fd);
|
||||
|
||||
if (r >= 0)
|
||||
return 1;
|
||||
|
||||
/* ENXIO: not bound, so no error */
|
||||
if (errno == ENXIO)
|
||||
return 0;
|
||||
|
||||
return -errno;
|
||||
}
|
||||
|
||||
static int delete_dm(dev_t devnum) {
|
||||
int fd, r;
|
||||
struct dm_ioctl dm;
|
||||
|
||||
assert(major(devnum) != 0);
|
||||
|
||||
if ((fd = open("/dev/mapper/control", O_RDWR|O_CLOEXEC)) < 0)
|
||||
return -errno;
|
||||
|
||||
zero(dm);
|
||||
dm.version[0] = DM_VERSION_MAJOR;
|
||||
dm.version[1] = DM_VERSION_MINOR;
|
||||
dm.version[2] = DM_VERSION_PATCHLEVEL;
|
||||
|
||||
dm.data_size = sizeof(dm);
|
||||
dm.dev = devnum;
|
||||
|
||||
r = ioctl(fd, DM_DEV_REMOVE, &dm);
|
||||
close_nointr_nofail(fd);
|
||||
|
||||
return r >= 0 ? 0 : -errno;
|
||||
}
|
||||
|
||||
static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_error) {
|
||||
MountPoint *m, *n;
|
||||
int n_failed = 0;
|
||||
|
||||
assert(head);
|
||||
|
||||
LIST_FOREACH_SAFE(mount_point, m, n, *head) {
|
||||
if (path_equal(m->path, "/")
|
||||
#ifndef HAVE_SPLIT_USR
|
||||
|| path_equal(m->path, "/usr")
|
||||
#endif
|
||||
) {
|
||||
n_failed++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Trying to umount. Forcing to umount if busy (only for NFS mounts) */
|
||||
if (umount2(m->path, MNT_FORCE) == 0) {
|
||||
log_info("Unmounted %s.", m->path);
|
||||
if (changed)
|
||||
*changed = true;
|
||||
|
||||
mount_point_free(head, m);
|
||||
} else if (log_error) {
|
||||
log_warning("Could not unmount %s: %m", m->path);
|
||||
n_failed++;
|
||||
}
|
||||
}
|
||||
|
||||
return n_failed;
|
||||
}
|
||||
|
||||
static int mount_points_list_remount_read_only(MountPoint **head, bool *changed) {
|
||||
MountPoint *m, *n;
|
||||
int n_failed = 0;
|
||||
|
||||
assert(head);
|
||||
|
||||
LIST_FOREACH_SAFE(mount_point, m, n, *head) {
|
||||
|
||||
if (m->skip_ro) {
|
||||
n_failed++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Trying to remount read-only */
|
||||
if (mount(NULL, m->path, NULL, MS_MGC_VAL|MS_REMOUNT|MS_RDONLY, NULL) == 0) {
|
||||
if (changed)
|
||||
*changed = true;
|
||||
|
||||
mount_point_free(head, m);
|
||||
} else {
|
||||
log_warning("Could not remount as read-only %s: %m", m->path);
|
||||
n_failed++;
|
||||
}
|
||||
}
|
||||
|
||||
return n_failed;
|
||||
}
|
||||
|
||||
static int swap_points_list_off(MountPoint **head, bool *changed) {
|
||||
MountPoint *m, *n;
|
||||
int n_failed = 0;
|
||||
|
||||
assert(head);
|
||||
|
||||
LIST_FOREACH_SAFE(mount_point, m, n, *head) {
|
||||
if (swapoff(m->path) == 0) {
|
||||
if (changed)
|
||||
*changed = true;
|
||||
|
||||
mount_point_free(head, m);
|
||||
} else {
|
||||
log_warning("Could not deactivate swap %s: %m", m->path);
|
||||
n_failed++;
|
||||
}
|
||||
}
|
||||
|
||||
return n_failed;
|
||||
}
|
||||
|
||||
static int loopback_points_list_detach(MountPoint **head, bool *changed) {
|
||||
MountPoint *m, *n;
|
||||
int n_failed = 0, k;
|
||||
struct stat root_st;
|
||||
|
||||
assert(head);
|
||||
|
||||
k = lstat("/", &root_st);
|
||||
|
||||
LIST_FOREACH_SAFE(mount_point, m, n, *head) {
|
||||
int r;
|
||||
struct stat loopback_st;
|
||||
|
||||
if (k >= 0 &&
|
||||
major(root_st.st_dev) != 0 &&
|
||||
lstat(m->path, &loopback_st) >= 0 &&
|
||||
root_st.st_dev == loopback_st.st_rdev) {
|
||||
n_failed ++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((r = delete_loopback(m->path)) >= 0) {
|
||||
|
||||
if (r > 0 && changed)
|
||||
*changed = true;
|
||||
|
||||
mount_point_free(head, m);
|
||||
} else {
|
||||
log_warning("Could not delete loopback %s: %m", m->path);
|
||||
n_failed++;
|
||||
}
|
||||
}
|
||||
|
||||
return n_failed;
|
||||
}
|
||||
|
||||
static int dm_points_list_detach(MountPoint **head, bool *changed) {
|
||||
MountPoint *m, *n;
|
||||
int n_failed = 0, k;
|
||||
struct stat root_st;
|
||||
|
||||
assert(head);
|
||||
|
||||
k = lstat("/", &root_st);
|
||||
|
||||
LIST_FOREACH_SAFE(mount_point, m, n, *head) {
|
||||
int r;
|
||||
|
||||
if (k >= 0 &&
|
||||
major(root_st.st_dev) != 0 &&
|
||||
root_st.st_dev == m->devnum) {
|
||||
n_failed ++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((r = delete_dm(m->devnum)) >= 0) {
|
||||
|
||||
if (r > 0 && changed)
|
||||
*changed = true;
|
||||
|
||||
mount_point_free(head, m);
|
||||
} else {
|
||||
log_warning("Could not delete dm %s: %m", m->path);
|
||||
n_failed++;
|
||||
}
|
||||
}
|
||||
|
||||
return n_failed;
|
||||
}
|
||||
|
||||
int umount_all(bool *changed) {
|
||||
int r;
|
||||
bool umount_changed;
|
||||
|
||||
LIST_HEAD(MountPoint, mp_list_head);
|
||||
|
||||
LIST_HEAD_INIT(MountPoint, mp_list_head);
|
||||
|
||||
r = mount_points_list_get(&mp_list_head);
|
||||
if (r < 0)
|
||||
goto end;
|
||||
|
||||
/* retry umount, until nothing can be umounted anymore */
|
||||
do {
|
||||
umount_changed = false;
|
||||
|
||||
mount_points_list_umount(&mp_list_head, &umount_changed, false);
|
||||
if (umount_changed)
|
||||
*changed = true;
|
||||
|
||||
} while (umount_changed);
|
||||
|
||||
/* umount one more time with logging enabled */
|
||||
r = mount_points_list_umount(&mp_list_head, &umount_changed, true);
|
||||
if (r <= 0)
|
||||
goto end;
|
||||
|
||||
r = mount_points_list_remount_read_only(&mp_list_head, changed);
|
||||
|
||||
end:
|
||||
mount_points_list_free(&mp_list_head);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int swapoff_all(bool *changed) {
|
||||
int r;
|
||||
LIST_HEAD(MountPoint, swap_list_head);
|
||||
|
||||
LIST_HEAD_INIT(MountPoint, swap_list_head);
|
||||
|
||||
r = swap_list_get(&swap_list_head);
|
||||
if (r < 0)
|
||||
goto end;
|
||||
|
||||
r = swap_points_list_off(&swap_list_head, changed);
|
||||
|
||||
end:
|
||||
mount_points_list_free(&swap_list_head);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int loopback_detach_all(bool *changed) {
|
||||
int r;
|
||||
LIST_HEAD(MountPoint, loopback_list_head);
|
||||
|
||||
LIST_HEAD_INIT(MountPoint, loopback_list_head);
|
||||
|
||||
r = loopback_list_get(&loopback_list_head);
|
||||
if (r < 0)
|
||||
goto end;
|
||||
|
||||
r = loopback_points_list_detach(&loopback_list_head, changed);
|
||||
|
||||
end:
|
||||
mount_points_list_free(&loopback_list_head);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int dm_detach_all(bool *changed) {
|
||||
int r;
|
||||
LIST_HEAD(MountPoint, dm_list_head);
|
||||
|
||||
LIST_HEAD_INIT(MountPoint, dm_list_head);
|
||||
|
||||
r = dm_list_get(&dm_list_head);
|
||||
if (r < 0)
|
||||
goto end;
|
||||
|
||||
r = dm_points_list_detach(&dm_list_head, changed);
|
||||
|
||||
end:
|
||||
mount_points_list_free(&dm_list_head);
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef fooumounthfoo
|
||||
#define fooumounthfoo
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 ProFUSION embedded systems
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
int umount_all(bool *changed);
|
||||
|
||||
int swapoff_all(bool *changed);
|
||||
|
||||
int loopback_detach_all(bool *changed);
|
||||
|
||||
int dm_detach_all(bool *changed);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,448 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "unit-name.h"
|
||||
|
||||
#define VALID_CHARS \
|
||||
"0123456789" \
|
||||
"abcdefghijklmnopqrstuvwxyz" \
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
|
||||
":-_.\\"
|
||||
|
||||
bool unit_name_is_valid_no_type(const char *n, bool template_ok) {
|
||||
const char *e, *i, *at;
|
||||
|
||||
/* Valid formats:
|
||||
*
|
||||
* string@instance.suffix
|
||||
* string.suffix
|
||||
*/
|
||||
|
||||
assert(n);
|
||||
|
||||
if (strlen(n) >= UNIT_NAME_MAX)
|
||||
return false;
|
||||
|
||||
e = strrchr(n, '.');
|
||||
if (!e || e == n)
|
||||
return false;
|
||||
|
||||
for (i = n, at = NULL; i < e; i++) {
|
||||
|
||||
if (*i == '@' && !at)
|
||||
at = i;
|
||||
|
||||
if (!strchr("@" VALID_CHARS, *i))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (at) {
|
||||
if (at == n)
|
||||
return false;
|
||||
|
||||
if (!template_ok && at+1 == e)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool unit_instance_is_valid(const char *i) {
|
||||
assert(i);
|
||||
|
||||
/* The max length depends on the length of the string, so we
|
||||
* don't really check this here. */
|
||||
|
||||
if (i[0] == 0)
|
||||
return false;
|
||||
|
||||
/* We allow additional @ in the instance string, we do not
|
||||
* allow them in the prefix! */
|
||||
|
||||
for (; *i; i++)
|
||||
if (!strchr("@" VALID_CHARS, *i))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool unit_prefix_is_valid(const char *p) {
|
||||
|
||||
/* We don't allow additional @ in the instance string */
|
||||
|
||||
if (p[0] == 0)
|
||||
return false;
|
||||
|
||||
for (; *p; p++)
|
||||
if (!strchr(VALID_CHARS, *p))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int unit_name_to_instance(const char *n, char **instance) {
|
||||
const char *p, *d;
|
||||
char *i;
|
||||
|
||||
assert(n);
|
||||
assert(instance);
|
||||
|
||||
/* Everything past the first @ and before the last . is the instance */
|
||||
if (!(p = strchr(n, '@'))) {
|
||||
*instance = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert_se(d = strrchr(n, '.'));
|
||||
assert(p < d);
|
||||
|
||||
if (!(i = strndup(p+1, d-p-1)))
|
||||
return -ENOMEM;
|
||||
|
||||
*instance = i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *unit_name_to_prefix_and_instance(const char *n) {
|
||||
const char *d;
|
||||
|
||||
assert(n);
|
||||
|
||||
assert_se(d = strrchr(n, '.'));
|
||||
|
||||
return strndup(n, d - n);
|
||||
}
|
||||
|
||||
char *unit_name_to_prefix(const char *n) {
|
||||
const char *p;
|
||||
|
||||
if ((p = strchr(n, '@')))
|
||||
return strndup(n, p - n);
|
||||
|
||||
return unit_name_to_prefix_and_instance(n);
|
||||
}
|
||||
|
||||
char *unit_name_change_suffix(const char *n, const char *suffix) {
|
||||
char *e, *r;
|
||||
size_t a, b;
|
||||
|
||||
assert(n);
|
||||
assert(unit_name_is_valid_no_type(n, true));
|
||||
assert(suffix);
|
||||
|
||||
assert_se(e = strrchr(n, '.'));
|
||||
a = e - n;
|
||||
b = strlen(suffix);
|
||||
|
||||
if (!(r = new(char, a + b + 1)))
|
||||
return NULL;
|
||||
|
||||
memcpy(r, n, a);
|
||||
memcpy(r+a, suffix, b+1);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
char *unit_name_build(const char *prefix, const char *instance, const char *suffix) {
|
||||
assert(prefix);
|
||||
assert(unit_prefix_is_valid(prefix));
|
||||
assert(!instance || unit_instance_is_valid(instance));
|
||||
assert(suffix);
|
||||
|
||||
if (!instance)
|
||||
return strappend(prefix, suffix);
|
||||
|
||||
return join(prefix, "@", instance, suffix, NULL);
|
||||
}
|
||||
|
||||
static char* do_escape(const char *f, char *t) {
|
||||
assert(f);
|
||||
assert(t);
|
||||
|
||||
for (; *f; f++) {
|
||||
if (*f == '/')
|
||||
*(t++) = '-';
|
||||
else if (*f == '-' || *f == '\\' || !strchr(VALID_CHARS, *f)) {
|
||||
*(t++) = '\\';
|
||||
*(t++) = 'x';
|
||||
*(t++) = hexchar(*f >> 4);
|
||||
*(t++) = hexchar(*f);
|
||||
} else
|
||||
*(t++) = *f;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
char *unit_name_build_escape(const char *prefix, const char *instance, const char *suffix) {
|
||||
char *r, *t;
|
||||
size_t a, b, c;
|
||||
|
||||
assert(prefix);
|
||||
assert(suffix);
|
||||
|
||||
/* Takes a arbitrary string for prefix and instance plus a
|
||||
* suffix and makes a nice string suitable as unit name of it,
|
||||
* escaping all weird chars on the way.
|
||||
*
|
||||
* / becomes ., and all chars not allowed in a unit name get
|
||||
* escaped as \xFF, including \ and ., of course. This
|
||||
* escaping is hence reversible.
|
||||
*
|
||||
* This is primarily useful to make nice unit names from
|
||||
* strings, but is actually useful for any kind of string.
|
||||
*/
|
||||
|
||||
a = strlen(prefix);
|
||||
c = strlen(suffix);
|
||||
|
||||
if (instance) {
|
||||
b = strlen(instance);
|
||||
|
||||
if (!(r = new(char, a*4 + 1 + b*4 + c + 1)))
|
||||
return NULL;
|
||||
|
||||
t = do_escape(prefix, r);
|
||||
*(t++) = '@';
|
||||
t = do_escape(instance, t);
|
||||
} else {
|
||||
|
||||
if (!(r = new(char, a*4 + c + 1)))
|
||||
return NULL;
|
||||
|
||||
t = do_escape(prefix, r);
|
||||
}
|
||||
|
||||
strcpy(t, suffix);
|
||||
return r;
|
||||
}
|
||||
|
||||
char *unit_name_escape(const char *f) {
|
||||
char *r, *t;
|
||||
|
||||
if (!(r = new(char, strlen(f)*4+1)))
|
||||
return NULL;
|
||||
|
||||
t = do_escape(f, r);
|
||||
*t = 0;
|
||||
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
char *unit_name_unescape(const char *f) {
|
||||
char *r, *t;
|
||||
|
||||
assert(f);
|
||||
|
||||
if (!(r = strdup(f)))
|
||||
return NULL;
|
||||
|
||||
for (t = r; *f; f++) {
|
||||
if (*f == '-')
|
||||
*(t++) = '/';
|
||||
else if (*f == '\\') {
|
||||
int a, b;
|
||||
|
||||
if (f[1] != 'x' ||
|
||||
(a = unhexchar(f[2])) < 0 ||
|
||||
(b = unhexchar(f[3])) < 0) {
|
||||
/* Invalid escape code, let's take it literal then */
|
||||
*(t++) = '\\';
|
||||
} else {
|
||||
*(t++) = (char) ((a << 4) | b);
|
||||
f += 3;
|
||||
}
|
||||
} else
|
||||
*(t++) = *f;
|
||||
}
|
||||
|
||||
*t = 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
bool unit_name_is_template(const char *n) {
|
||||
const char *p;
|
||||
|
||||
assert(n);
|
||||
|
||||
if (!(p = strchr(n, '@')))
|
||||
return false;
|
||||
|
||||
return p[1] == '.';
|
||||
}
|
||||
|
||||
char *unit_name_replace_instance(const char *f, const char *i) {
|
||||
const char *p, *e;
|
||||
char *r, *k;
|
||||
size_t a;
|
||||
|
||||
assert(f);
|
||||
|
||||
p = strchr(f, '@');
|
||||
assert_se(e = strrchr(f, '.'));
|
||||
|
||||
a = p - f;
|
||||
|
||||
if (p) {
|
||||
size_t b;
|
||||
|
||||
b = strlen(i);
|
||||
|
||||
if (!(r = new(char, a + 1 + b + strlen(e) + 1)))
|
||||
return NULL;
|
||||
|
||||
k = mempcpy(r, f, a + 1);
|
||||
k = mempcpy(k, i, b);
|
||||
} else {
|
||||
|
||||
if (!(r = new(char, a + strlen(e) + 1)))
|
||||
return NULL;
|
||||
|
||||
k = mempcpy(r, f, a);
|
||||
}
|
||||
|
||||
strcpy(k, e);
|
||||
return r;
|
||||
}
|
||||
|
||||
char *unit_name_template(const char *f) {
|
||||
const char *p, *e;
|
||||
char *r;
|
||||
size_t a;
|
||||
|
||||
if (!(p = strchr(f, '@')))
|
||||
return strdup(f);
|
||||
|
||||
assert_se(e = strrchr(f, '.'));
|
||||
a = p - f + 1;
|
||||
|
||||
if (!(r = new(char, a + strlen(e) + 1)))
|
||||
return NULL;
|
||||
|
||||
strcpy(mempcpy(r, f, a), e);
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
char *unit_name_from_path(const char *path, const char *suffix) {
|
||||
char *p, *r;
|
||||
|
||||
assert(path);
|
||||
assert(suffix);
|
||||
|
||||
if (!(p = strdup(path)))
|
||||
return NULL;
|
||||
|
||||
path_kill_slashes(p);
|
||||
|
||||
path = p[0] == '/' ? p + 1 : p;
|
||||
|
||||
if (path[0] == 0) {
|
||||
free(p);
|
||||
return strappend("-", suffix);
|
||||
}
|
||||
|
||||
r = unit_name_build_escape(path, NULL, suffix);
|
||||
free(p);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
char *unit_name_from_path_instance(const char *prefix, const char *path, const char *suffix) {
|
||||
char *p, *r;
|
||||
|
||||
assert(path);
|
||||
assert(suffix);
|
||||
|
||||
if (!(p = strdup(path)))
|
||||
return NULL;
|
||||
|
||||
path_kill_slashes(p);
|
||||
|
||||
path = p[0] == '/' ? p + 1 : p;
|
||||
|
||||
if (path[0] == 0) {
|
||||
free(p);
|
||||
return unit_name_build_escape(prefix, "-", suffix);
|
||||
}
|
||||
|
||||
r = unit_name_build_escape(prefix, path, suffix);
|
||||
free(p);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
char *unit_name_to_path(const char *name) {
|
||||
char *w, *e;
|
||||
|
||||
assert(name);
|
||||
|
||||
if (!(w = unit_name_to_prefix(name)))
|
||||
return NULL;
|
||||
|
||||
e = unit_name_unescape(w);
|
||||
free(w);
|
||||
|
||||
if (!e)
|
||||
return NULL;
|
||||
|
||||
if (e[0] != '/') {
|
||||
w = strappend("/", e);
|
||||
free(e);
|
||||
|
||||
if (!w)
|
||||
return NULL;
|
||||
|
||||
e = w;
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
char *unit_name_path_unescape(const char *f) {
|
||||
char *e;
|
||||
|
||||
assert(f);
|
||||
|
||||
if (!(e = unit_name_unescape(f)))
|
||||
return NULL;
|
||||
|
||||
if (e[0] != '/') {
|
||||
char *w;
|
||||
|
||||
w = strappend("/", e);
|
||||
free(e);
|
||||
|
||||
if (!w)
|
||||
return NULL;
|
||||
|
||||
e = w;
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef foounitnamehfoo
|
||||
#define foounitnamehfoo
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define UNIT_NAME_MAX 256
|
||||
|
||||
int unit_name_to_instance(const char *n, char **instance);
|
||||
char* unit_name_to_prefix(const char *n);
|
||||
char* unit_name_to_prefix_and_instance(const char *n);
|
||||
|
||||
bool unit_name_is_valid_no_type(const char *n, bool template_ok);
|
||||
bool unit_prefix_is_valid(const char *p);
|
||||
bool unit_instance_is_valid(const char *i);
|
||||
|
||||
char *unit_name_change_suffix(const char *n, const char *suffix);
|
||||
|
||||
char *unit_name_build(const char *prefix, const char *instance, const char *suffix);
|
||||
char *unit_name_build_escape(const char *prefix, const char *instance, const char *suffix);
|
||||
|
||||
char *unit_name_escape(const char *f);
|
||||
char *unit_name_unescape(const char *f);
|
||||
|
||||
char *unit_name_path_unescape(const char *f);
|
||||
|
||||
bool unit_name_is_template(const char *n);
|
||||
|
||||
char *unit_name_replace_instance(const char *f, const char *i);
|
||||
|
||||
char *unit_name_template(const char *f);
|
||||
|
||||
char *unit_name_from_path(const char *path, const char *suffix);
|
||||
char *unit_name_from_path_instance(const char *prefix, const char *path, const char *suffix);
|
||||
char *unit_name_to_path(const char *name);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,430 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <utmpx.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/poll.h>
|
||||
|
||||
#include "macro.h"
|
||||
#include "utmp-wtmp.h"
|
||||
|
||||
int utmp_get_runlevel(int *runlevel, int *previous) {
|
||||
struct utmpx lookup, *found;
|
||||
int r;
|
||||
const char *e;
|
||||
|
||||
assert(runlevel);
|
||||
|
||||
/* If these values are set in the environment this takes
|
||||
* precedence. Presumably, sysvinit does this to work around a
|
||||
* race condition that would otherwise exist where we'd always
|
||||
* go to disk and hence might read runlevel data that might be
|
||||
* very new and does not apply to the current script being
|
||||
* executed. */
|
||||
|
||||
if ((e = getenv("RUNLEVEL")) && e[0] > 0) {
|
||||
*runlevel = e[0];
|
||||
|
||||
if (previous) {
|
||||
/* $PREVLEVEL seems to be an Upstart thing */
|
||||
|
||||
if ((e = getenv("PREVLEVEL")) && e[0] > 0)
|
||||
*previous = e[0];
|
||||
else
|
||||
*previous = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (utmpxname(_PATH_UTMPX) < 0)
|
||||
return -errno;
|
||||
|
||||
setutxent();
|
||||
|
||||
zero(lookup);
|
||||
lookup.ut_type = RUN_LVL;
|
||||
|
||||
if (!(found = getutxid(&lookup)))
|
||||
r = -errno;
|
||||
else {
|
||||
int a, b;
|
||||
|
||||
a = found->ut_pid & 0xFF;
|
||||
b = (found->ut_pid >> 8) & 0xFF;
|
||||
|
||||
if (a < 0 || b < 0)
|
||||
r = -EIO;
|
||||
else {
|
||||
*runlevel = a;
|
||||
|
||||
if (previous)
|
||||
*previous = b;
|
||||
r = 0;
|
||||
}
|
||||
}
|
||||
|
||||
endutxent();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void init_timestamp(struct utmpx *store, usec_t t) {
|
||||
assert(store);
|
||||
|
||||
zero(*store);
|
||||
|
||||
if (t <= 0)
|
||||
t = now(CLOCK_REALTIME);
|
||||
|
||||
store->ut_tv.tv_sec = t / USEC_PER_SEC;
|
||||
store->ut_tv.tv_usec = t % USEC_PER_SEC;
|
||||
}
|
||||
|
||||
static void init_entry(struct utmpx *store, usec_t t) {
|
||||
struct utsname uts;
|
||||
|
||||
assert(store);
|
||||
|
||||
init_timestamp(store, t);
|
||||
|
||||
zero(uts);
|
||||
|
||||
if (uname(&uts) >= 0)
|
||||
strncpy(store->ut_host, uts.release, sizeof(store->ut_host));
|
||||
|
||||
strncpy(store->ut_line, "~", sizeof(store->ut_line)); /* or ~~ ? */
|
||||
strncpy(store->ut_id, "~~", sizeof(store->ut_id));
|
||||
}
|
||||
|
||||
static int write_entry_utmp(const struct utmpx *store) {
|
||||
int r;
|
||||
|
||||
assert(store);
|
||||
|
||||
/* utmp is similar to wtmp, but there is only one entry for
|
||||
* each entry type resp. user; i.e. basically a key/value
|
||||
* table. */
|
||||
|
||||
if (utmpxname(_PATH_UTMPX) < 0)
|
||||
return -errno;
|
||||
|
||||
setutxent();
|
||||
|
||||
if (!pututxline(store))
|
||||
r = -errno;
|
||||
else
|
||||
r = 0;
|
||||
|
||||
endutxent();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int write_entry_wtmp(const struct utmpx *store) {
|
||||
assert(store);
|
||||
|
||||
/* wtmp is a simple append-only file where each entry is
|
||||
simply appended to * the end; i.e. basically a log. */
|
||||
|
||||
errno = 0;
|
||||
updwtmpx(_PATH_WTMPX, store);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
static int write_utmp_wtmp(const struct utmpx *store_utmp, const struct utmpx *store_wtmp) {
|
||||
int r, s;
|
||||
|
||||
r = write_entry_utmp(store_utmp);
|
||||
s = write_entry_wtmp(store_wtmp);
|
||||
|
||||
if (r >= 0)
|
||||
r = s;
|
||||
|
||||
/* If utmp/wtmp have been disabled, that's a good thing, hence
|
||||
* ignore the errors */
|
||||
if (r == -ENOENT)
|
||||
r = 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int write_entry_both(const struct utmpx *store) {
|
||||
return write_utmp_wtmp(store, store);
|
||||
}
|
||||
|
||||
int utmp_put_shutdown(void) {
|
||||
struct utmpx store;
|
||||
|
||||
init_entry(&store, 0);
|
||||
|
||||
store.ut_type = RUN_LVL;
|
||||
strncpy(store.ut_user, "shutdown", sizeof(store.ut_user));
|
||||
|
||||
return write_entry_both(&store);
|
||||
}
|
||||
|
||||
int utmp_put_reboot(usec_t t) {
|
||||
struct utmpx store;
|
||||
|
||||
init_entry(&store, t);
|
||||
|
||||
store.ut_type = BOOT_TIME;
|
||||
strncpy(store.ut_user, "reboot", sizeof(store.ut_user));
|
||||
|
||||
return write_entry_both(&store);
|
||||
}
|
||||
|
||||
static const char *sanitize_id(const char *id) {
|
||||
size_t l;
|
||||
|
||||
assert(id);
|
||||
l = strlen(id);
|
||||
|
||||
if (l <= sizeof(((struct utmpx*) NULL)->ut_id))
|
||||
return id;
|
||||
|
||||
return id + l - sizeof(((struct utmpx*) NULL)->ut_id);
|
||||
}
|
||||
|
||||
int utmp_put_init_process(const char *id, pid_t pid, pid_t sid, const char *line) {
|
||||
struct utmpx store;
|
||||
|
||||
assert(id);
|
||||
|
||||
init_timestamp(&store, 0);
|
||||
|
||||
store.ut_type = INIT_PROCESS;
|
||||
store.ut_pid = pid;
|
||||
store.ut_session = sid;
|
||||
|
||||
strncpy(store.ut_id, sanitize_id(id), sizeof(store.ut_id));
|
||||
|
||||
if (line)
|
||||
strncpy(store.ut_line, file_name_from_path(line), sizeof(store.ut_line));
|
||||
|
||||
return write_entry_both(&store);
|
||||
}
|
||||
|
||||
int utmp_put_dead_process(const char *id, pid_t pid, int code, int status) {
|
||||
struct utmpx lookup, store, store_wtmp, *found;
|
||||
|
||||
assert(id);
|
||||
|
||||
setutxent();
|
||||
|
||||
zero(lookup);
|
||||
lookup.ut_type = INIT_PROCESS; /* looks for DEAD_PROCESS, LOGIN_PROCESS, USER_PROCESS, too */
|
||||
strncpy(lookup.ut_id, sanitize_id(id), sizeof(lookup.ut_id));
|
||||
|
||||
if (!(found = getutxid(&lookup)))
|
||||
return 0;
|
||||
|
||||
if (found->ut_pid != pid)
|
||||
return 0;
|
||||
|
||||
memcpy(&store, found, sizeof(store));
|
||||
store.ut_type = DEAD_PROCESS;
|
||||
store.ut_exit.e_termination = code;
|
||||
store.ut_exit.e_exit = status;
|
||||
|
||||
zero(store.ut_user);
|
||||
zero(store.ut_host);
|
||||
zero(store.ut_tv);
|
||||
|
||||
memcpy(&store_wtmp, &store, sizeof(store_wtmp));
|
||||
/* wtmp wants the current time */
|
||||
init_timestamp(&store_wtmp, 0);
|
||||
|
||||
return write_utmp_wtmp(&store, &store_wtmp);
|
||||
}
|
||||
|
||||
|
||||
int utmp_put_runlevel(int runlevel, int previous) {
|
||||
struct utmpx store;
|
||||
int r;
|
||||
|
||||
assert(runlevel > 0);
|
||||
|
||||
if (previous <= 0) {
|
||||
/* Find the old runlevel automatically */
|
||||
|
||||
if ((r = utmp_get_runlevel(&previous, NULL)) < 0) {
|
||||
if (r != -ESRCH)
|
||||
return r;
|
||||
|
||||
previous = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (previous == runlevel)
|
||||
return 0;
|
||||
|
||||
init_entry(&store, 0);
|
||||
|
||||
store.ut_type = RUN_LVL;
|
||||
store.ut_pid = (runlevel & 0xFF) | ((previous & 0xFF) << 8);
|
||||
strncpy(store.ut_user, "runlevel", sizeof(store.ut_user));
|
||||
|
||||
return write_entry_both(&store);
|
||||
}
|
||||
|
||||
#define TIMEOUT_MSEC 50
|
||||
|
||||
static int write_to_terminal(const char *tty, const char *message) {
|
||||
int fd, r;
|
||||
const char *p;
|
||||
size_t left;
|
||||
usec_t end;
|
||||
|
||||
assert(tty);
|
||||
assert(message);
|
||||
|
||||
if ((fd = open(tty, O_WRONLY|O_NDELAY|O_NOCTTY|O_CLOEXEC)) < 0)
|
||||
return -errno;
|
||||
|
||||
if (!isatty(fd)) {
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
p = message;
|
||||
left = strlen(message);
|
||||
|
||||
end = now(CLOCK_MONOTONIC) + TIMEOUT_MSEC*USEC_PER_MSEC;
|
||||
|
||||
while (left > 0) {
|
||||
ssize_t n;
|
||||
struct pollfd pollfd;
|
||||
usec_t t;
|
||||
int k;
|
||||
|
||||
t = now(CLOCK_MONOTONIC);
|
||||
|
||||
if (t >= end) {
|
||||
r = -ETIME;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
zero(pollfd);
|
||||
pollfd.fd = fd;
|
||||
pollfd.events = POLLOUT;
|
||||
|
||||
if ((k = poll(&pollfd, 1, (end - t) / USEC_PER_MSEC)) < 0)
|
||||
return -errno;
|
||||
|
||||
if (k <= 0) {
|
||||
r = -ETIME;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if ((n = write(fd, p, left)) < 0) {
|
||||
|
||||
if (errno == EAGAIN)
|
||||
continue;
|
||||
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
assert((size_t) n <= left);
|
||||
|
||||
p += n;
|
||||
left -= n;
|
||||
}
|
||||
|
||||
r = 0;
|
||||
|
||||
finish:
|
||||
close_nointr_nofail(fd);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int utmp_wall(const char *message, bool (*match_tty)(const char *tty)) {
|
||||
struct utmpx *u;
|
||||
char date[FORMAT_TIMESTAMP_MAX];
|
||||
char *text = NULL, *hn = NULL, *un = NULL, *tty = NULL;
|
||||
int r;
|
||||
|
||||
if (!(hn = gethostname_malloc()) ||
|
||||
!(un = getlogname_malloc())) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
getttyname_harder(STDIN_FILENO, &tty);
|
||||
|
||||
if (asprintf(&text,
|
||||
"\a\r\n"
|
||||
"Broadcast message from %s@%s%s%s (%s):\r\n\r\n"
|
||||
"%s\r\n\r\n",
|
||||
un, hn,
|
||||
tty ? " on " : "", strempty(tty),
|
||||
format_timestamp(date, sizeof(date), now(CLOCK_REALTIME)),
|
||||
message) < 0) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
setutxent();
|
||||
|
||||
r = 0;
|
||||
|
||||
while ((u = getutxent())) {
|
||||
int q;
|
||||
const char *path;
|
||||
char *buf = NULL;
|
||||
|
||||
if (u->ut_type != USER_PROCESS || u->ut_user[0] == 0)
|
||||
continue;
|
||||
|
||||
if (path_startswith(u->ut_line, "/dev/"))
|
||||
path = u->ut_line;
|
||||
else {
|
||||
if (asprintf(&buf, "/dev/%s", u->ut_line) < 0) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
path = buf;
|
||||
}
|
||||
|
||||
if (!match_tty || match_tty(path))
|
||||
if ((q = write_to_terminal(path, text)) < 0)
|
||||
r = q;
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
finish:
|
||||
free(hn);
|
||||
free(un);
|
||||
free(tty);
|
||||
free(text);
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef fooutmpwtmphfoo
|
||||
#define fooutmpwtmphfoo
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include "util.h"
|
||||
|
||||
int utmp_get_runlevel(int *runlevel, int *previous);
|
||||
|
||||
int utmp_put_shutdown(void);
|
||||
int utmp_put_reboot(usec_t timestamp);
|
||||
int utmp_put_runlevel(int runlevel, int previous);
|
||||
|
||||
int utmp_put_dead_process(const char *id, pid_t pid, int code, int status);
|
||||
int utmp_put_init_process(const char *id, pid_t pid, pid_t sid, const char *line);
|
||||
|
||||
int utmp_wall(const char *message, bool (*match_tty)(const char *tty));
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,169 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2012 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/watchdog.h>
|
||||
|
||||
#include "watchdog.h"
|
||||
#include "log.h"
|
||||
|
||||
static int watchdog_fd = -1;
|
||||
static usec_t watchdog_timeout = (usec_t) -1;
|
||||
|
||||
static int update_timeout(void) {
|
||||
int r;
|
||||
|
||||
if (watchdog_fd < 0)
|
||||
return 0;
|
||||
|
||||
if (watchdog_timeout == (usec_t) -1)
|
||||
return 0;
|
||||
else if (watchdog_timeout == 0) {
|
||||
int flags;
|
||||
|
||||
flags = WDIOS_DISABLECARD;
|
||||
r = ioctl(watchdog_fd, WDIOC_SETOPTIONS, &flags);
|
||||
if (r < 0) {
|
||||
log_warning("Failed to disable hardware watchdog: %m");
|
||||
return -errno;
|
||||
}
|
||||
} else {
|
||||
int sec, flags;
|
||||
char buf[FORMAT_TIMESPAN_MAX];
|
||||
|
||||
sec = (int) ((watchdog_timeout + USEC_PER_SEC - 1) / USEC_PER_SEC);
|
||||
r = ioctl(watchdog_fd, WDIOC_SETTIMEOUT, &sec);
|
||||
if (r < 0) {
|
||||
log_warning("Failed to set timeout to %is: %m", sec);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
watchdog_timeout = (usec_t) sec * USEC_PER_SEC;
|
||||
log_info("Set hardware watchdog to %s.", format_timespan(buf, sizeof(buf), watchdog_timeout));
|
||||
|
||||
flags = WDIOS_ENABLECARD;
|
||||
r = ioctl(watchdog_fd, WDIOC_SETOPTIONS, &flags);
|
||||
if (r < 0) {
|
||||
log_warning("Failed to enable hardware watchdog: %m");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
r = ioctl(watchdog_fd, WDIOC_KEEPALIVE, 0);
|
||||
if (r < 0) {
|
||||
log_warning("Failed to ping hardware watchdog: %m");
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int open_watchdog(void) {
|
||||
struct watchdog_info ident;
|
||||
|
||||
if (watchdog_fd >= 0)
|
||||
return 0;
|
||||
|
||||
watchdog_fd = open("/dev/watchdog", O_WRONLY|O_CLOEXEC);
|
||||
if (watchdog_fd < 0)
|
||||
return -errno;
|
||||
|
||||
if (ioctl(watchdog_fd, WDIOC_GETSUPPORT, &ident) >= 0)
|
||||
log_info("Hardware watchdog '%s', version %x",
|
||||
ident.identity,
|
||||
ident.firmware_version);
|
||||
|
||||
return update_timeout();
|
||||
}
|
||||
|
||||
int watchdog_set_timeout(usec_t *usec) {
|
||||
int r;
|
||||
|
||||
watchdog_timeout = *usec;
|
||||
|
||||
/* If we didn't open the watchdog yet and didn't get any
|
||||
* explicit timeout value set, don't do anything */
|
||||
if (watchdog_fd < 0 && watchdog_timeout == (usec_t) -1)
|
||||
return 0;
|
||||
|
||||
if (watchdog_fd < 0)
|
||||
r = open_watchdog();
|
||||
else
|
||||
r = update_timeout();
|
||||
|
||||
*usec = watchdog_timeout;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int watchdog_ping(void) {
|
||||
int r;
|
||||
|
||||
if (watchdog_fd < 0) {
|
||||
r = open_watchdog();
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = ioctl(watchdog_fd, WDIOC_KEEPALIVE, 0);
|
||||
if (r < 0) {
|
||||
log_warning("Failed to ping hardware watchdog: %m");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void watchdog_close(bool disarm) {
|
||||
int r;
|
||||
|
||||
if (watchdog_fd < 0)
|
||||
return;
|
||||
|
||||
if (disarm) {
|
||||
int flags;
|
||||
|
||||
/* Explicitly disarm it */
|
||||
flags = WDIOS_DISABLECARD;
|
||||
r = ioctl(watchdog_fd, WDIOC_SETOPTIONS, &flags);
|
||||
if (r < 0)
|
||||
log_warning("Failed to disable hardware watchdog: %m");
|
||||
|
||||
/* To be sure, use magic close logic, too */
|
||||
for (;;) {
|
||||
static const char v = 'V';
|
||||
|
||||
if (write(watchdog_fd, &v, 1) > 0)
|
||||
break;
|
||||
|
||||
if (errno != EINTR) {
|
||||
log_error("Failed to disarm watchdog timer: %m");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
close_nointr_nofail(watchdog_fd);
|
||||
watchdog_fd = -1;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef foowatchdoghfoo
|
||||
#define foowatchdoghfoo
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2012 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include "util.h"
|
||||
|
||||
int watchdog_set_timeout(usec_t *usec);
|
||||
int watchdog_ping(void);
|
||||
void watchdog_close(bool disarm);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user