chiark / gitweb /
service: add StartLimitInterval/StartLimitBurst/StartLimitAction
[elogind.git] / src / systemctl.c
index 10e3991745a59878ab10d48fcdc5359f55458b63..ab6d126a26deca84c75b72861c310ebb591a0fd5 100644 (file)
@@ -35,6 +35,8 @@
 #include <sys/prctl.h>
 #include <dbus/dbus.h>
 
+#include <systemd/sd-daemon.h>
+
 #include "log.h"
 #include "util.h"
 #include "macro.h"
@@ -49,7 +51,6 @@
 #include "list.h"
 #include "path-lookup.h"
 #include "conf-parser.h"
-#include "sd-daemon.h"
 #include "shutdownd.h"
 #include "exit-status.h"
 #include "bus-errors.h"
@@ -118,6 +119,9 @@ static enum transport {
         TRANSPORT_POLKIT
 } arg_transport = TRANSPORT_NORMAL;
 static const char *arg_host = NULL;
+static bool arg_follow = false;
+static unsigned arg_lines = 10;
+static OutputMode arg_output = OUTPUT_SHORT;
 
 static bool private_bus = false;
 
@@ -162,12 +166,12 @@ static void agent_open_if_enabled(void) {
         agent_open();
 }
 
-static const char *ansi_highlight(bool b) {
+static const char *ansi_highlight_red(bool b) {
 
         if (!on_tty())
                 return "";
 
-        return b ? ANSI_HIGHLIGHT_ON : ANSI_HIGHLIGHT_OFF;
+        return b ? ANSI_HIGHLIGHT_RED_ON : ANSI_HIGHLIGHT_OFF;
 }
 
 static const char *ansi_highlight_green(bool b) {
@@ -379,14 +383,14 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
                 n_shown++;
 
                 if (streq(u->load_state, "error")) {
-                        on_loaded = ansi_highlight(true);
-                        off_loaded = ansi_highlight(false);
+                        on_loaded = ansi_highlight_red(true);
+                        off_loaded = ansi_highlight_red(false);
                 } else
                         on_loaded = off_loaded = "";
 
                 if (streq(u->active_state, "failed")) {
-                        on_active = ansi_highlight(true);
-                        off_active = ansi_highlight(false);
+                        on_active = ansi_highlight_red(true);
+                        off_active = ansi_highlight_red(false);
                 } else
                         on_active = off_active = "";
 
@@ -589,8 +593,8 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) {
                 if (u->state == UNIT_FILE_MASKED ||
                     u->state == UNIT_FILE_MASKED_RUNTIME ||
                     u->state == UNIT_FILE_DISABLED) {
-                        on  = ansi_highlight(true);
-                        off = ansi_highlight(false);
+                        on  = ansi_highlight_red(true);
+                        off = ansi_highlight_red(false);
                 } else if (u->state == UNIT_FILE_ENABLED) {
                         on  = ansi_highlight_green(true);
                         off = ansi_highlight_green(false);
@@ -1433,9 +1437,9 @@ static int wait_for_jobs(DBusConnection *bus, Set *s) {
                 else if (streq(d.result, "canceled"))
                         log_error("Job canceled.");
                 else if (streq(d.result, "dependency"))
-                        log_error("A dependency job failed. See system logs for details.");
+                        log_error("A dependency job failed. See system journal for details.");
                 else if (!streq(d.result, "done") && !streq(d.result, "skipped"))
-                        log_error("Job failed. See system logs and 'systemctl status' for details.");
+                        log_error("Job failed. See system journal and 'systemctl status' for details.");
         }
 
         if (streq_ptr(d.result, "timeout"))
@@ -1999,8 +2003,10 @@ typedef struct UnitStatusInfo {
         const char *default_control_group;
 
         const char *load_error;
+        const char *result;
 
         usec_t inactive_exit_timestamp;
+        usec_t inactive_exit_timestamp_monotonic;
         usec_t active_enter_timestamp;
         usec_t active_exit_timestamp;
         usec_t inactive_enter_timestamp;
@@ -2064,8 +2070,8 @@ static void print_status_info(UnitStatusInfo *i) {
                 printf("\t  Follow: unit currently follows state of %s\n", i->following);
 
         if (streq_ptr(i->load_state, "error")) {
-                on = ansi_highlight(true);
-                off = ansi_highlight(false);
+                on = ansi_highlight_red(true);
+                off = ansi_highlight_red(false);
         } else
                 on = off = "";
 
@@ -2081,8 +2087,8 @@ static void print_status_info(UnitStatusInfo *i) {
         ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
 
         if (streq_ptr(i->active_state, "failed")) {
-                on = ansi_highlight(true);
-                off = ansi_highlight(false);
+                on = ansi_highlight_red(true);
+                off = ansi_highlight_red(false);
         } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
                 on = ansi_highlight_green(true);
                 off = ansi_highlight_green(false);
@@ -2101,6 +2107,9 @@ static void print_status_info(UnitStatusInfo *i) {
                        strna(i->active_state),
                        off);
 
+        if (!isempty(i->result) && !streq(i->result, "success"))
+                printf(" (Result: %s)", i->result);
+
         timestamp = (streq_ptr(i->active_state, "active")      ||
                      streq_ptr(i->active_state, "reloading"))   ? i->active_enter_timestamp :
                     (streq_ptr(i->active_state, "inactive")    ||
@@ -2158,8 +2167,8 @@ static void print_status_info(UnitStatusInfo *i) {
                         good = is_clean_exit(p->code, p->status);
 
                 if (!good) {
-                        on = ansi_highlight(true);
-                        off = ansi_highlight(false);
+                        on = ansi_highlight_red(true);
+                        off = ansi_highlight_red(false);
                 } else
                         on = off = "";
 
@@ -2258,17 +2267,19 @@ static void print_status_info(UnitStatusInfo *i) {
                         else
                                 c = 0;
 
-                        show_cgroup_by_path(i->default_control_group, "\t\t  ", c);
+                        show_cgroup_by_path(i->default_control_group, "\t\t  ", c, false);
                 }
         }
 
-        if (i->id && arg_transport != TRANSPORT_SSH)
-                show_journal_by_service(i->id, OUTPUT_SHORT, NULL, 0, 0, 0, arg_all);
+        if (i->id && arg_transport != TRANSPORT_SSH) {
+                printf("\n");
+                show_journal_by_unit(i->id, arg_output, NULL, 0, i->inactive_exit_timestamp_monotonic, arg_lines, arg_all, arg_follow);
+        }
 
         if (i->need_daemon_reload)
                 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n",
-                       ansi_highlight(true),
-                       ansi_highlight(false),
+                       ansi_highlight_red(true),
+                       ansi_highlight_red(false),
                        arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
 }
 
@@ -2318,6 +2329,8 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn
                                 i->following = s;
                         else if (streq(name, "UnitFileState"))
                                 i->unit_file_state = s;
+                        else if (streq(name, "Result"))
+                                i->result = s;
                 }
 
                 break;
@@ -2389,6 +2402,8 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn
                         i->inactive_enter_timestamp = (usec_t) u;
                 else if (streq(name, "InactiveExitTimestamp"))
                         i->inactive_exit_timestamp = (usec_t) u;
+                else if (streq(name, "InactiveExitTimestampMonotonic"))
+                        i->inactive_exit_timestamp_monotonic = (usec_t) u;
                 else if (streq(name, "ActiveExitTimestamp"))
                         i->active_exit_timestamp = (usec_t) u;
                 else if (streq(name, "ConditionTimestamp"))
@@ -3647,12 +3662,15 @@ static int enable_unit(DBusConnection *bus, char **args) {
         int r;
         DBusError error;
 
-        dbus_error_init(&error);
-
         r = enable_sysv_units(args);
         if (r < 0)
                 return r;
 
+        if (!args[1])
+                return 0;
+
+        dbus_error_init(&error);
+
         if (!bus || avoid_bus()) {
                 if (streq(verb, "enable")) {
                         r = unit_file_enable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
@@ -3679,11 +3697,13 @@ static int enable_unit(DBusConnection *bus, char **args) {
                         goto finish;
                 }
 
-                for (i = 0; i < n_changes; i++) {
-                        if (changes[i].type == UNIT_FILE_SYMLINK)
-                                log_info("ln -s '%s' '%s'", changes[i].source, changes[i].path);
-                        else
-                                log_info("rm '%s'", changes[i].path);
+                if (!arg_quiet) {
+                        for (i = 0; i < n_changes; i++) {
+                                if (changes[i].type == UNIT_FILE_SYMLINK)
+                                        log_info("ln -s '%s' '%s'", changes[i].source, changes[i].path);
+                                else
+                                        log_info("rm '%s'", changes[i].path);
+                        }
                 }
 
         } else {
@@ -3799,10 +3819,12 @@ static int enable_unit(DBusConnection *bus, char **args) {
                                 goto finish;
                         }
 
-                        if (streq(type, "symlink"))
-                                log_info("ln -s '%s' '%s'", source, path);
-                        else
-                                log_info("rm '%s'", path);
+                        if (!arg_quiet) {
+                                if (streq(type, "symlink"))
+                                        log_info("ln -s '%s' '%s'", source, path);
+                                else
+                                        log_info("rm '%s'", path);
+                        }
 
                         dbus_message_iter_next(&sub);
                 }
@@ -3967,7 +3989,11 @@ static int systemctl_help(void) {
                "  -f --force          When enabling unit files, override existing symlinks\n"
                "                      When shutting down, execute action immediately\n"
                "     --root=PATH      Enable unit files in the specified root directory\n"
-               "     --runtime        Enable unit files only temporarily until next reboot\n\n"
+               "     --runtime        Enable unit files only temporarily until next reboot\n"
+               "  -n --lines=INTEGER  Journal entries to show\n"
+               "     --follow         Follow journal\n"
+               "  -o --output=STRING  Change journal output mode (short, short-monotonic,\n"
+               "                      verbose, export, json, cat)\n\n"
                "Unit Commands:\n"
                "  list-units                      List loaded units\n"
                "  start [NAME...]                 Start (activate) one or more units\n"
@@ -4118,7 +4144,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 ARG_KILL_WHO,
                 ARG_NO_ASK_PASSWORD,
                 ARG_FAILED,
-                ARG_RUNTIME
+                ARG_RUNTIME,
+                ARG_FOLLOW
         };
 
         static const struct option options[] = {
@@ -4151,6 +4178,9 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 { "host",      required_argument, NULL, 'H'           },
                 { "privileged",no_argument,       NULL, 'P'           },
                 { "runtime",   no_argument,       NULL, ARG_RUNTIME   },
+                { "lines",     required_argument, NULL, 'n'           },
+                { "follow",    no_argument,       NULL, ARG_FOLLOW    },
+                { "output",    required_argument, NULL, 'o'           },
                 { NULL,        0,                 NULL, 0             }
         };
 
@@ -4162,7 +4192,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
         /* Only when running as systemctl we ask for passwords */
         arg_ask_password = true;
 
-        while ((c = getopt_long(argc, argv, "ht:p:aqfs:H:P", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "ht:p:aqfs:H:Pn:o:", options, NULL)) >= 0) {
 
                 switch (c) {
 
@@ -4300,6 +4330,25 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         arg_runtime = true;
                         break;
 
+                case 'n':
+                        if (safe_atou(optarg, &arg_lines) < 0) {
+                                log_error("Failed to parse lines '%s'", optarg);
+                                return -EINVAL;
+                        }
+                        break;
+
+                case ARG_FOLLOW:
+                        arg_follow = true;
+                        break;
+
+                case 'o':
+                        arg_output = output_mode_from_string(optarg);
+                        if (arg_output < 0) {
+                                log_error("Unknown output '%s'.", optarg);
+                                return -EINVAL;
+                        }
+                        break;
+
                 case '?':
                         return -EINVAL;