Stephen Boston
Stephen Boston

Reputation: 1189

Output from systemctl start/restart/stop

I want to see output from my systemctl commands. For example:

systemctl restart systemd-networkd  

would display the output of

systemctl status systemd-networkd. 

I know that I could write a script that always puts the commands sequentially but I am hoping there is something like

systemctl --verbose restart ....

that didn't make it into the man page.

Upvotes: 34

Views: 40694

Answers (4)

lauhub
lauhub

Reputation: 920

I admit that this did really bother me, because from a user-experience POV, having no message to tell "hey, look at journalctl !" is not acceptable.

I wrote a dash script (should be POSIX compatible) that does this by a massive tweak: it searches for the parent shell process that ran systemctl command).

Finding the tty/pts of the calling shell

Here is the code that allows to do this:

has_parent_process(){
    local parent_to_search
    local ppid
    parent_to_search="${1:-}"
    if [ -z "${parent_to_search:-}" ]
    then
        echo "ERROR: need parent process pid as first arg" >&2
        return 5
    fi
    local pid
    pid="${2:-}"
    if [ -z "${pid:-}" ]
    then
        pid=$$
    fi
    if [ $parent_to_search = $pid ]
    then
        echo ${parent_to_search}
        return 0
    else if [ $pid > 1 ]
        then
            ppid=$(ps --pid ${pid} -o ppid= | xargs)
            if [ $ppid = $pid ]
            then
                echo "ERROR: pid=$pid is the same as ppid=$ppid" >&2
                echo -1
            else
                has_parent_process ${parent_to_search} ${ppid}
            fi
        else
            echo "NOT FOUND: ${parent_to_search}" >&2
            echo 1
        fi
    fi
    return 1
}

find_pid_user_of(){
    local used_file=$1
    local regex="$2"
    lsof ${used_file} | awk 'NR>1 && $1 ~ /'${regex}'/ && !($2 in a){a[$2]++; print $2}'
}

find_systemctl_pids(){
    ps -elf | grep 'systemctl' | grep -v grep | awk '{print $13}' | sort -u | while read term
    do
        if [ -z "${shell_pid:-}" ]
        then
            shell_pid=$(find_pid_user_of /dev/$term '.*sh$')
        fi
        if [ -z "${systemctl_pid:-}" ]
        then
            systemctl_pid=$(find_pid_user_of /dev/$term 'systemctl')
        fi
        echo ${shell_pid} ${systemctl_pid}
    done
}

process_and_parent=`find_systemctl_pids`

if has_parent_process ${process_and_parent}
then
    shell_process=$(echo ${process_and_parent} | awk '{print $1}')
    parent_term=`readlink /proc/${shell_process}/fd/2`
fi

# And here, if the magic is done
if [ -c "${parent_term}" ]
then
    # Redirects error output
    # to the shell's terminal
    exec 2>${parent_term}
fi

Assuming that the systemctl command was called from a shell process and that, the previous code searches for all systemctl processes and their associated TTY. It then looks for a systemctl that has a shell parent process (hoping there will not be several people to run the systemctl command at the same time, which is acceptable in my use case). In that case, it retrieves the terminal linked to the shell process.

How to print

One thing to add is that echo command did not work well for me. So to print my messages, I add to use printf and \n\r

printf "#######################\n\r" >&2
printf "# IMPORTANT WARNING ! #\n\r" >&2
printf "#######################\n\r" >&2

Upvotes: 1

marcosdsanchez
marcosdsanchez

Reputation: 2619

systemctl does not have a verbose option. If you want to see the output of the service you are running in real time, what you can do is to open another terminal and run:

sudo journalctl --unit=systemd-networkd.service -f

Journalctl documentation: https://www.freedesktop.org/software/systemd/man/journalctl.html

Upvotes: 4

reichhart
reichhart

Reputation: 889

Unfortunately systemctl does not provide a "verbose" option like most Unix commands do.

One solution is to increase SYSTEMD_LOG_LEVEL to debug (info is useless here) and then filter the output like e.g.:

$ SERVICES="smartmontools cron xxxxx"
$ SYSTEMD_LOG_LEVEL=debug systemctl restart $SERVICES 2>&1|egrep "Got result|Failed"
Failed to restart xxxxx.service: Unit xxxxx.service not found.
Got result done/Success for job cron.service
Got result done/Success for job smartmontools.service

You can also add a prefix like e.g.

$ SYSTEMD_LOG_LEVEL=debug systemctl restart $SERVICES 2>&1|egrep -i "Got result|Failed"|sed 's,^,restart: ,'
restart: Failed to restart xxxxx.service: Unit xxxxx.service not found.
restart: Got result done/Success for job cron.service
restart: Got result done/Success for job smartmontools.service

SYSTEMD_LOG_LEVEL might not be available on all systems.

Upvotes: 5

dGRAMOP
dGRAMOP

Reputation: 793

To my knowledge, there is no such thing. That being said, you can go ahead and "make you own":

We're going to edit out bashrc file to add this as a an alias command

echo "startstat(){ systemctl start \$*; systemctl status \$* }" >> ~/.bashrc

Note that this will only work for bash sessions and for the user you're running it for, so don't run this inside stuff that doesn't run bashrc before starting.

You can then start services and immediately get the status by running

startstat [arguments to pass to BOTH systemctl start AND systemctl status]

Sample usage:

startstat systemd-networkd 

If you want to wait a little bit before checking the status, you can always add a sleep between:

Just nano ~/.bashrc, scroll to the bottom (or if you added things, whichever line it's at), and just add sleep [seconds]; between systemctl start \$*; and systemctl status \$*;

If you want the status to be run after the start is finished, you can put a singular & sign with a space in front of it between the \$* and the ; to fork it off into background.

Upvotes: 5

Related Questions