2010-08-14 19:59:25 +02:00
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2010-06-15 02:51:55 +02:00
/***
This file is part of systemd .
Copyright 2010 Lennart Poettering
2013-11-07 05:49:04 +01:00
Copyright 2013 Marc - Antoine Perennou
2010-06-15 02:51:55 +02:00
systemd is free software ; you can redistribute it and / or modify it
2012-04-12 00:20:58 +02:00
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
2010-06-15 02:51:55 +02:00
( 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
2012-04-12 00:20:58 +02:00
Lesser General Public License for more details .
2010-06-15 02:51:55 +02:00
2012-04-12 00:20:58 +02:00
You should have received a copy of the GNU Lesser General Public License
2010-06-15 02:51:55 +02:00
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
2010-06-17 22:57:28 +02:00
# include <sys/reboot.h>
2013-11-06 09:02:41 +01:00
# include <linux/reboot.h>
# include <sys/syscall.h>
2010-06-15 02:51:55 +02:00
# include <stdio.h>
# include <getopt.h>
2012-11-12 20:16:07 +01:00
# include <locale.h>
2010-06-15 02:51:55 +02:00
# include <stdbool.h>
# include <string.h>
# include <errno.h>
# include <sys/ioctl.h>
# include <termios.h>
# include <unistd.h>
2010-06-18 04:44:53 +02:00
# include <fcntl.h>
2010-06-19 16:58:59 +02:00
# include <sys/socket.h>
2010-07-24 00:53:33 +02:00
# include <sys/stat.h>
2010-10-07 02:34:17 +02:00
# include <stddef.h>
2010-10-26 05:29:39 +02:00
# include <sys/prctl.h>
2012-01-05 16:01:58 +01:00
2013-11-07 05:49:04 +01:00
# include "sd-daemon.h"
# include "sd-shutdown.h"
# include "sd-login.h"
# include "sd-bus.h"
2010-06-15 02:51:55 +02:00
# include "log.h"
# include "util.h"
# include "macro.h"
# include "set.h"
2010-06-17 22:57:28 +02:00
# include "utmp-wtmp.h"
2010-06-18 04:22:59 +02:00
# include "special.h"
2010-06-18 04:44:53 +02:00
# include "initreq.h"
2012-05-07 21:36:12 +02:00
# include "path-util.h"
2010-06-18 20:23:17 +02:00
# include "strv.h"
2010-07-08 06:08:32 +02:00
# include "cgroup-show.h"
2010-07-11 00:50:49 +02:00
# include "cgroup-util.h"
2010-07-10 15:42:24 +02:00
# include "list.h"
2010-07-24 00:53:33 +02:00
# include "path-lookup.h"
# include "conf-parser.h"
2010-08-19 03:18:49 +02:00
# include "exit-status.h"
2010-08-31 21:05:54 +02:00
# include "bus-errors.h"
2010-09-06 03:11:24 +02:00
# include "build.h"
2010-10-06 02:33:40 +02:00
# include "unit-name.h"
2011-07-07 02:34:35 +02:00
# include "pager.h"
2012-04-11 18:50:16 +02:00
# include "spawn-ask-password-agent.h"
# include "spawn-polkit-agent.h"
2011-07-25 04:58:02 +02:00
# include "install.h"
2012-01-03 21:08:28 +01:00
# include "logs-show.h"
2012-05-07 21:36:12 +02:00
# include "path-util.h"
2012-09-18 17:11:12 +02:00
# include "socket-util.h"
2013-02-14 12:26:13 +01:00
# include "fileio.h"
2013-11-07 05:49:04 +01:00
# include "bus-util.h"
# include "bus-message.h"
# include "bus-error.h"
2010-06-15 02:51:55 +02:00
2013-04-11 04:40:58 +02:00
static char * * arg_types = NULL ;
2013-07-18 13:24:12 +02:00
static char * * arg_states = NULL ;
2013-04-11 04:40:58 +02:00
static char * * arg_properties = NULL ;
2010-06-15 02:51:55 +02:00
static bool arg_all = false ;
2013-09-19 23:12:00 +02:00
static bool original_stdout_is_tty ;
2013-04-24 05:49:46 +02:00
static enum dependency {
DEPENDENCY_FORWARD ,
DEPENDENCY_REVERSE ,
DEPENDENCY_AFTER ,
DEPENDENCY_BEFORE ,
} arg_dependency = DEPENDENCY_FORWARD ;
2011-02-16 21:59:31 +01:00
static const char * arg_job_mode = " replace " ;
2011-07-25 04:58:02 +02:00
static UnitFileScope arg_scope = UNIT_FILE_SYSTEM ;
2010-07-24 00:53:33 +02:00
static bool arg_no_block = false ;
2011-09-27 00:48:40 +02:00
static bool arg_no_legend = false ;
2011-01-02 00:25:57 +01:00
static bool arg_no_pager = false ;
2010-06-17 22:57:28 +02:00
static bool arg_no_wtmp = false ;
2010-06-18 04:22:59 +02:00
static bool arg_no_wall = false ;
2010-07-24 00:53:33 +02:00
static bool arg_no_reload = false ;
2013-04-12 00:59:18 +02:00
static bool arg_show_types = false ;
2013-01-11 04:24:05 +01:00
static bool arg_ignore_inhibitors = false ;
2010-06-17 22:57:28 +02:00
static bool arg_dry = false ;
2010-07-01 01:06:58 +02:00
static bool arg_quiet = false ;
2010-07-24 00:53:33 +02:00
static bool arg_full = false ;
2012-02-15 20:05:49 +01:00
static int arg_force = 0 ;
2012-04-11 18:50:16 +02:00
static bool arg_ask_password = true ;
2011-07-25 04:58:02 +02:00
static bool arg_runtime = false ;
2010-06-17 22:57:28 +02:00
static char * * arg_wall = NULL ;
2010-10-22 16:11:50 +02:00
static const char * arg_kill_who = NULL ;
static int arg_signal = SIGTERM ;
2011-07-07 04:19:03 +02:00
static const char * arg_root = NULL ;
2010-08-16 15:37:52 +02:00
static usec_t arg_when = 0 ;
2010-07-16 02:56:00 +02:00
static enum action {
2013-11-07 05:49:04 +01:00
_ACTION_INVALID ,
2010-06-17 22:57:28 +02:00
ACTION_SYSTEMCTL ,
ACTION_HALT ,
ACTION_POWEROFF ,
ACTION_REBOOT ,
2010-10-14 00:56:12 +02:00
ACTION_KEXEC ,
ACTION_EXIT ,
2012-05-05 02:06:58 +02:00
ACTION_SUSPEND ,
ACTION_HIBERNATE ,
2012-10-28 00:49:04 +02:00
ACTION_HYBRID_SLEEP ,
2010-06-17 22:57:28 +02:00
ACTION_RUNLEVEL2 ,
ACTION_RUNLEVEL3 ,
ACTION_RUNLEVEL4 ,
ACTION_RUNLEVEL5 ,
ACTION_RESCUE ,
2010-06-18 04:22:59 +02:00
ACTION_EMERGENCY ,
ACTION_DEFAULT ,
2010-06-17 22:57:28 +02:00
ACTION_RELOAD ,
ACTION_REEXEC ,
ACTION_RUNLEVEL ,
2010-08-16 15:37:52 +02:00
ACTION_CANCEL_SHUTDOWN ,
2010-06-17 22:57:28 +02:00
_ACTION_MAX
} arg_action = ACTION_SYSTEMCTL ;
2013-11-07 05:49:04 +01:00
static BusTransport arg_transport = BUS_TRANSPORT_LOCAL ;
2013-06-09 22:54:39 +02:00
static char * arg_host = NULL ;
2012-01-04 18:33:36 +01:00
static unsigned arg_lines = 10 ;
static OutputMode arg_output = OUTPUT_SHORT ;
2013-05-03 12:52:19 +02:00
static bool arg_plain = false ;
2010-06-17 22:57:28 +02:00
2013-11-07 05:49:04 +01:00
static int daemon_reload ( sd_bus * bus , char * * args ) ;
2012-02-29 22:22:15 +01:00
static void halt_now ( enum action a ) ;
2011-07-07 02:34:35 +02:00
2011-07-07 03:30:31 +02:00
static void pager_open_if_enabled ( void ) {
2011-09-23 01:44:36 +02:00
2011-07-25 04:58:02 +02:00
if ( arg_no_pager )
return ;
2011-07-07 03:30:31 +02:00
2013-03-07 20:44:35 +01:00
pager_open ( false ) ;
2011-07-25 04:58:02 +02:00
}
2011-02-25 02:51:48 +01:00
2012-04-11 18:50:16 +02:00
static void ask_password_agent_open_if_enabled ( void ) {
2010-10-26 05:29:39 +02:00
2011-07-25 04:58:02 +02:00
/* Open the password agent as a child process if necessary */
2010-10-26 05:29:39 +02:00
if ( ! arg_ask_password )
return ;
2011-02-09 01:09:09 +01:00
2011-07-25 04:58:02 +02:00
if ( arg_scope ! = UNIT_FILE_SYSTEM )
2010-10-26 05:29:39 +02:00
return ;
2013-11-08 13:54:46 +01:00
if ( arg_transport ! = BUS_TRANSPORT_LOCAL )
return ;
2012-04-11 18:50:16 +02:00
ask_password_agent_open ( ) ;
}
2012-05-30 22:25:01 +02:00
# ifdef HAVE_LOGIND
2012-04-11 18:50:16 +02:00
static void polkit_agent_open_if_enabled ( void ) {
/* Open the polkit agent as a child process if necessary */
if ( ! arg_ask_password )
return ;
if ( arg_scope ! = UNIT_FILE_SYSTEM )
return ;
2013-11-07 05:49:04 +01:00
if ( arg_transport ! = BUS_TRANSPORT_LOCAL )
return ;
2012-04-11 18:50:16 +02:00
polkit_agent_open ( ) ;
2010-10-26 05:29:39 +02:00
}
2012-05-30 22:25:01 +02:00
# endif
2010-10-26 05:29:39 +02:00
2013-11-07 05:49:04 +01:00
static int translate_bus_error_to_exit_status ( int r , const sd_bus_error * error ) {
2010-08-31 21:05:54 +02:00
assert ( error ) ;
2013-11-07 05:49:04 +01:00
if ( ! sd_bus_error_is_set ( error ) )
2010-08-31 21:05:54 +02:00
return r ;
2013-11-07 05:49:04 +01:00
if ( sd_bus_error_has_name ( error , SD_BUS_ERROR_ACCESS_DENIED ) | |
sd_bus_error_has_name ( error , BUS_ERROR_ONLY_BY_DEPENDENCY ) | |
sd_bus_error_has_name ( error , BUS_ERROR_NO_ISOLATION ) | |
sd_bus_error_has_name ( error , BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE ) )
2010-08-31 21:05:54 +02:00
return EXIT_NOPERMISSION ;
2013-11-07 05:49:04 +01:00
if ( sd_bus_error_has_name ( error , BUS_ERROR_NO_SUCH_UNIT ) )
2010-08-31 21:05:54 +02:00
return EXIT_NOTINSTALLED ;
2013-11-07 05:49:04 +01:00
if ( sd_bus_error_has_name ( error , BUS_ERROR_JOB_TYPE_NOT_APPLICABLE ) | |
sd_bus_error_has_name ( error , BUS_ERROR_NOT_SUPPORTED ) )
2010-08-31 21:05:54 +02:00
return EXIT_NOTIMPLEMENTED ;
2013-11-07 05:49:04 +01:00
if ( sd_bus_error_has_name ( error , BUS_ERROR_LOAD_FAILED ) )
2010-08-31 21:05:54 +02:00
return EXIT_NOTCONFIGURED ;
if ( r ! = 0 )
return r ;
return EXIT_FAILURE ;
}
2012-02-29 22:22:15 +01:00
static void warn_wall ( enum action a ) {
2010-06-18 02:28:35 +02:00
static const char * table [ _ACTION_MAX ] = {
2012-07-30 17:25:39 +02:00
[ ACTION_HALT ] = " The system is going down for system halt NOW! " ,
[ ACTION_REBOOT ] = " The system is going down for reboot NOW! " ,
[ ACTION_POWEROFF ] = " The system is going down for power-off NOW! " ,
[ ACTION_KEXEC ] = " The system is going down for kexec reboot NOW! " ,
[ ACTION_RESCUE ] = " The system is going down to rescue mode NOW! " ,
[ ACTION_EMERGENCY ] = " The system is going down to emergency mode NOW! " ,
[ ACTION_CANCEL_SHUTDOWN ] = " The system shutdown has been cancelled NOW! "
2010-06-18 02:28:35 +02:00
} ;
2010-06-18 04:22:59 +02:00
if ( arg_no_wall )
return ;
2010-06-18 20:23:17 +02:00
if ( arg_wall ) {
2013-01-14 02:11:22 +01:00
_cleanup_free_ char * p ;
2010-06-18 20:23:17 +02:00
2012-04-11 00:36:44 +02:00
p = strv_join ( arg_wall , " " ) ;
if ( ! p ) {
2013-01-14 02:11:22 +01:00
log_oom ( ) ;
2010-06-18 20:23:17 +02:00
return ;
}
if ( * p ) {
2010-11-12 03:33:08 +01:00
utmp_wall ( p , NULL ) ;
2010-06-18 20:23:17 +02:00
return ;
}
}
2012-02-29 22:22:15 +01:00
if ( ! table [ a ] )
2010-06-18 02:28:35 +02:00
return ;
2012-02-29 22:22:15 +01:00
utmp_wall ( table [ a ] , NULL ) ;
2010-06-18 02:28:35 +02:00
}
2011-07-25 04:58:02 +02:00
static bool avoid_bus ( void ) {
if ( running_in_chroot ( ) > 0 )
return true ;
if ( sd_booted ( ) < = 0 )
return true ;
if ( ! isempty ( arg_root ) )
return true ;
if ( arg_scope = = UNIT_FILE_GLOBAL )
return true ;
return false ;
}
2010-08-14 03:40:10 +02:00
static int compare_unit_info ( const void * a , const void * b ) {
2013-11-07 05:49:04 +01:00
const UnitInfo * u = a , * v = b ;
2010-08-14 03:40:10 +02:00
const char * d1 , * d2 ;
d1 = strrchr ( u - > id , ' . ' ) ;
d2 = strrchr ( v - > id , ' . ' ) ;
if ( d1 & & d2 ) {
int r ;
2013-01-14 02:11:22 +01:00
r = strcasecmp ( d1 , d2 ) ;
if ( r ! = 0 )
2010-08-14 03:40:10 +02:00
return r ;
}
2010-08-15 02:21:17 +02:00
return strcasecmp ( u - > id , v - > id ) ;
2010-08-14 03:40:10 +02:00
}
2013-11-07 05:49:04 +01:00
static bool output_show_unit ( const UnitInfo * u ) {
2010-09-07 10:30:52 +02:00
const char * dot ;
2010-09-15 03:12:04 +02:00
2013-07-18 13:24:12 +02:00
if ( ! strv_isempty ( arg_states ) )
2013-11-07 05:49:04 +01:00
return
strv_contains ( arg_states , u - > load_state ) | |
strv_contains ( arg_states , u - > sub_state ) | |
strv_contains ( arg_states , u - > active_state ) ;
2011-02-16 20:34:59 +01:00
2013-04-11 04:40:58 +02:00
return ( ! arg_types | | ( ( dot = strrchr ( u - > id , ' . ' ) ) & &
strv_find ( arg_types , dot + 1 ) ) ) & &
2012-07-10 18:03:03 +02:00
( arg_all | | ! ( streq ( u - > active_state , " inactive " )
| | u - > following [ 0 ] ) | | u - > job_id > 0 ) ;
2010-09-07 10:30:52 +02:00
}
2013-11-07 05:49:04 +01:00
static void output_units_list ( const UnitInfo * unit_infos , unsigned c ) {
2013-11-04 22:01:17 +01:00
unsigned id_len , max_id_len , load_len , active_len , sub_len , job_len , desc_len ;
2013-11-07 05:49:04 +01:00
const UnitInfo * u ;
2013-11-04 22:01:17 +01:00
unsigned n_shown = 0 ;
2012-10-28 13:22:37 +01:00
int job_count = 0 ;
2010-09-07 10:30:52 +02:00
2013-11-07 05:49:04 +01:00
max_id_len = sizeof ( " UNIT " ) - 1 ;
load_len = sizeof ( " LOAD " ) - 1 ;
active_len = sizeof ( " ACTIVE " ) - 1 ;
sub_len = sizeof ( " SUB " ) - 1 ;
job_len = sizeof ( " JOB " ) - 1 ;
2011-09-27 11:20:20 +02:00
desc_len = 0 ;
2010-09-15 03:12:04 +02:00
for ( u = unit_infos ; u < unit_infos + c ; u + + ) {
2011-02-16 20:34:59 +01:00
if ( ! output_show_unit ( u ) )
2010-09-15 03:12:04 +02:00
continue ;
2011-09-27 11:20:20 +02:00
max_id_len = MAX ( max_id_len , strlen ( u - > id ) ) ;
2013-11-04 22:01:17 +01:00
load_len = MAX ( load_len , strlen ( u - > load_state ) ) ;
2010-09-15 03:12:04 +02:00
active_len = MAX ( active_len , strlen ( u - > active_state ) ) ;
sub_len = MAX ( sub_len , strlen ( u - > sub_state ) ) ;
2013-11-07 05:49:04 +01:00
2012-10-28 13:22:37 +01:00
if ( u - > job_id ! = 0 ) {
2010-09-15 03:12:04 +02:00
job_len = MAX ( job_len , strlen ( u - > job_type ) ) ;
2012-10-28 13:22:37 +01:00
job_count + + ;
}
2010-09-07 10:30:52 +02:00
}
2013-09-19 23:12:00 +02:00
if ( ! arg_full & & original_stdout_is_tty ) {
2011-09-27 11:20:20 +02:00
unsigned basic_len ;
2013-11-08 13:54:46 +01:00
2013-04-01 08:08:05 +02:00
id_len = MIN ( max_id_len , 25u ) ;
2012-10-28 13:22:37 +01:00
basic_len = 5 + id_len + 5 + active_len + sub_len ;
2013-11-08 13:54:46 +01:00
2012-10-28 13:22:37 +01:00
if ( job_count )
basic_len + = job_len + 1 ;
2013-11-08 13:54:46 +01:00
2011-09-27 11:20:20 +02:00
if ( basic_len < ( unsigned ) columns ( ) ) {
unsigned extra_len , incr ;
extra_len = columns ( ) - basic_len ;
2013-11-08 13:54:46 +01:00
2011-09-27 11:20:20 +02:00
/* Either UNIT already got 25, or is fully satisfied.
* Grant up to 25 to DESC now . */
2013-04-01 08:08:05 +02:00
incr = MIN ( extra_len , 25u ) ;
2011-09-27 11:20:20 +02:00
desc_len + = incr ;
extra_len - = incr ;
2013-11-08 13:54:46 +01:00
2011-09-27 11:20:20 +02:00
/* split the remaining space between UNIT and DESC,
* but do not give UNIT more than it needs . */
if ( extra_len > 0 ) {
incr = MIN ( extra_len / 2 , max_id_len - id_len ) ;
id_len + = incr ;
desc_len + = extra_len - incr ;
}
}
} else
id_len = max_id_len ;
2010-09-15 03:12:04 +02:00
for ( u = unit_infos ; u < unit_infos + c ; u + + ) {
2013-04-18 09:11:22 +02:00
_cleanup_free_ char * e = NULL ;
2013-04-12 00:11:47 +02:00
const char * on_loaded , * off_loaded , * on = " " ;
const char * on_active , * off_active , * off = " " ;
2010-09-15 03:12:04 +02:00
2011-02-16 20:34:59 +01:00
if ( ! output_show_unit ( u ) )
2010-09-15 03:12:04 +02:00
continue ;
2012-10-04 13:01:10 +02:00
if ( ! n_shown & & ! arg_no_legend ) {
2013-11-08 13:54:46 +01:00
printf ( " %-*s %-*s %-*s %-*s " ,
id_len , " UNIT " ,
load_len , " LOAD " ,
active_len , " ACTIVE " ,
sub_len , " SUB " ) ;
2012-10-28 13:22:37 +01:00
if ( job_count )
printf ( " %-*s " , job_len , " JOB " ) ;
2013-11-08 13:54:46 +01:00
2012-10-04 13:01:10 +02:00
if ( ! arg_full & & arg_no_pager )
printf ( " %.*s \n " , desc_len , " DESCRIPTION " ) ;
else
printf ( " %s \n " , " DESCRIPTION " ) ;
}
2010-10-19 19:43:44 +02:00
n_shown + + ;
2013-07-18 02:31:06 +02:00
if ( streq ( u - > load_state , " error " ) | |
streq ( u - > load_state , " not-found " ) ) {
2013-08-02 07:59:02 +02:00
on_loaded = on = ansi_highlight_red ( ) ;
off_loaded = off = ansi_highlight_off ( ) ;
2010-09-15 03:12:04 +02:00
} else
on_loaded = off_loaded = " " ;
if ( streq ( u - > active_state , " failed " ) ) {
2013-08-02 07:59:02 +02:00
on_active = on = ansi_highlight_red ( ) ;
off_active = off = ansi_highlight_off ( ) ;
2010-09-15 03:12:04 +02:00
} else
on_active = off_active = " " ;
2010-09-07 10:30:51 +02:00
2011-09-27 11:20:20 +02:00
e = arg_full ? NULL : ellipsize ( u - > id , id_len , 33 ) ;
2010-09-07 10:30:51 +02:00
2013-11-04 22:01:17 +01:00
printf ( " %s%-*s%s %s%-*s%s %s%-*s %-*s%s %-*s " ,
2013-04-12 00:11:47 +02:00
on , id_len , e ? e : u - > id , off ,
2013-11-04 22:01:17 +01:00
on_loaded , load_len , u - > load_state , off_loaded ,
2010-09-15 03:12:04 +02:00
on_active , active_len , u - > active_state ,
sub_len , u - > sub_state , off_active ,
2012-10-28 13:22:37 +01:00
job_count ? job_len + 1 : 0 , u - > job_id ? u - > job_type : " " ) ;
2013-11-08 13:54:46 +01:00
2013-09-19 23:12:00 +02:00
if ( desc_len > 0 )
2011-09-29 21:18:17 +02:00
printf ( " %.*s \n " , desc_len , u - > description ) ;
else
printf ( " %s \n " , u - > description ) ;
2010-09-07 10:30:51 +02:00
}
2011-09-27 00:48:40 +02:00
if ( ! arg_no_legend ) {
2012-10-04 13:12:23 +02:00
const char * on , * off ;
if ( n_shown ) {
2012-10-04 13:01:10 +02:00
printf ( " \n LOAD = Reflects whether the unit definition was properly loaded. \n "
" ACTIVE = The high-level unit activation state, i.e. generalization of SUB. \n "
2012-10-28 13:22:37 +01:00
" SUB = The low-level unit activation state, values depend on unit type. \n " ) ;
if ( job_count )
printf ( " JOB = Pending job for the unit. \n " ) ;
2012-11-15 11:39:23 +01:00
puts ( " " ) ;
2013-08-02 07:59:02 +02:00
on = ansi_highlight ( ) ;
off = ansi_highlight_off ( ) ;
2012-10-04 13:12:23 +02:00
} else {
2013-08-02 07:59:02 +02:00
on = ansi_highlight_red ( ) ;
off = ansi_highlight_off ( ) ;
2012-10-04 13:12:23 +02:00
}
2010-09-07 10:30:51 +02:00
if ( arg_all )
2012-11-15 11:39:23 +01:00
printf ( " %s%u loaded units listed.%s \n "
2012-10-04 13:12:23 +02:00
" To show all installed unit files use 'systemctl list-unit-files'. \n " ,
on , n_shown , off ) ;
2010-09-07 10:30:51 +02:00
else
2012-11-15 11:39:23 +01:00
printf ( " %s%u loaded units listed.%s Pass --all to see loaded but inactive units, too. \n "
2012-10-04 13:12:23 +02:00
" To show all installed unit files use 'systemctl list-unit-files'. \n " ,
on , n_shown , off ) ;
2010-09-07 10:30:51 +02:00
}
}
2013-07-01 00:02:41 +02:00
static int get_unit_list (
2013-11-07 05:49:04 +01:00
sd_bus * bus ,
sd_bus_message * * _reply ,
UnitInfo * * _unit_infos ) {
2013-07-01 00:02:41 +02:00
2013-11-07 05:49:04 +01:00
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL ;
_cleanup_bus_message_unref_ sd_bus_message * reply = NULL ;
_cleanup_free_ UnitInfo * unit_infos = NULL ;
2013-04-12 00:59:18 +02:00
size_t size = 0 ;
2013-11-07 05:49:04 +01:00
int r , c = 0 ;
UnitInfo u ;
2010-06-15 02:51:55 +02:00
2013-02-14 22:55:24 +01:00
assert ( bus ) ;
2013-11-07 05:49:04 +01:00
assert ( _reply ) ;
assert ( _unit_infos ) ;
2011-01-04 01:04:20 +01:00
2013-11-07 05:49:04 +01:00
r = sd_bus_call_method (
2012-08-08 01:32:30 +02:00
bus ,
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
" ListUnits " ,
2013-11-07 05:49:04 +01:00
& error ,
& reply ,
NULL ) ;
if ( r < 0 ) {
log_error ( " Failed to list units: %s " , bus_error_message ( & error , r ) ) ;
2013-01-14 02:11:22 +01:00
return r ;
2010-06-15 02:51:55 +02:00
}
2013-11-07 05:49:04 +01:00
r = sd_bus_message_enter_container ( reply , SD_BUS_TYPE_ARRAY , " (ssssssouso) " ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2010-06-15 02:51:55 +02:00
2013-11-07 05:49:04 +01:00
while ( ( r = bus_parse_unit_info ( reply , & u ) ) > 0 ) {
2010-06-15 02:51:55 +02:00
2013-11-07 05:49:04 +01:00
if ( ! GREEDY_REALLOC ( unit_infos , size , c + 1 ) )
return log_oom ( ) ;
2010-08-14 03:40:10 +02:00
2013-11-07 05:49:04 +01:00
unit_infos [ c + + ] = u ;
2013-04-12 00:59:18 +02:00
}
2013-11-07 05:49:04 +01:00
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2013-04-12 00:59:18 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_exit_container ( reply ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
* _reply = reply ;
reply = NULL ;
* _unit_infos = unit_infos ;
unit_infos = NULL ;
return c ;
2013-04-12 00:59:18 +02:00
}
2013-11-07 05:49:04 +01:00
static int list_units ( sd_bus * bus , char * * args ) {
_cleanup_bus_message_unref_ sd_bus_message * reply = NULL ;
_cleanup_free_ UnitInfo * unit_infos = NULL ;
2013-04-12 00:59:18 +02:00
int r ;
pager_open_if_enabled ( ) ;
2013-11-07 05:49:04 +01:00
r = get_unit_list ( bus , & reply , & unit_infos ) ;
2013-04-12 00:59:18 +02:00
if ( r < 0 )
return r ;
2013-11-07 05:49:04 +01:00
qsort_safe ( unit_infos , r , sizeof ( UnitInfo ) , compare_unit_info ) ;
output_units_list ( unit_infos , r ) ;
2013-04-12 00:59:18 +02:00
return 0 ;
}
2013-07-01 00:02:41 +02:00
static int get_triggered_units (
2013-11-07 05:49:04 +01:00
sd_bus * bus ,
const char * path ,
char * * * ret ) {
2013-07-01 00:02:41 +02:00
2013-11-07 05:49:04 +01:00
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL ;
2013-04-12 00:59:18 +02:00
int r ;
2013-11-07 05:49:04 +01:00
r = sd_bus_get_property_strv (
bus ,
" org.freedesktop.systemd1 " ,
path ,
" org.freedesktop.systemd1.Unit " ,
" Triggers " ,
& error ,
ret ) ;
2013-04-12 00:59:18 +02:00
2013-11-07 05:49:04 +01:00
if ( r < 0 )
log_error ( " Failed to determine triggers: %s " , bus_error_message ( & error , r ) ) ;
2013-04-12 00:59:18 +02:00
return 0 ;
}
2013-11-07 05:49:04 +01:00
static int get_listening (
sd_bus * bus ,
const char * unit_path ,
2013-11-08 18:50:58 +01:00
char * * * listening ,
2013-11-07 05:49:04 +01:00
unsigned * c ) {
_cleanup_bus_message_unref_ sd_bus_message * reply = NULL ;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL ;
const char * type , * path ;
2013-04-12 00:59:18 +02:00
int r ;
2013-11-07 05:49:04 +01:00
r = sd_bus_get_property (
bus ,
" org.freedesktop.systemd1 " ,
unit_path ,
" org.freedesktop.systemd1.Socket " ,
" Listen " ,
& error ,
& reply ,
" a(ss) " ) ;
if ( r < 0 ) {
log_error ( " Failed to get list of listening sockets: %s " , bus_error_message ( & error , r ) ) ;
2013-04-12 00:59:18 +02:00
return r ;
}
2013-11-07 05:49:04 +01:00
r = sd_bus_message_enter_container ( reply , SD_BUS_TYPE_ARRAY , " (ss) " ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2013-04-12 00:59:18 +02:00
2013-11-07 05:49:04 +01:00
while ( ( r = sd_bus_message_read ( reply , " (ss) " , & type , & path ) ) > 0 ) {
2010-08-14 03:40:10 +02:00
2013-11-08 18:50:58 +01:00
r = strv_extend ( listening , type ) ;
2013-11-07 05:49:04 +01:00
if ( r < 0 )
return log_oom ( ) ;
2013-04-12 00:59:18 +02:00
2013-11-08 18:50:58 +01:00
r = strv_extend ( listening , path ) ;
2013-11-07 05:49:04 +01:00
if ( r < 0 )
return log_oom ( ) ;
2010-06-15 02:51:55 +02:00
2013-11-07 05:49:04 +01:00
( * c ) + + ;
2010-08-14 03:40:10 +02:00
}
2013-11-07 05:49:04 +01:00
if ( r < 0 )
return bus_log_parse_error ( r ) ;
r = sd_bus_message_exit_container ( reply ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2010-08-14 03:40:10 +02:00
2013-04-12 00:59:18 +02:00
return 0 ;
}
struct socket_info {
const char * id ;
char * type ;
char * path ;
/* Note: triggered is a list here, although it almost certainly
* will always be one unit . Nevertheless , dbus API allows for multiple
* values , so let ' s follow that . */
char * * triggered ;
/* The strv above is shared. free is set only in the first one. */
bool own_triggered ;
} ;
static int socket_info_compare ( struct socket_info * a , struct socket_info * b ) {
2013-11-08 13:54:46 +01:00
int o ;
o = strcmp ( a - > path , b - > path ) ;
2013-04-12 00:59:18 +02:00
if ( o = = 0 )
o = strcmp ( a - > type , b - > type ) ;
2013-11-08 13:54:46 +01:00
2013-04-12 00:59:18 +02:00
return o ;
}
static int output_sockets_list ( struct socket_info * socket_infos , unsigned cs ) {
struct socket_info * s ;
unsigned pathlen = sizeof ( " LISTEN " ) - 1 ,
typelen = ( sizeof ( " TYPE " ) - 1 ) * arg_show_types ,
socklen = sizeof ( " UNIT " ) - 1 ,
servlen = sizeof ( " ACTIVATES " ) - 1 ;
const char * on , * off ;
for ( s = socket_infos ; s < socket_infos + cs ; s + + ) {
unsigned tmp = 0 ;
2013-11-08 13:54:46 +01:00
char * * a ;
2013-04-12 00:59:18 +02:00
socklen = MAX ( socklen , strlen ( s - > id ) ) ;
if ( arg_show_types )
typelen = MAX ( typelen , strlen ( s - > type ) ) ;
pathlen = MAX ( pathlen , strlen ( s - > path ) ) ;
STRV_FOREACH ( a , s - > triggered )
tmp + = strlen ( * a ) + 2 * ( a ! = s - > triggered ) ;
servlen = MAX ( servlen , tmp ) ;
}
if ( cs ) {
2013-05-20 10:20:15 +02:00
if ( ! arg_no_legend )
printf ( " %-*s %-*.*s%-*s %s \n " ,
pathlen , " LISTEN " ,
typelen + arg_show_types , typelen + arg_show_types , " TYPE " ,
socklen , " UNIT " ,
" ACTIVATES " ) ;
2013-04-12 00:59:18 +02:00
for ( s = socket_infos ; s < socket_infos + cs ; s + + ) {
char * * a ;
if ( arg_show_types )
printf ( " %-*s %-*s %-*s " ,
pathlen , s - > path , typelen , s - > type , socklen , s - > id ) ;
else
printf ( " %-*s %-*s " ,
pathlen , s - > path , socklen , s - > id ) ;
STRV_FOREACH ( a , s - > triggered )
printf ( " %s %s " ,
a = = s - > triggered ? " " : " , " , * a ) ;
printf ( " \n " ) ;
}
2013-08-02 07:59:02 +02:00
on = ansi_highlight ( ) ;
off = ansi_highlight_off ( ) ;
2013-05-20 10:20:15 +02:00
if ( ! arg_no_legend )
printf ( " \n " ) ;
2013-04-12 00:59:18 +02:00
} else {
2013-08-02 07:59:02 +02:00
on = ansi_highlight_red ( ) ;
off = ansi_highlight_off ( ) ;
2013-04-12 00:59:18 +02:00
}
2013-05-20 10:20:15 +02:00
if ( ! arg_no_legend ) {
printf ( " %s%u sockets listed.%s \n " , on , cs , off ) ;
if ( ! arg_all )
printf ( " Pass --all to see loaded but inactive sockets, too. \n " ) ;
}
2013-02-14 22:55:24 +01:00
return 0 ;
}
2013-11-07 05:49:04 +01:00
static int list_sockets ( sd_bus * bus , char * * args ) {
_cleanup_bus_message_unref_ sd_bus_message * reply = NULL ;
_cleanup_free_ UnitInfo * unit_infos = NULL ;
2013-04-12 00:59:18 +02:00
struct socket_info * socket_infos = NULL ;
2013-11-07 05:49:04 +01:00
const UnitInfo * u ;
2013-04-12 00:59:18 +02:00
struct socket_info * s ;
unsigned cu = 0 , cs = 0 ;
size_t size = 0 ;
2013-02-14 22:55:24 +01:00
int r ;
pager_open_if_enabled ( ) ;
2013-11-07 05:49:04 +01:00
r = get_unit_list ( bus , & reply , & unit_infos ) ;
2013-02-14 22:55:24 +01:00
if ( r < 0 )
return r ;
2013-11-07 05:49:04 +01:00
cu = ( unsigned ) r ;
2013-04-12 00:59:18 +02:00
for ( u = unit_infos ; u < unit_infos + cu ; u + + ) {
2013-11-08 18:50:58 +01:00
_cleanup_strv_free_ char * * listening = NULL , * * triggered = NULL ;
2013-04-12 00:59:18 +02:00
unsigned c = 0 , i ;
if ( ! output_show_unit ( u ) )
continue ;
2013-11-08 13:54:46 +01:00
if ( ! endswith ( u - > id , " .socket " ) )
2013-04-12 00:59:18 +02:00
continue ;
r = get_triggered_units ( bus , u - > unit_path , & triggered ) ;
if ( r < 0 )
goto cleanup ;
2013-11-08 18:50:58 +01:00
r = get_listening ( bus , u - > unit_path , & listening , & c ) ;
2013-04-12 00:59:18 +02:00
if ( r < 0 )
goto cleanup ;
if ( ! GREEDY_REALLOC ( socket_infos , size , cs + c ) ) {
r = log_oom ( ) ;
goto cleanup ;
}
for ( i = 0 ; i < c ; i + + )
socket_infos [ cs + i ] = ( struct socket_info ) {
. id = u - > id ,
2013-11-08 18:50:58 +01:00
. type = listening [ i * 2 ] ,
. path = listening [ i * 2 + 1 ] ,
2013-04-12 00:59:18 +02:00
. triggered = triggered ,
. own_triggered = i = = 0 ,
} ;
/* from this point on we will cleanup those socket_infos */
cs + = c ;
2013-11-08 18:50:58 +01:00
free ( listening ) ;
listening = triggered = NULL ; /* avoid cleanup */
2013-04-12 00:59:18 +02:00
}
2013-10-12 01:33:13 +02:00
qsort_safe ( socket_infos , cs , sizeof ( struct socket_info ) ,
( __compar_fn_t ) socket_info_compare ) ;
2013-04-12 00:59:18 +02:00
output_sockets_list ( socket_infos , cs ) ;
cleanup :
assert ( cs = = 0 | | socket_infos ) ;
for ( s = socket_infos ; s < socket_infos + cs ; s + + ) {
free ( s - > type ) ;
free ( s - > path ) ;
if ( s - > own_triggered )
strv_free ( s - > triggered ) ;
}
free ( socket_infos ) ;
2010-07-16 02:56:00 +02:00
2013-10-12 01:34:17 +02:00
return r ;
2010-07-16 02:56:00 +02:00
}
2011-07-25 04:58:02 +02:00
static int compare_unit_file_list ( const void * a , const void * b ) {
const char * d1 , * d2 ;
const UnitFileList * u = a , * v = b ;
d1 = strrchr ( u - > path , ' . ' ) ;
d2 = strrchr ( v - > path , ' . ' ) ;
if ( d1 & & d2 ) {
int r ;
r = strcasecmp ( d1 , d2 ) ;
if ( r ! = 0 )
return r ;
}
2012-05-07 21:36:12 +02:00
return strcasecmp ( path_get_file_name ( u - > path ) , path_get_file_name ( v - > path ) ) ;
2011-07-25 04:58:02 +02:00
}
static bool output_show_unit_file ( const UnitFileList * u ) {
const char * dot ;
2013-04-11 04:40:58 +02:00
return ! arg_types | | ( ( dot = strrchr ( u - > path , ' . ' ) ) & & strv_find ( arg_types , dot + 1 ) ) ;
2011-07-25 04:58:02 +02:00
}
static void output_unit_file_list ( const UnitFileList * units , unsigned c ) {
2011-10-24 11:49:59 +02:00
unsigned max_id_len , id_cols , state_cols , n_shown = 0 ;
2011-07-25 04:58:02 +02:00
const UnitFileList * u ;
2011-10-24 11:49:59 +02:00
max_id_len = sizeof ( " UNIT FILE " ) - 1 ;
state_cols = sizeof ( " STATE " ) - 1 ;
2013-11-08 13:54:46 +01:00
2011-10-24 11:49:59 +02:00
for ( u = units ; u < units + c ; u + + ) {
if ( ! output_show_unit_file ( u ) )
continue ;
2012-05-07 21:36:12 +02:00
max_id_len = MAX ( max_id_len , strlen ( path_get_file_name ( u - > path ) ) ) ;
2011-10-24 11:49:59 +02:00
state_cols = MAX ( state_cols , strlen ( unit_file_state_to_string ( u - > state ) ) ) ;
}
if ( ! arg_full ) {
unsigned basic_cols ;
2013-11-08 13:54:46 +01:00
2013-04-01 08:08:05 +02:00
id_cols = MIN ( max_id_len , 25u ) ;
2011-10-24 11:49:59 +02:00
basic_cols = 1 + id_cols + state_cols ;
if ( basic_cols < ( unsigned ) columns ( ) )
id_cols + = MIN ( columns ( ) - basic_cols , max_id_len - id_cols ) ;
} else
id_cols = max_id_len ;
if ( ! arg_no_legend )
2013-11-08 13:54:46 +01:00
printf ( " %-*s %-*s \n " ,
id_cols , " UNIT FILE " ,
state_cols , " STATE " ) ;
2011-07-25 04:58:02 +02:00
for ( u = units ; u < units + c ; u + + ) {
2013-04-18 09:11:22 +02:00
_cleanup_free_ char * e = NULL ;
2011-07-25 04:58:02 +02:00
const char * on , * off ;
const char * id ;
if ( ! output_show_unit_file ( u ) )
continue ;
n_shown + + ;
if ( u - > state = = UNIT_FILE_MASKED | |
u - > state = = UNIT_FILE_MASKED_RUNTIME | |
2012-09-11 01:11:32 +02:00
u - > state = = UNIT_FILE_DISABLED | |
u - > state = = UNIT_FILE_INVALID ) {
2013-08-02 07:59:02 +02:00
on = ansi_highlight_red ( ) ;
off = ansi_highlight_off ( ) ;
2011-07-25 04:58:02 +02:00
} else if ( u - > state = = UNIT_FILE_ENABLED ) {
2013-08-02 07:59:02 +02:00
on = ansi_highlight_green ( ) ;
off = ansi_highlight_off ( ) ;
2011-07-25 04:58:02 +02:00
} else
on = off = " " ;
2012-05-07 21:36:12 +02:00
id = path_get_file_name ( u - > path ) ;
2011-07-25 04:58:02 +02:00
2011-10-24 11:49:59 +02:00
e = arg_full ? NULL : ellipsize ( id , id_cols , 33 ) ;
2011-07-25 04:58:02 +02:00
2011-10-24 11:49:59 +02:00
printf ( " %-*s %s%-*s%s \n " ,
id_cols , e ? e : id ,
on , state_cols , unit_file_state_to_string ( u - > state ) , off ) ;
2011-07-25 04:58:02 +02:00
}
2011-10-24 11:49:59 +02:00
if ( ! arg_no_legend )
2011-07-25 04:58:02 +02:00
printf ( " \n %u unit files listed. \n " , n_shown ) ;
}
2013-11-07 05:49:04 +01:00
static int list_unit_files ( sd_bus * bus , char * * args ) {
_cleanup_bus_message_unref_ sd_bus_message * reply = NULL ;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL ;
2013-01-14 02:11:22 +01:00
_cleanup_free_ UnitFileList * units = NULL ;
2013-11-07 05:49:04 +01:00
unsigned c = 0 ;
const char * state ;
char * path ;
2013-01-14 02:11:22 +01:00
int r ;
2011-07-25 04:58:02 +02:00
pager_open_if_enabled ( ) ;
if ( avoid_bus ( ) ) {
Hashmap * h ;
UnitFileList * u ;
Iterator i ;
2013-11-07 05:49:04 +01:00
unsigned n_units ;
2011-07-25 04:58:02 +02:00
h = hashmap_new ( string_hash_func , string_compare_func ) ;
2012-07-25 23:55:59 +02:00
if ( ! h )
return log_oom ( ) ;
2011-07-25 04:58:02 +02:00
r = unit_file_get_list ( arg_scope , arg_root , h ) ;
if ( r < 0 ) {
2011-09-23 01:43:28 +02:00
unit_file_list_free ( h ) ;
2011-07-25 04:58:02 +02:00
log_error ( " Failed to get unit file list: %s " , strerror ( - r ) ) ;
return r ;
}
n_units = hashmap_size ( h ) ;
units = new ( UnitFileList , n_units ) ;
if ( ! units ) {
unit_file_list_free ( h ) ;
2012-07-25 23:55:59 +02:00
return log_oom ( ) ;
2011-07-25 04:58:02 +02:00
}
HASHMAP_FOREACH ( u , h , i ) {
memcpy ( units + c + + , u , sizeof ( UnitFileList ) ) ;
free ( u ) ;
}
2013-11-07 05:49:04 +01:00
assert ( c = = n_units ) ;
2011-07-25 04:58:02 +02:00
hashmap_free ( h ) ;
} else {
2013-11-07 05:49:04 +01:00
size_t size = 0 ;
r = sd_bus_call_method (
2012-08-08 01:32:30 +02:00
bus ,
2011-07-25 04:58:02 +02:00
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
2012-08-08 01:32:30 +02:00
" ListUnitFiles " ,
2013-11-07 05:49:04 +01:00
& error ,
2012-08-08 01:32:30 +02:00
& reply ,
2013-11-07 05:49:04 +01:00
NULL ) ;
if ( r < 0 ) {
log_error ( " Failed to list unit files: %s " , bus_error_message ( & error , r ) ) ;
2013-01-14 02:11:22 +01:00
return r ;
2011-07-25 04:58:02 +02:00
}
2013-11-07 05:49:04 +01:00
r = sd_bus_message_enter_container ( reply , SD_BUS_TYPE_ARRAY , " (ss) " ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2011-07-25 04:58:02 +02:00
2013-11-07 05:49:04 +01:00
while ( ( r = sd_bus_message_read ( reply , " (ss) " , & path , & state ) ) > 0 ) {
2011-07-25 04:58:02 +02:00
2013-11-07 05:49:04 +01:00
if ( ! GREEDY_REALLOC ( units , size , c + 1 ) )
return log_oom ( ) ;
2011-07-25 04:58:02 +02:00
2013-11-07 05:49:04 +01:00
units [ c + + ] = ( struct UnitFileList ) {
path ,
unit_file_state_from_string ( state )
} ;
2011-07-25 04:58:02 +02:00
}
2013-11-07 05:49:04 +01:00
if ( r < 0 )
return bus_log_parse_error ( r ) ;
r = sd_bus_message_exit_container ( reply ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2011-07-25 04:58:02 +02:00
}
if ( c > 0 ) {
qsort ( units , c , sizeof ( UnitFileList ) , compare_unit_file_list ) ;
output_unit_file_list ( units , c ) ;
}
2013-01-14 02:11:22 +01:00
return 0 ;
2011-07-25 04:58:02 +02:00
}
2013-01-17 21:34:11 +01:00
static int list_dependencies_print ( const char * name , int level , unsigned int branches , bool last ) {
_cleanup_free_ char * n = NULL ;
2013-04-01 08:08:05 +02:00
size_t max_len = MAX ( columns ( ) , 20u ) ;
2013-11-08 13:54:46 +01:00
size_t len = 0 ;
int i ;
2013-01-17 21:34:11 +01:00
2013-05-03 12:52:19 +02:00
if ( ! arg_plain ) {
2013-11-08 13:54:46 +01:00
2013-05-03 12:52:19 +02:00
for ( i = level - 1 ; i > = 0 ; i - - ) {
len + = 2 ;
if ( len > max_len - 3 & & ! arg_full ) {
printf ( " %s... \n " , max_len % 2 ? " " : " " ) ;
return 0 ;
}
printf ( " %s " , draw_special_char ( branches & ( 1 < < i ) ? DRAW_TREE_VERT : DRAW_TREE_SPACE ) ) ;
}
2013-01-17 21:34:11 +01:00
len + = 2 ;
2013-11-08 13:54:46 +01:00
2013-01-17 21:34:11 +01:00
if ( len > max_len - 3 & & ! arg_full ) {
printf ( " %s... \n " , max_len % 2 ? " " : " " ) ;
return 0 ;
}
2013-11-08 13:54:46 +01:00
2013-05-03 12:52:19 +02:00
printf ( " %s " , draw_special_char ( last ? DRAW_TREE_RIGHT : DRAW_TREE_BRANCH ) ) ;
2013-01-17 21:34:11 +01:00
}
2013-11-08 13:54:46 +01:00
if ( arg_full ) {
2013-01-17 21:34:11 +01:00
printf ( " %s \n " , name ) ;
return 0 ;
}
n = ellipsize ( name , max_len - len , 100 ) ;
if ( ! n )
return log_oom ( ) ;
printf ( " %s \n " , n ) ;
return 0 ;
}
2013-11-07 05:49:04 +01:00
static int list_dependencies_get_dependencies ( sd_bus * bus , const char * name , char * * * deps ) {
2013-04-24 05:49:46 +02:00
static const char * dependencies [ ] = {
[ DEPENDENCY_FORWARD ] = " Requires \0 "
" RequiresOverridable \0 "
" Requisite \0 "
" RequisiteOverridable \0 "
" Wants \0 " ,
[ DEPENDENCY_REVERSE ] = " RequiredBy \0 "
" RequiredByOverridable \0 "
" WantedBy \0 "
" PartOf \0 " ,
[ DEPENDENCY_AFTER ] = " After \0 " ,
[ DEPENDENCY_BEFORE ] = " Before \0 " ,
} ;
2013-01-17 21:34:11 +01:00
2013-11-07 05:49:04 +01:00
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL ;
_cleanup_bus_message_unref_ sd_bus_message * reply = NULL ;
_cleanup_strv_free_ char * * ret = NULL ;
_cleanup_free_ char * path = NULL ;
int r ;
2013-01-17 21:34:11 +01:00
assert ( bus ) ;
assert ( name ) ;
assert ( deps ) ;
2013-11-07 05:49:04 +01:00
assert ( arg_dependency < ELEMENTSOF ( dependencies ) ) ;
2013-01-17 21:34:11 +01:00
path = unit_dbus_path_from_name ( name ) ;
2013-11-07 05:49:04 +01:00
if ( ! path )
return log_oom ( ) ;
2013-01-17 21:34:11 +01:00
2013-11-07 05:49:04 +01:00
r = sd_bus_call_method (
bus ,
" org.freedesktop.systemd1 " ,
path ,
" org.freedesktop.DBus.Properties " ,
" GetAll " ,
& error ,
& reply ,
" s " , " org.freedesktop.systemd1.Unit " ) ;
if ( r < 0 ) {
log_error ( " Failed to get properties of %s: %s " , name , bus_error_message ( & error , r ) ) ;
return r ;
2013-01-17 21:34:11 +01:00
}
2013-11-07 05:49:04 +01:00
r = sd_bus_message_enter_container ( reply , SD_BUS_TYPE_ARRAY , " {sv} " ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2013-01-17 21:34:11 +01:00
2013-11-07 05:49:04 +01:00
while ( ( r = sd_bus_message_enter_container ( reply , SD_BUS_TYPE_DICT_ENTRY , " sv " ) ) > 0 ) {
2013-01-17 21:34:11 +01:00
const char * prop ;
2013-11-07 05:49:04 +01:00
r = sd_bus_message_read ( reply , " s " , & prop ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2013-01-17 21:34:11 +01:00
2013-11-07 05:49:04 +01:00
if ( ! nulstr_contains ( dependencies [ arg_dependency ] , prop ) ) {
r = sd_bus_message_skip ( reply , " v " ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
} else {
2013-01-17 21:34:11 +01:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_enter_container ( reply , SD_BUS_TYPE_VARIANT , " as " ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2013-01-17 21:34:11 +01:00
2013-11-07 05:49:04 +01:00
r = bus_message_read_strv_extend ( reply , & ret ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2013-01-17 21:34:11 +01:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_exit_container ( reply ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
}
2013-01-17 21:34:11 +01:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_exit_container ( reply ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2013-01-17 21:34:11 +01:00
2013-11-07 05:49:04 +01:00
}
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2013-01-17 21:34:11 +01:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_exit_container ( reply ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2013-01-18 00:51:46 +01:00
2013-11-07 05:49:04 +01:00
* deps = ret ;
ret = NULL ;
2013-01-18 00:51:46 +01:00
2013-11-07 05:49:04 +01:00
return 0 ;
2013-01-17 21:34:11 +01:00
}
static int list_dependencies_compare ( const void * _a , const void * _b ) {
const char * * a = ( const char * * ) _a , * * b = ( const char * * ) _b ;
2013-11-08 13:54:46 +01:00
2013-01-17 21:34:11 +01:00
if ( unit_name_to_type ( * a ) = = UNIT_TARGET & & unit_name_to_type ( * b ) ! = UNIT_TARGET )
return 1 ;
if ( unit_name_to_type ( * a ) ! = UNIT_TARGET & & unit_name_to_type ( * b ) = = UNIT_TARGET )
return - 1 ;
2013-11-08 13:54:46 +01:00
2013-01-17 21:34:11 +01:00
return strcasecmp ( * a , * b ) ;
}
2013-11-07 05:49:04 +01:00
static int list_dependencies_one (
sd_bus * bus ,
const char * name ,
int level ,
char * * * units ,
unsigned int branches ) {
2013-04-18 09:11:22 +02:00
_cleanup_strv_free_ char * * deps = NULL , * * u ;
2013-01-17 21:34:11 +01:00
char * * c ;
int r = 0 ;
2013-11-08 13:54:46 +01:00
assert ( bus ) ;
assert ( name ) ;
assert ( units ) ;
2013-05-03 12:52:19 +02:00
u = strv_append ( * units , name ) ;
2013-02-14 19:32:19 +01:00
if ( ! u )
2013-01-17 21:34:11 +01:00
return log_oom ( ) ;
r = list_dependencies_get_dependencies ( bus , name , & deps ) ;
if ( r < 0 )
2013-02-14 19:32:19 +01:00
return r ;
2013-01-17 21:34:11 +01:00
2013-10-12 01:33:13 +02:00
qsort_safe ( deps , strv_length ( deps ) , sizeof ( char * ) , list_dependencies_compare ) ;
2013-01-17 21:34:11 +01:00
STRV_FOREACH ( c , deps ) {
if ( strv_contains ( u , * c ) ) {
2013-05-03 12:52:19 +02:00
if ( ! arg_plain ) {
r = list_dependencies_print ( " ... " , level + 1 , ( branches < < 1 ) | ( c [ 1 ] = = NULL ? 0 : 1 ) , 1 ) ;
if ( r < 0 )
return r ;
}
2013-01-17 21:34:11 +01:00
continue ;
}
r = list_dependencies_print ( * c , level , branches , c [ 1 ] = = NULL ) ;
2013-02-14 19:32:19 +01:00
if ( r < 0 )
return r ;
2013-01-17 21:34:11 +01:00
if ( arg_all | | unit_name_to_type ( * c ) = = UNIT_TARGET ) {
2013-05-03 12:52:19 +02:00
r = list_dependencies_one ( bus , * c , level + 1 , & u , ( branches < < 1 ) | ( c [ 1 ] = = NULL ? 0 : 1 ) ) ;
2013-01-17 21:34:11 +01:00
if ( r < 0 )
2013-02-14 19:32:19 +01:00
return r ;
2013-01-17 21:34:11 +01:00
}
}
2013-11-07 05:49:04 +01:00
2013-05-03 12:52:19 +02:00
if ( arg_plain ) {
strv_free ( * units ) ;
* units = u ;
u = NULL ;
}
2013-11-07 05:49:04 +01:00
2013-02-14 19:32:19 +01:00
return 0 ;
2013-01-17 21:34:11 +01:00
}
2013-11-07 05:49:04 +01:00
static int list_dependencies ( sd_bus * bus , char * * args ) {
2013-05-03 12:52:19 +02:00
_cleanup_strv_free_ char * * units = NULL ;
2013-11-07 05:49:04 +01:00
_cleanup_free_ char * unit = NULL ;
2013-01-18 00:36:12 +01:00
const char * u ;
2013-01-17 21:34:11 +01:00
assert ( bus ) ;
2013-01-18 00:36:12 +01:00
if ( args [ 1 ] ) {
unit = unit_name_mangle ( args [ 1 ] ) ;
if ( ! unit )
return log_oom ( ) ;
u = unit ;
} else
u = SPECIAL_DEFAULT_TARGET ;
2013-01-17 21:34:11 +01:00
pager_open_if_enabled ( ) ;
2013-01-18 00:36:12 +01:00
puts ( u ) ;
2013-05-03 12:52:19 +02:00
return list_dependencies_one ( bus , u , 0 , & units , 0 ) ;
2013-01-17 21:34:11 +01:00
}
2013-11-07 05:49:04 +01:00
static int get_default ( sd_bus * bus , char * * args ) {
_cleanup_bus_message_unref_ sd_bus_message * reply = NULL ;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL ;
_cleanup_free_ char * _path = NULL ;
const char * path ;
2013-05-28 11:05:48 +02:00
int r ;
if ( ! bus | | avoid_bus ( ) ) {
2013-11-07 05:49:04 +01:00
r = unit_file_get_default ( arg_scope , arg_root , & _path ) ;
2013-05-28 11:05:48 +02:00
if ( r < 0 ) {
2013-11-07 05:49:04 +01:00
log_error ( " Failed to get default target: %s " , strerror ( - r ) ) ;
return r ;
2013-05-28 11:05:48 +02:00
}
2013-11-07 05:49:04 +01:00
path = _path ;
2013-05-28 11:05:48 +02:00
} else {
2013-11-07 05:49:04 +01:00
r = sd_bus_call_method (
bus ,
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
" GetDefaultTarget " ,
& error ,
& reply ,
NULL ) ;
2013-05-28 11:05:48 +02:00
if ( r < 0 ) {
2013-11-07 05:49:04 +01:00
log_error ( " Failed to get default target: %s " , bus_error_message ( & error , - r ) ) ;
return r ;
2013-05-28 11:05:48 +02:00
}
2013-11-07 05:49:04 +01:00
r = sd_bus_message_read ( reply , " s " , & path ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2013-05-28 11:05:48 +02:00
}
if ( path )
printf ( " %s \n " , path ) ;
2013-11-07 05:49:04 +01:00
return 0 ;
2013-05-28 11:05:48 +02:00
}
2013-04-11 00:30:19 +02:00
struct job_info {
uint32_t id ;
2013-11-07 05:49:04 +01:00
const char * name , * type , * state ;
2013-04-11 00:30:19 +02:00
} ;
2013-11-07 05:49:04 +01:00
static void output_jobs_list ( const struct job_info * jobs , unsigned n ) {
unsigned id_len , unit_len , type_len , state_len ;
const struct job_info * j ;
2013-04-11 00:30:19 +02:00
const char * on , * off ;
bool shorten = false ;
assert ( n = = 0 | | jobs ) ;
if ( n = = 0 ) {
2013-08-02 07:59:02 +02:00
on = ansi_highlight_green ( ) ;
off = ansi_highlight_off ( ) ;
2013-04-11 00:30:19 +02:00
printf ( " %sNo jobs running.%s \n " , on , off ) ;
return ;
}
pager_open_if_enabled ( ) ;
2013-11-08 18:57:26 +01:00
id_len = sizeof ( " JOB " ) - 1 ;
unit_len = sizeof ( " UNIT " ) - 1 ;
type_len = sizeof ( " TYPE " ) - 1 ;
state_len = sizeof ( " STATE " ) - 1 ;
2013-11-07 05:49:04 +01:00
for ( j = jobs ; j < jobs + n ; j + + ) {
uint32_t id = j - > id ;
assert ( j - > name & & j - > type & & j - > state ) ;
2013-04-11 00:30:19 +02:00
2013-11-07 05:49:04 +01:00
id_len = MAX ( id_len , DECIMAL_STR_WIDTH ( id ) ) ;
unit_len = MAX ( unit_len , strlen ( j - > name ) ) ;
type_len = MAX ( type_len , strlen ( j - > type ) ) ;
state_len = MAX ( state_len , strlen ( j - > state ) ) ;
}
2013-04-11 00:30:19 +02:00
2013-11-07 05:49:04 +01:00
if ( ! arg_full & & id_len + 1 + unit_len + type_len + 1 + state_len > columns ( ) ) {
unit_len = MAX ( 33u , columns ( ) - id_len - type_len - state_len - 3 ) ;
shorten = true ;
}
2013-04-11 00:30:19 +02:00
2013-11-07 05:49:04 +01:00
printf ( " %*s %-*s %-*s %-*s \n " ,
id_len , " JOB " ,
unit_len , " UNIT " ,
type_len , " TYPE " ,
state_len , " STATE " ) ;
2013-04-11 00:30:19 +02:00
2013-11-07 05:49:04 +01:00
for ( j = jobs ; j < jobs + n ; j + + ) {
_cleanup_free_ char * e = NULL ;
2013-04-11 00:30:19 +02:00
2013-11-07 05:49:04 +01:00
if ( streq ( j - > state , " running " ) ) {
on = ansi_highlight ( ) ;
off = ansi_highlight_off ( ) ;
} else
on = off = " " ;
e = shorten ? ellipsize ( j - > name , unit_len , 33 ) : NULL ;
printf ( " %*u %s%-*s%s %-*s %s%-*s%s \n " ,
id_len , j - > id ,
on , unit_len , e ? e : j - > name , off ,
type_len , j - > type ,
on , state_len , j - > state , off ) ;
2013-04-11 00:30:19 +02:00
}
2013-08-02 07:59:02 +02:00
on = ansi_highlight ( ) ;
off = ansi_highlight_off ( ) ;
2013-04-11 00:30:19 +02:00
2013-11-07 05:49:04 +01:00
printf ( " \n %s%u jobs listed%s. \n " , on , n , off ) ;
2013-04-11 00:30:19 +02:00
}
2013-11-07 05:49:04 +01:00
static int list_jobs ( sd_bus * bus , char * * args ) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL ;
_cleanup_bus_message_unref_ sd_bus_message * reply = NULL ;
const char * name , * type , * state , * job_path , * unit_path ;
_cleanup_free_ struct job_info * jobs = NULL ;
size_t size = 0 ;
unsigned c = 0 ;
uint32_t id ;
2013-01-14 02:11:22 +01:00
int r ;
2011-01-04 01:04:20 +01:00
2013-11-07 05:49:04 +01:00
r = sd_bus_call_method (
2012-08-08 01:32:30 +02:00
bus ,
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
" ListJobs " ,
2013-11-07 05:49:04 +01:00
& error ,
2012-08-08 01:32:30 +02:00
& reply ,
2013-11-07 05:49:04 +01:00
NULL ) ;
if ( r < 0 ) {
log_error ( " Failed to list jobs: %s " , bus_error_message ( & error , r ) ) ;
2013-01-14 02:11:22 +01:00
return r ;
2010-06-15 02:51:55 +02:00
}
2013-11-07 05:49:04 +01:00
r = sd_bus_message_enter_container ( reply , ' a ' , " (usssoo) " ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2010-06-15 02:51:55 +02:00
2013-11-07 05:49:04 +01:00
while ( ( r = sd_bus_message_read ( reply , " (usssoo) " , & id , & name , & type , & state , & job_path , & unit_path ) ) > 0 ) {
2010-07-20 20:33:19 +02:00
2013-11-07 05:49:04 +01:00
if ( ! GREEDY_REALLOC ( jobs , size , c + 1 ) )
return log_oom ( ) ;
2010-06-15 02:51:55 +02:00
2013-11-07 05:49:04 +01:00
jobs [ c + + ] = ( struct job_info ) {
id ,
name ,
type ,
state
} ;
2010-06-15 02:51:55 +02:00
}
2013-11-07 05:49:04 +01:00
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2010-06-15 02:51:55 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_exit_container ( reply ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2010-08-31 16:56:08 +02:00
2013-11-07 05:49:04 +01:00
output_jobs_list ( jobs , c ) ;
2013-11-06 11:18:02 +01:00
return r ;
2010-06-15 02:51:55 +02:00
}
2013-11-07 05:49:04 +01:00
static int cancel_job ( sd_bus * bus , char * * args ) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL ;
2011-07-25 04:58:02 +02:00
char * * name ;
2010-06-15 02:51:55 +02:00
2010-06-18 04:22:59 +02:00
assert ( args ) ;
2011-07-25 04:58:02 +02:00
if ( strv_length ( args ) < = 1 )
return daemon_reload ( bus , args ) ;
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
STRV_FOREACH ( name , args + 1 ) {
2013-01-10 22:45:45 +01:00
uint32_t id ;
int r ;
2010-06-15 02:51:55 +02:00
2013-01-10 22:45:45 +01:00
r = safe_atou32 ( * name , & id ) ;
2012-08-08 01:32:30 +02:00
if ( r < 0 ) {
2013-11-07 05:49:04 +01:00
log_error ( " Failed to parse job id \" %s \" : %s " , * name , strerror ( - r ) ) ;
2013-01-10 22:45:45 +01:00
return r ;
2010-06-15 02:51:55 +02:00
}
2013-11-07 05:49:04 +01:00
r = sd_bus_call_method (
2012-08-08 01:32:30 +02:00
bus ,
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
2013-01-10 22:45:45 +01:00
" CancelJob " ,
2013-11-07 05:49:04 +01:00
& error ,
2012-08-08 01:32:30 +02:00
NULL ,
2013-11-07 05:49:04 +01:00
" u " , id ) ;
if ( r < 0 ) {
log_error ( " Failed to cancel job %u: %s " , ( unsigned ) id , bus_error_message ( & error , r ) ) ;
2013-01-10 22:45:45 +01:00
return r ;
2013-11-07 05:49:04 +01:00
}
2010-06-15 02:51:55 +02:00
}
2013-01-10 22:45:45 +01:00
return 0 ;
2010-06-15 02:51:55 +02:00
}
2013-11-07 05:49:04 +01:00
static int need_daemon_reload ( sd_bus * bus , const char * unit ) {
_cleanup_bus_message_unref_ sd_bus_message * reply = NULL ;
2013-01-14 02:11:22 +01:00
_cleanup_free_ char * n = NULL ;
2013-11-07 05:49:04 +01:00
const char * path ;
int b , r ;
2013-07-10 20:37:19 +02:00
2013-11-07 05:49:04 +01:00
/* We ignore all errors here, since this is used to show a
* warning only */
2010-07-17 00:57:51 +02:00
2012-06-22 13:08:48 +02:00
n = unit_name_mangle ( unit ) ;
2013-01-15 11:58:42 +01:00
if ( ! n )
2013-11-07 05:49:04 +01:00
return - ENOMEM ;
/* We don't use unit_dbus_path_from_name() directly since we
* don ' t want to load the unit if it isn ' t loaded . */
2013-01-14 02:11:22 +01:00
2013-11-07 05:49:04 +01:00
r = sd_bus_call_method (
2012-08-08 01:32:30 +02:00
bus ,
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
" GetUnit " ,
2013-11-07 05:49:04 +01:00
NULL ,
2012-08-08 01:32:30 +02:00
& reply ,
2013-11-07 05:49:04 +01:00
" s " , n ) ;
2013-01-14 02:11:22 +01:00
if ( r < 0 )
return r ;
2010-07-17 00:57:51 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_read ( reply , " o " , & path ) ;
if ( r < 0 )
return r ;
2013-01-14 02:11:22 +01:00
2013-11-07 05:49:04 +01:00
r = sd_bus_get_property_trivial (
2012-08-08 01:32:30 +02:00
bus ,
2012-06-22 13:08:48 +02:00
" org.freedesktop.systemd1 " ,
path ,
2013-11-07 05:49:04 +01:00
" org.freedesktop.systemd1.Unit " ,
" NeedDaemonReload " ,
NULL ,
' b ' , & b ) ;
2013-01-14 02:11:22 +01:00
if ( r < 0 )
return r ;
2010-07-17 00:57:51 +02:00
return b ;
}
2010-07-01 03:44:09 +02:00
typedef struct WaitData {
Set * set ;
2012-09-14 15:11:07 +02:00
char * name ;
2011-02-24 02:36:34 +01:00
char * result ;
2010-07-01 03:44:09 +02:00
} WaitData ;
2013-11-07 05:49:04 +01:00
static int wait_filter ( sd_bus * bus , sd_bus_message * m , void * data ) {
2010-07-01 03:44:09 +02:00
WaitData * d = data ;
2010-06-15 02:51:55 +02:00
2013-11-07 05:49:04 +01:00
assert ( bus ) ;
assert ( m ) ;
2010-07-01 03:44:09 +02:00
assert ( d ) ;
2010-06-15 02:51:55 +02:00
2010-07-07 17:57:54 +02:00
log_debug ( " Got D-Bus request: %s.%s() on %s " ,
2013-11-07 05:49:04 +01:00
sd_bus_message_get_interface ( m ) ,
sd_bus_message_get_member ( m ) ,
sd_bus_message_get_path ( m ) ) ;
2010-06-15 02:51:55 +02:00
2013-11-07 05:49:04 +01:00
if ( sd_bus_message_is_signal ( m , " org.freedesktop.DBus.Local " , " Disconnected " ) ) {
2010-06-15 02:51:55 +02:00
log_error ( " Warning! D-Bus connection terminated. " ) ;
2013-11-07 05:49:04 +01:00
sd_bus_close ( bus ) ;
} else if ( sd_bus_message_is_signal ( m , " org.freedesktop.systemd1.Manager " , " JobRemoved " ) ) {
2010-06-15 02:51:55 +02:00
uint32_t id ;
2013-09-12 23:37:23 +02:00
const char * path , * result , * unit ;
2013-11-07 05:49:04 +01:00
char * ret ;
int r ;
2010-06-15 02:51:55 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_read ( m , " uoss " , & id , & path , & unit , & result ) ;
if ( r > = 0 ) {
ret = set_remove ( d - > set , ( char * ) path ) ;
if ( ! ret )
return 0 ;
2013-09-12 15:42:24 +02:00
2013-11-07 05:49:04 +01:00
free ( ret ) ;
2011-02-24 02:36:34 +01:00
2012-09-14 15:11:07 +02:00
if ( ! isempty ( result ) )
2011-02-24 02:36:34 +01:00
d - > result = strdup ( result ) ;
2012-09-14 15:11:07 +02:00
if ( ! isempty ( unit ) )
d - > name = strdup ( unit ) ;
2013-11-07 05:49:04 +01:00
return 0 ;
2011-02-24 02:36:34 +01:00
}
2013-07-03 09:38:35 +02:00
# ifndef NOLEGACY
2013-11-07 05:49:04 +01:00
r = sd_bus_message_read ( m , " uos " , & id , & path , & result ) ;
if ( r > = 0 ) {
ret = set_remove ( d - > set , ( char * ) path ) ;
if ( ! ret )
return 0 ;
free ( ret ) ;
2011-02-24 02:36:34 +01:00
2012-05-03 22:53:25 +02:00
if ( * result )
d - > result = strdup ( result ) ;
2013-11-07 05:49:04 +01:00
return 0 ;
2012-05-03 22:53:25 +02:00
}
2011-02-24 02:36:34 +01:00
# endif
2013-11-07 05:49:04 +01:00
log_error ( " Failed to parse message. " ) ;
2010-06-15 02:51:55 +02:00
}
2013-11-07 05:49:04 +01:00
return 0 ;
2010-06-15 02:51:55 +02:00
}
2013-11-07 05:49:04 +01:00
static int enable_wait_for_jobs ( sd_bus * bus ) {
int r ;
2010-06-15 02:51:55 +02:00
assert ( bus ) ;
2013-11-07 05:49:04 +01:00
r = sd_bus_add_match (
bus ,
" type='signal', "
" sender='org.freedesktop.systemd1', "
" interface='org.freedesktop.systemd1.Manager', "
" member='JobRemoved', "
" path='/org/freedesktop/systemd1' " ,
NULL , NULL ) ;
if ( r < 0 ) {
log_error ( " Failed to add match " ) ;
2010-07-05 00:58:07 +02:00
return - EIO ;
2010-06-15 02:51:55 +02:00
}
2010-06-15 04:24:30 +02:00
/* This is slightly dirty, since we don't undo the match registrations. */
2010-07-05 00:58:07 +02:00
return 0 ;
2010-06-15 02:51:55 +02:00
}
2013-11-07 05:49:04 +01:00
static int wait_for_jobs ( sd_bus * bus , Set * s ) {
2013-03-25 00:59:00 +01:00
WaitData d = { . set = s } ;
2013-11-07 05:49:04 +01:00
int r ;
2010-06-15 04:24:30 +02:00
assert ( bus ) ;
assert ( s ) ;
2013-11-07 05:49:04 +01:00
r = sd_bus_add_filter ( bus , wait_filter , & d ) ;
if ( r < 0 )
2012-09-14 15:11:07 +02:00
return log_oom ( ) ;
2010-06-15 04:24:30 +02:00
2012-09-14 15:11:07 +02:00
while ( ! set_isempty ( s ) ) {
2013-11-07 05:49:04 +01:00
for ( ; ; ) {
r = sd_bus_process ( bus , NULL ) ;
if ( r < 0 )
return r ;
if ( r > 0 )
break ;
r = sd_bus_wait ( bus , ( uint64_t ) - 1 ) ;
if ( r < 0 )
return r ;
2012-09-14 15:11:07 +02:00
}
2011-02-24 03:24:51 +01:00
2012-09-19 08:15:07 +02:00
if ( ! d . result )
goto free_name ;
if ( ! arg_quiet ) {
2012-09-14 15:11:07 +02:00
if ( streq ( d . result , " timeout " ) )
log_error ( " Job for %s timed out. " , strna ( d . name ) ) ;
else if ( streq ( d . result , " canceled " ) )
log_error ( " Job for %s canceled. " , strna ( d . name ) ) ;
else if ( streq ( d . result , " dependency " ) )
2012-11-16 03:03:54 +01:00
log_error ( " A dependency job for %s failed. See 'journalctl -xn' for details. " , strna ( d . name ) ) ;
2012-09-14 15:11:07 +02:00
else if ( ! streq ( d . result , " done " ) & & ! streq ( d . result , " skipped " ) )
2012-11-16 03:03:54 +01:00
log_error ( " Job for %s failed. See 'systemctl status %s' and 'journalctl -xn' for details. " , strna ( d . name ) , strna ( d . name ) ) ;
2012-09-14 15:11:07 +02:00
}
2010-06-15 04:24:30 +02:00
2012-09-14 15:11:07 +02:00
if ( streq_ptr ( d . result , " timeout " ) )
r = - ETIME ;
else if ( streq_ptr ( d . result , " canceled " ) )
r = - ECANCELED ;
else if ( ! streq_ptr ( d . result , " done " ) & & ! streq_ptr ( d . result , " skipped " ) )
r = - EIO ;
free ( d . result ) ;
d . result = NULL ;
2012-09-19 08:15:07 +02:00
free_name :
2012-09-14 15:11:07 +02:00
free ( d . name ) ;
d . name = NULL ;
}
2010-06-15 04:24:30 +02:00
2013-11-07 05:49:04 +01:00
return sd_bus_remove_filter ( bus , wait_filter , & d ) ;
2010-06-15 04:24:30 +02:00
}
2013-11-07 05:49:04 +01:00
static int check_one_unit ( sd_bus * bus , const char * name , const char * good_states , bool quiet ) {
_cleanup_bus_message_unref_ sd_bus_message * reply = NULL ;
_cleanup_free_ char * n = NULL , * state = NULL ;
const char * path ;
2012-08-08 01:32:30 +02:00
int r ;
2012-06-13 14:14:13 +02:00
2012-06-13 17:29:11 +02:00
assert ( name ) ;
2012-06-13 14:14:13 +02:00
2012-08-08 01:32:30 +02:00
n = unit_name_mangle ( name ) ;
2013-01-11 23:59:41 +01:00
if ( ! n )
return log_oom ( ) ;
2013-11-07 05:49:04 +01:00
/* We don't use unit_dbus_path_from_name() directly since we
* don ' t want to load the unit if it isn ' t loaded . */
r = sd_bus_call_method (
2012-08-08 01:32:30 +02:00
bus ,
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
" GetUnit " ,
2013-11-07 05:49:04 +01:00
NULL ,
2012-08-08 01:32:30 +02:00
& reply ,
2013-11-07 05:49:04 +01:00
" s " , n ) ;
2013-01-11 23:59:41 +01:00
if ( r < 0 ) {
if ( ! quiet )
2012-08-08 01:32:30 +02:00
puts ( " unknown " ) ;
2013-01-11 23:59:41 +01:00
return 0 ;
2012-08-08 01:32:30 +02:00
}
2012-06-13 15:52:27 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_read ( reply , " o " , & path ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2013-01-11 23:59:41 +01:00
2013-11-07 05:49:04 +01:00
r = sd_bus_get_property_string (
2012-08-08 01:32:30 +02:00
bus ,
" org.freedesktop.systemd1 " ,
path ,
2013-11-07 05:49:04 +01:00
" org.freedesktop.systemd1.Unit " ,
" ActiveState " ,
2012-08-08 01:32:30 +02:00
NULL ,
2013-11-07 05:49:04 +01:00
& state ) ;
2013-01-11 23:59:41 +01:00
if ( r < 0 ) {
if ( ! quiet )
puts ( " unknown " ) ;
return 0 ;
}
2012-06-13 14:14:13 +02:00
2012-06-13 17:29:11 +02:00
if ( ! quiet )
puts ( state ) ;
2013-11-07 05:49:04 +01:00
return nulstr_contains ( good_states , state ) ;
2012-06-13 14:14:13 +02:00
}
2013-11-07 05:49:04 +01:00
static int check_triggering_units (
sd_bus * bus ,
const char * name ) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL ;
_cleanup_free_ char * path = NULL , * n = NULL , * state = NULL ;
_cleanup_strv_free_ char * * triggered_by = NULL ;
2012-06-13 15:52:27 +02:00
bool print_warning_label = true ;
2013-11-07 05:49:04 +01:00
char * * i ;
2012-08-08 01:32:30 +02:00
int r ;
2012-06-13 14:14:13 +02:00
2013-11-07 05:49:04 +01:00
n = unit_name_mangle ( name ) ;
if ( ! n )
return log_oom ( ) ;
2012-09-18 20:22:57 +02:00
2013-11-07 05:49:04 +01:00
path = unit_dbus_path_from_name ( n ) ;
if ( ! path )
return log_oom ( ) ;
2012-06-13 14:14:13 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_get_property_string (
2013-02-15 16:10:36 +01:00
bus ,
" org.freedesktop.systemd1 " ,
2013-11-07 05:49:04 +01:00
path ,
" org.freedesktop.systemd1.Unit " ,
" LoadState " ,
& error ,
& state ) ;
if ( r < 0 ) {
log_error ( " Failed to get load state of %s: %s " , n , bus_error_message ( & error , r ) ) ;
return r ;
2013-02-15 16:10:36 +01:00
}
if ( streq ( state , " masked " ) )
2013-11-07 05:49:04 +01:00
return 0 ;
2012-06-13 14:14:13 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_get_property_strv (
bus ,
" org.freedesktop.systemd1 " ,
path ,
" org.freedesktop.systemd1.Unit " ,
" TriggeredBy " ,
& error ,
& triggered_by ) ;
if ( r < 0 ) {
log_error ( " Failed to get triggered by array of %s: %s " , n , bus_error_message ( & error , r ) ) ;
return r ;
}
2012-06-13 14:14:13 +02:00
2013-11-07 05:49:04 +01:00
STRV_FOREACH ( i , triggered_by ) {
r = check_one_unit ( bus , * i , " active \0 reloading \0 " , true ) ;
if ( r < 0 ) {
log_error ( " Failed to check unit: %s " , strerror ( - r ) ) ;
return r ;
2012-06-13 14:14:13 +02:00
}
2013-11-07 05:49:04 +01:00
if ( r = = 0 )
continue ;
2013-01-11 23:59:41 +01:00
2013-11-07 05:49:04 +01:00
if ( print_warning_label ) {
log_warning ( " Warning: Stopping %s, but it can still be activated by: " , n ) ;
print_warning_label = false ;
2012-06-13 14:14:13 +02:00
}
2012-06-13 18:27:41 +02:00
2013-11-07 05:49:04 +01:00
log_warning ( " %s " , * i ) ;
2012-06-13 14:14:13 +02:00
}
2013-11-07 05:49:04 +01:00
return 0 ;
2012-06-13 14:14:13 +02:00
}
2010-06-17 22:57:28 +02:00
static int start_unit_one (
2013-11-07 05:49:04 +01:00
sd_bus * bus ,
2010-06-17 22:57:28 +02:00
const char * method ,
const char * name ,
const char * mode ,
2013-11-07 05:49:04 +01:00
sd_bus_error * error ,
2010-06-17 22:57:28 +02:00
Set * s ) {
2010-06-15 02:51:55 +02:00
2013-11-07 05:49:04 +01:00
_cleanup_bus_message_unref_ sd_bus_message * reply = NULL ;
2013-01-14 02:11:22 +01:00
_cleanup_free_ char * n ;
2010-07-17 00:57:51 +02:00
const char * path ;
2010-06-15 02:51:55 +02:00
int r ;
2010-06-17 22:57:28 +02:00
assert ( method ) ;
assert ( name ) ;
assert ( mode ) ;
2010-08-31 21:05:54 +02:00
assert ( error ) ;
2010-06-15 02:51:55 +02:00
2012-08-08 01:32:30 +02:00
n = unit_name_mangle ( name ) ;
2012-09-14 15:11:07 +02:00
if ( ! n )
return log_oom ( ) ;
2013-11-07 05:49:04 +01:00
r = sd_bus_call_method (
2012-08-08 01:32:30 +02:00
bus ,
2012-06-22 13:08:48 +02:00
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
2012-08-08 01:32:30 +02:00
method ,
error ,
2013-11-07 05:49:04 +01:00
& reply ,
" ss " , n , mode ) ;
if ( r < 0 ) {
2012-09-14 15:11:07 +02:00
if ( r = = - ENOENT & & arg_action ! = ACTION_SYSTEMCTL )
2010-06-17 22:57:28 +02:00
/* There's always a fallback possible for
* legacy actions . */
2013-11-07 05:49:04 +01:00
return - EADDRNOTAVAIL ;
2012-09-14 15:11:07 +02:00
2013-11-07 05:49:04 +01:00
log_error ( " Failed to start %s: %s " , name , bus_error_message ( error , r ) ) ;
2012-09-18 20:37:15 +02:00
return r ;
2010-06-15 02:51:55 +02:00
}
2013-11-07 05:49:04 +01:00
r = sd_bus_message_read ( reply , " o " , & path ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2010-07-17 00:57:51 +02:00
2013-07-10 20:37:19 +02:00
if ( need_daemon_reload ( bus , n ) > 0 )
2013-11-07 05:49:04 +01:00
log_warning ( " Warning: Unit file of %s changed on disk, 'systemctl%s daemon-reload' recommended. " ,
n , arg_scope = = UNIT_FILE_SYSTEM ? " " : " --user " ) ;
2010-07-17 00:57:51 +02:00
2012-09-14 15:11:07 +02:00
if ( s ) {
2013-01-14 02:11:22 +01:00
char * p ;
2012-09-14 15:11:07 +02:00
p = strdup ( path ) ;
2012-09-18 20:37:15 +02:00
if ( ! p )
return log_oom ( ) ;
2010-06-15 02:51:55 +02:00
2013-04-23 05:12:15 +02:00
r = set_consume ( s , p ) ;
2013-11-08 13:54:46 +01:00
if ( r < 0 )
return log_oom ( ) ;
2010-06-17 22:57:28 +02:00
}
2010-06-15 02:51:55 +02:00
2012-09-18 20:37:15 +02:00
return 0 ;
2010-06-15 02:51:55 +02:00
}
2013-02-22 13:37:57 +01:00
static const struct {
const char * target ;
const char * verb ;
const char * mode ;
} action_table [ _ACTION_MAX ] = {
[ ACTION_HALT ] = { SPECIAL_HALT_TARGET , " halt " , " replace-irreversibly " } ,
[ ACTION_POWEROFF ] = { SPECIAL_POWEROFF_TARGET , " poweroff " , " replace-irreversibly " } ,
[ ACTION_REBOOT ] = { SPECIAL_REBOOT_TARGET , " reboot " , " replace-irreversibly " } ,
[ ACTION_KEXEC ] = { SPECIAL_KEXEC_TARGET , " kexec " , " replace-irreversibly " } ,
[ ACTION_RUNLEVEL2 ] = { SPECIAL_RUNLEVEL2_TARGET , NULL , " isolate " } ,
[ ACTION_RUNLEVEL3 ] = { SPECIAL_RUNLEVEL3_TARGET , NULL , " isolate " } ,
[ ACTION_RUNLEVEL4 ] = { SPECIAL_RUNLEVEL4_TARGET , NULL , " isolate " } ,
[ ACTION_RUNLEVEL5 ] = { SPECIAL_RUNLEVEL5_TARGET , NULL , " isolate " } ,
[ ACTION_RESCUE ] = { SPECIAL_RESCUE_TARGET , " rescue " , " isolate " } ,
[ ACTION_EMERGENCY ] = { SPECIAL_EMERGENCY_TARGET , " emergency " , " isolate " } ,
[ ACTION_DEFAULT ] = { SPECIAL_DEFAULT_TARGET , " default " , " isolate " } ,
[ ACTION_EXIT ] = { SPECIAL_EXIT_TARGET , " exit " , " replace-irreversibly " } ,
[ ACTION_SUSPEND ] = { SPECIAL_SUSPEND_TARGET , " suspend " , " replace-irreversibly " } ,
[ ACTION_HIBERNATE ] = { SPECIAL_HIBERNATE_TARGET , " hibernate " , " replace-irreversibly " } ,
[ ACTION_HYBRID_SLEEP ] = { SPECIAL_HYBRID_SLEEP_TARGET , " hybrid-sleep " , " replace-irreversibly " } ,
} ;
2010-06-18 04:22:59 +02:00
static enum action verb_to_action ( const char * verb ) {
2013-02-22 13:37:57 +01:00
enum action i ;
2013-11-07 05:49:04 +01:00
for ( i = _ACTION_INVALID ; i < _ACTION_MAX ; i + + )
if ( streq_ptr ( action_table [ i ] . verb , verb ) )
2013-02-22 13:37:57 +01:00
return i ;
2010-06-18 04:22:59 +02:00
2013-11-07 05:49:04 +01:00
return _ACTION_INVALID ;
}
2010-06-17 22:57:28 +02:00
2013-11-07 05:49:04 +01:00
static int start_unit ( sd_bus * bus , char * * args ) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL ;
2013-04-18 09:11:22 +02:00
_cleanup_set_free_free_ Set * s = NULL ;
2013-11-07 05:49:04 +01:00
const char * method , * mode , * one_name ;
2011-07-25 04:58:02 +02:00
char * * name ;
2013-11-07 05:49:04 +01:00
int r ;
2010-06-17 22:57:28 +02:00
2010-06-18 04:22:59 +02:00
assert ( bus ) ;
2012-04-11 18:50:16 +02:00
ask_password_agent_open_if_enabled ( ) ;
2010-10-26 05:29:39 +02:00
2010-06-17 22:57:28 +02:00
if ( arg_action = = ACTION_SYSTEMCTL ) {
2013-02-22 13:37:57 +01:00
enum action action ;
2010-06-17 22:57:28 +02:00
method =
2011-03-17 03:41:51 +01:00
streq ( args [ 0 ] , " stop " ) | |
streq ( args [ 0 ] , " condstop " ) ? " StopUnit " :
2010-07-13 20:20:36 +02:00
streq ( args [ 0 ] , " reload " ) ? " ReloadUnit " :
streq ( args [ 0 ] , " restart " ) ? " RestartUnit " :
2011-03-08 01:44:19 +01:00
2010-09-20 20:45:08 +02:00
streq ( args [ 0 ] , " try-restart " ) | |
streq ( args [ 0 ] , " condrestart " ) ? " TryRestartUnit " :
2011-03-08 01:44:19 +01:00
2010-07-13 20:20:36 +02:00
streq ( args [ 0 ] , " reload-or-restart " ) ? " ReloadOrRestartUnit " :
2011-03-08 01:44:19 +01:00
2010-07-23 05:24:45 +02:00
streq ( args [ 0 ] , " reload-or-try-restart " ) | |
2013-11-08 13:54:46 +01:00
streq ( args [ 0 ] , " condreload " ) | |
2010-09-20 20:45:08 +02:00
streq ( args [ 0 ] , " force-reload " ) ? " ReloadOrTryRestartUnit " :
2010-07-13 20:20:36 +02:00
" StartUnit " ;
2013-02-22 13:37:57 +01:00
action = verb_to_action ( args [ 0 ] ) ;
2010-06-17 22:57:28 +02:00
2013-02-22 13:37:57 +01:00
mode = streq ( args [ 0 ] , " isolate " ) ? " isolate " :
action_table [ action ] . mode ? : arg_job_mode ;
2010-06-17 22:57:28 +02:00
2013-02-22 13:37:57 +01:00
one_name = action_table [ action ] . target ;
2010-06-17 22:57:28 +02:00
} else {
2013-02-22 13:37:57 +01:00
assert ( arg_action < ELEMENTSOF ( action_table ) ) ;
assert ( action_table [ arg_action ] . target ) ;
2010-06-17 22:57:28 +02:00
method = " StartUnit " ;
2010-06-18 04:22:59 +02:00
2013-02-22 13:37:57 +01:00
mode = action_table [ arg_action ] . mode ;
one_name = action_table [ arg_action ] . target ;
2010-06-18 04:22:59 +02:00
}
2010-07-01 00:32:29 +02:00
if ( ! arg_no_block ) {
2013-11-07 05:49:04 +01:00
r = enable_wait_for_jobs ( bus ) ;
if ( r < 0 ) {
log_error ( " Could not watch jobs: %s " , strerror ( - r ) ) ;
return r ;
2010-06-18 04:22:59 +02:00
}
2012-09-14 15:11:07 +02:00
s = set_new ( string_hash_func , string_compare_func ) ;
2013-02-14 19:32:19 +01:00
if ( ! s )
return log_oom ( ) ;
2010-06-17 22:57:28 +02:00
}
2010-06-18 04:22:59 +02:00
if ( one_name ) {
2013-11-07 05:49:04 +01:00
r = start_unit_one ( bus , method , one_name , mode , & error , s ) ;
if ( r < 0 )
r = translate_bus_error_to_exit_status ( r , & error ) ;
2010-06-18 04:22:59 +02:00
} else {
2013-11-07 05:49:04 +01:00
r = 0 ;
2012-09-14 15:11:07 +02:00
STRV_FOREACH ( name , args + 1 ) {
2013-11-07 05:49:04 +01:00
int q ;
q = start_unit_one ( bus , method , * name , mode , & error , s ) ;
if ( q < 0 ) {
r = translate_bus_error_to_exit_status ( r , & error ) ;
sd_bus_error_free ( & error ) ;
2010-08-31 21:05:54 +02:00
}
2012-09-14 15:11:07 +02:00
}
2010-06-17 22:57:28 +02:00
}
2012-09-14 15:11:07 +02:00
if ( ! arg_no_block ) {
2013-11-07 05:49:04 +01:00
int q ;
q = wait_for_jobs ( bus , s ) ;
if ( q < 0 )
return q ;
2012-09-18 22:03:34 +02:00
/* When stopping units, warn if they can still be triggered by
* another active unit ( socket , path , timer ) */
if ( ! arg_quiet & & streq ( method , " StopUnit " ) ) {
if ( one_name )
check_triggering_units ( bus , one_name ) ;
else
STRV_FOREACH ( name , args + 1 )
check_triggering_units ( bus , * name ) ;
}
2012-09-14 15:11:07 +02:00
}
2010-06-18 04:22:59 +02:00
2013-11-07 05:49:04 +01:00
return r ;
2010-06-17 22:57:28 +02:00
}
2012-04-11 00:36:44 +02:00
/* Ask systemd-logind, which might grant access to unprivileged users
* through PolicyKit */
2013-11-07 05:49:04 +01:00
static int reboot_with_logind ( sd_bus * bus , enum action a ) {
2012-02-29 22:22:15 +01:00
# ifdef HAVE_LOGIND
2013-11-07 05:49:04 +01:00
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL ;
2012-02-29 22:22:15 +01:00
const char * method ;
2013-11-07 05:49:04 +01:00
int r ;
2012-02-29 22:22:15 +01:00
2013-01-12 00:00:22 +01:00
if ( ! bus )
return - EIO ;
2012-04-11 18:50:16 +02:00
polkit_agent_open_if_enabled ( ) ;
2012-02-29 22:22:15 +01:00
switch ( a ) {
case ACTION_REBOOT :
method = " Reboot " ;
break ;
case ACTION_POWEROFF :
method = " PowerOff " ;
break ;
2012-05-08 19:02:25 +02:00
case ACTION_SUSPEND :
method = " Suspend " ;
break ;
case ACTION_HIBERNATE :
method = " Hibernate " ;
break ;
2012-10-28 00:49:04 +02:00
case ACTION_HYBRID_SLEEP :
method = " HybridSleep " ;
break ;
2012-02-29 22:22:15 +01:00
default :
return - EINVAL ;
}
2013-11-07 05:49:04 +01:00
r = sd_bus_call_method (
2012-08-08 01:32:30 +02:00
bus ,
" org.freedesktop.login1 " ,
" /org/freedesktop/login1 " ,
" org.freedesktop.login1.Manager " ,
method ,
2013-11-07 05:49:04 +01:00
& error ,
2012-08-08 01:32:30 +02:00
NULL ,
2013-11-07 05:49:04 +01:00
" b " , true ) ;
if ( r < 0 )
log_error ( " Failed to execute operation: %s " , bus_error_message ( & error , r ) ) ;
return r ;
2012-02-29 22:22:15 +01:00
# else
return - ENOSYS ;
# endif
}
2013-11-07 05:49:04 +01:00
static int check_inhibitors ( sd_bus * bus , enum action a ) {
2013-01-11 04:24:05 +01:00
# ifdef HAVE_LOGIND
2013-11-07 05:49:04 +01:00
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL ;
_cleanup_bus_message_unref_ sd_bus_message * reply = NULL ;
2013-01-15 03:00:43 +01:00
_cleanup_strv_free_ char * * sessions = NULL ;
2013-11-07 05:49:04 +01:00
const char * what , * who , * why , * mode ;
uint32_t uid , pid ;
unsigned c = 0 ;
2013-01-15 03:00:43 +01:00
char * * s ;
2013-11-07 05:49:04 +01:00
int r ;
2013-01-11 04:24:05 +01:00
2013-01-12 00:09:22 +01:00
if ( ! bus )
return 0 ;
if ( arg_ignore_inhibitors | | arg_force > 0 )
return 0 ;
if ( arg_when > 0 )
return 0 ;
if ( geteuid ( ) = = 0 )
2013-01-11 04:24:05 +01:00
return 0 ;
if ( ! on_tty ( ) )
return 0 ;
2013-11-07 05:49:04 +01:00
r = sd_bus_call_method (
2013-01-11 04:24:05 +01:00
bus ,
" org.freedesktop.login1 " ,
" /org/freedesktop/login1 " ,
" org.freedesktop.login1.Manager " ,
" ListInhibitors " ,
NULL ,
2013-11-07 05:49:04 +01:00
& reply ,
NULL ) ;
2013-01-11 04:24:05 +01:00
if ( r < 0 )
/* If logind is not around, then there are no inhibitors... */
return 0 ;
2013-11-08 17:49:59 +01:00
r = sd_bus_message_enter_container ( reply , SD_BUS_TYPE_ARRAY , " (ssssuu) " ) ;
2013-11-07 05:49:04 +01:00
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2013-01-11 04:24:05 +01:00
2013-11-08 17:49:59 +01:00
while ( ( r = sd_bus_message_read ( reply , " (ssssuu) " , & what , & who , & why , & mode , & uid , & pid ) ) > 0 ) {
2013-01-15 03:00:43 +01:00
_cleanup_free_ char * comm = NULL , * user = NULL ;
2013-11-07 05:49:04 +01:00
_cleanup_strv_free_ char * * sv = NULL ;
2013-01-11 04:24:05 +01:00
if ( ! streq ( mode , " block " ) )
2013-11-07 05:49:04 +01:00
continue ;
2013-01-11 04:24:05 +01:00
sv = strv_split ( what , " : " ) ;
if ( ! sv )
return log_oom ( ) ;
if ( ! strv_contains ( sv ,
a = = ACTION_HALT | |
a = = ACTION_POWEROFF | |
a = = ACTION_REBOOT | |
a = = ACTION_KEXEC ? " shutdown " : " sleep " ) )
2013-11-07 05:49:04 +01:00
continue ;
2013-01-11 04:24:05 +01:00
get_process_comm ( pid , & comm ) ;
2013-01-15 03:00:43 +01:00
user = uid_to_name ( uid ) ;
2013-11-07 05:49:04 +01:00
2013-01-15 03:00:43 +01:00
log_warning ( " Operation inhibited by \" %s \" (PID %lu \" %s \" , user %s), reason is \" %s \" . " ,
who , ( unsigned long ) pid , strna ( comm ) , strna ( user ) , why ) ;
2013-01-11 04:24:05 +01:00
2013-11-07 05:49:04 +01:00
c + + ;
2013-01-11 04:24:05 +01:00
}
2013-11-07 05:49:04 +01:00
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2013-01-11 04:24:05 +01:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_exit_container ( reply ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2013-01-11 04:24:05 +01:00
2013-01-15 03:00:43 +01:00
/* Check for current sessions */
sd_get_sessions ( & sessions ) ;
STRV_FOREACH ( s , sessions ) {
_cleanup_free_ char * type = NULL , * tty = NULL , * seat = NULL , * user = NULL , * service = NULL , * class = NULL ;
if ( sd_session_get_uid ( * s , & uid ) < 0 | | uid = = getuid ( ) )
continue ;
if ( sd_session_get_class ( * s , & class ) < 0 | | ! streq ( class , " user " ) )
continue ;
if ( sd_session_get_type ( * s , & type ) < 0 | | ( ! streq ( type , " x11 " ) & & ! streq ( type , " tty " ) ) )
continue ;
sd_session_get_tty ( * s , & tty ) ;
sd_session_get_seat ( * s , & seat ) ;
sd_session_get_service ( * s , & service ) ;
user = uid_to_name ( uid ) ;
log_warning ( " User %s is logged in on %s. " , strna ( user ) , isempty ( tty ) ? ( isempty ( seat ) ? strna ( service ) : seat ) : tty ) ;
c + + ;
}
2013-01-11 04:24:05 +01:00
if ( c < = 0 )
return 0 ;
2013-01-15 03:00:43 +01:00
log_error ( " Please retry operation after closing inhibitors and logging out other users. \n Alternatively, ignore inhibitors and users with 'systemctl %s -i'. " ,
2013-02-22 13:37:57 +01:00
action_table [ a ] . verb ) ;
2013-01-11 04:24:05 +01:00
return - EPERM ;
# else
return 0 ;
# endif
}
2013-11-07 05:49:04 +01:00
static int start_special ( sd_bus * bus , char * * args ) {
2012-02-29 22:22:15 +01:00
enum action a ;
2010-07-11 04:22:00 +02:00
int r ;
2010-06-18 04:22:59 +02:00
assert ( args ) ;
2012-02-29 22:22:15 +01:00
a = verb_to_action ( args [ 0 ] ) ;
2013-01-12 00:09:22 +01:00
r = check_inhibitors ( bus , a ) ;
if ( r < 0 )
return r ;
2012-05-03 16:17:58 +02:00
if ( arg_force > = 2 & & geteuid ( ) ! = 0 ) {
log_error ( " Must be root. " ) ;
return - EPERM ;
}
2012-04-11 00:36:44 +02:00
if ( arg_force > = 2 & &
( a = = ACTION_HALT | |
a = = ACTION_POWEROFF | |
a = = ACTION_REBOOT ) )
halt_now ( a ) ;
2012-02-15 20:05:49 +01:00
2012-04-11 00:36:44 +02:00
if ( arg_force > = 1 & &
2012-02-29 22:22:15 +01:00
( a = = ACTION_HALT | |
a = = ACTION_POWEROFF | |
a = = ACTION_REBOOT | |
a = = ACTION_KEXEC | |
a = = ACTION_EXIT ) )
2011-07-25 04:58:02 +02:00
return daemon_reload ( bus , args ) ;
2010-10-14 00:56:12 +02:00
2012-04-11 00:36:44 +02:00
/* first try logind, to allow authentication with polkit */
if ( geteuid ( ) ! = 0 & &
( a = = ACTION_POWEROFF | |
2012-05-08 19:02:25 +02:00
a = = ACTION_REBOOT | |
a = = ACTION_SUSPEND | |
2012-10-28 00:49:04 +02:00
a = = ACTION_HIBERNATE | |
a = = ACTION_HYBRID_SLEEP ) ) {
2012-04-11 00:36:44 +02:00
r = reboot_with_logind ( bus , a ) ;
if ( r > = 0 )
return r ;
2012-02-29 22:22:15 +01:00
}
2010-07-11 04:22:00 +02:00
2012-02-29 22:22:15 +01:00
r = start_unit ( bus , args ) ;
2013-02-14 20:08:09 +01:00
if ( r = = EXIT_SUCCESS )
2012-02-29 22:22:15 +01:00
warn_wall ( a ) ;
2010-06-18 04:22:59 +02:00
2010-07-11 04:22:00 +02:00
return r ;
2010-06-18 04:22:59 +02:00
}
2013-11-07 05:49:04 +01:00
static int check_unit_active ( sd_bus * bus , char * * args ) {
2011-07-25 04:58:02 +02:00
char * * name ;
2012-06-13 17:29:11 +02:00
int r = 3 ; /* According to LSB: "program is not running" */
2010-07-01 01:06:58 +02:00
assert ( bus ) ;
assert ( args ) ;
2011-07-25 04:58:02 +02:00
STRV_FOREACH ( name , args + 1 ) {
2013-01-11 23:59:41 +01:00
int state ;
2013-11-07 05:49:04 +01:00
state = check_one_unit ( bus , * name , " active \0 reloading \0 " , arg_quiet ) ;
2012-12-27 17:39:48 +01:00
if ( state < 0 )
return state ;
2013-01-11 23:59:41 +01:00
if ( state > 0 )
2012-12-27 17:39:48 +01:00
r = 0 ;
}
return r ;
}
2013-11-07 05:49:04 +01:00
static int check_unit_failed ( sd_bus * bus , char * * args ) {
2012-12-27 17:39:48 +01:00
char * * name ;
int r = 1 ;
assert ( bus ) ;
assert ( args ) ;
STRV_FOREACH ( name , args + 1 ) {
2013-01-11 23:59:41 +01:00
int state ;
2013-11-07 05:49:04 +01:00
state = check_one_unit ( bus , * name , " failed \0 " , arg_quiet ) ;
2012-06-13 17:29:11 +02:00
if ( state < 0 )
return state ;
2013-01-11 23:59:41 +01:00
if ( state > 0 )
2010-07-01 01:06:58 +02:00
r = 0 ;
}
return r ;
2010-07-04 03:43:57 +02:00
}
2013-11-07 05:49:04 +01:00
static int kill_unit ( sd_bus * bus , char * * args ) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL ;
2013-01-11 23:59:41 +01:00
char * * name ;
2010-10-22 16:11:50 +02:00
int r = 0 ;
2013-01-11 23:59:41 +01:00
assert ( bus ) ;
2010-10-22 16:11:50 +02:00
assert ( args ) ;
if ( ! arg_kill_who )
arg_kill_who = " all " ;
2011-07-25 04:58:02 +02:00
STRV_FOREACH ( name , args + 1 ) {
2013-01-11 23:59:41 +01:00
_cleanup_free_ char * n = NULL ;
2012-08-08 01:32:30 +02:00
n = unit_name_mangle ( * name ) ;
2013-01-14 02:11:22 +01:00
if ( ! n )
return log_oom ( ) ;
2013-01-11 23:59:41 +01:00
2013-11-07 05:49:04 +01:00
r = sd_bus_call_method (
2012-08-08 01:32:30 +02:00
bus ,
2012-06-22 13:08:48 +02:00
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
2012-08-08 01:32:30 +02:00
" KillUnit " ,
2013-11-07 05:49:04 +01:00
& error ,
2012-08-08 01:32:30 +02:00
NULL ,
2013-11-07 05:49:04 +01:00
" ssi " , n , arg_kill_who , arg_signal ) ;
if ( r < 0 ) {
log_error ( " Failed to kill unit %s: %s " , n , bus_error_message ( & error , r ) ) ;
2012-08-08 01:32:30 +02:00
return r ;
2013-11-07 05:49:04 +01:00
}
2010-10-22 16:11:50 +02:00
}
2013-11-07 05:49:04 +01:00
2012-08-08 01:32:30 +02:00
return 0 ;
2010-10-22 16:11:50 +02:00
}
2010-07-10 15:42:24 +02:00
typedef struct ExecStatusInfo {
2011-01-20 13:24:24 +01:00
char * name ;
2010-07-10 15:42:24 +02:00
char * path ;
char * * argv ;
2010-07-12 02:25:42 +02:00
bool ignore ;
2010-07-10 15:42:24 +02:00
usec_t start_timestamp ;
usec_t exit_timestamp ;
pid_t pid ;
int code ;
int status ;
LIST_FIELDS ( struct ExecStatusInfo , exec ) ;
} ExecStatusInfo ;
static void exec_status_info_free ( ExecStatusInfo * i ) {
assert ( i ) ;
2011-01-20 13:24:24 +01:00
free ( i - > name ) ;
2010-07-10 15:42:24 +02:00
free ( i - > path ) ;
strv_free ( i - > argv ) ;
free ( i ) ;
}
2013-11-07 05:49:04 +01:00
static int exec_status_info_deserialize ( sd_bus_message * m , ExecStatusInfo * i ) {
2011-04-07 21:35:37 +02:00
uint64_t start_timestamp , exit_timestamp , start_timestamp_monotonic , exit_timestamp_monotonic ;
2013-11-07 05:49:04 +01:00
const char * path ;
2010-07-10 15:42:24 +02:00
uint32_t pid ;
int32_t code , status ;
2013-11-07 05:49:04 +01:00
int ignore , r ;
2010-07-10 15:42:24 +02:00
2013-11-07 05:49:04 +01:00
assert ( m ) ;
2010-07-10 15:42:24 +02:00
assert ( i ) ;
2013-11-07 05:49:04 +01:00
r = sd_bus_message_enter_container ( m , SD_BUS_TYPE_STRUCT , " sasbttttuii " ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
else if ( r = = 0 )
return 0 ;
2010-07-10 15:42:24 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_read ( m , " s " , & path ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2010-07-10 15:42:24 +02:00
2013-01-14 02:11:22 +01:00
i - > path = strdup ( path ) ;
if ( ! i - > path )
2013-11-07 05:49:04 +01:00
return log_oom ( ) ;
2010-07-10 15:42:24 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_read_strv ( m , & i - > argv ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
r = sd_bus_message_read ( m ,
" bttttuii " ,
& ignore ,
& start_timestamp , & start_timestamp_monotonic ,
& exit_timestamp , & exit_timestamp_monotonic ,
& pid ,
& code , & status ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2010-07-10 15:42:24 +02:00
2010-07-12 02:25:42 +02:00
i - > ignore = ignore ;
2010-07-10 15:42:24 +02:00
i - > start_timestamp = ( usec_t ) start_timestamp ;
i - > exit_timestamp = ( usec_t ) exit_timestamp ;
i - > pid = ( pid_t ) pid ;
i - > code = code ;
i - > status = status ;
2013-11-07 05:49:04 +01:00
r = sd_bus_message_exit_container ( m ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
return 1 ;
2010-07-10 15:42:24 +02:00
}
2010-07-05 02:40:39 +02:00
typedef struct UnitStatusInfo {
const char * id ;
const char * load_state ;
const char * active_state ;
const char * sub_state ;
2011-07-31 18:28:02 +02:00
const char * unit_file_state ;
2010-07-05 02:40:39 +02:00
const char * description ;
2010-10-12 04:04:54 +02:00
const char * following ;
2010-07-05 02:40:39 +02:00
2012-05-21 15:12:18 +02:00
char * * documentation ;
2012-05-22 23:08:24 +02:00
const char * fragment_path ;
const char * source_path ;
2013-06-27 04:14:27 +02:00
const char * control_group ;
2010-07-05 02:40:39 +02:00
2013-04-05 19:58:04 +02:00
char * * dropin_paths ;
2011-07-31 18:13:03 +02:00
const char * load_error ;
2012-02-03 02:01:35 +01:00
const char * result ;
2011-07-31 18:13:03 +02:00
2010-08-25 03:13:44 +02:00
usec_t inactive_exit_timestamp ;
2012-01-04 18:33:36 +01:00
usec_t inactive_exit_timestamp_monotonic ;
2010-08-25 03:13:44 +02:00
usec_t active_enter_timestamp ;
usec_t active_exit_timestamp ;
usec_t inactive_enter_timestamp ;
2010-07-17 00:57:51 +02:00
bool need_daemon_reload ;
2010-07-05 02:40:39 +02:00
/* Service */
pid_t main_pid ;
pid_t control_pid ;
const char * status_text ;
2013-06-25 13:06:51 +02:00
const char * pid_file ;
2010-08-19 03:18:49 +02:00
bool running : 1 ;
2010-07-05 02:40:39 +02:00
usec_t start_timestamp ;
usec_t exit_timestamp ;
int exit_code , exit_status ;
2011-03-09 23:58:17 +01:00
usec_t condition_timestamp ;
bool condition_result ;
systemd,systemctl: export condition status and show failing condition
$ systemctl --user status hoohoo
hoohoo.service
Loaded: loaded (/home/zbyszek/.config/systemd/user/hoohoo.service; static)
Active: inactive (dead)
start condition failed at Tue 2013-06-25 18:08:42 EDT; 1s ago
ConditionPathExists=/tmp/hoo was not met
Full information is exported over D-Bus:
[(condition, trigger, negate, param, state),...]
where state is one of "failed" (<0), "untested" (0), "OK" (>0).
I've decided to use 0 for "untested", because it might be useful to
differentiate different types of failure later on, without breaking
compatibility.
systemctl shows the failing condition, if there was a non-trigger
failing condition, or says "none of the trigger conditions were met",
because there're often many trigger conditions, and they must all
fail for the condition to fail, so printing them all would consume
a lot of space, and bring unnecessary attention to something that is
quite low-level.
2013-06-25 22:09:07 +02:00
bool failed_condition_trigger ;
bool failed_condition_negate ;
const char * failed_condition ;
const char * failed_condition_param ;
2011-03-09 23:58:17 +01:00
2010-07-05 02:40:39 +02:00
/* Socket */
unsigned n_accepted ;
unsigned n_connections ;
2010-07-10 00:55:44 +02:00
bool accept ;
2010-07-05 02:40:39 +02:00
2013-04-02 05:09:35 +02:00
/* Pairs of type, path */
2013-04-01 22:09:45 +02:00
char * * listen ;
2010-07-05 02:40:39 +02:00
/* Device */
const char * sysfs_path ;
/* Mount, Automount */
const char * where ;
/* Swap */
const char * what ;
2010-07-10 15:42:24 +02:00
LIST_HEAD ( ExecStatusInfo , exec ) ;
2010-07-05 02:40:39 +02:00
} UnitStatusInfo ;
2013-11-07 05:49:04 +01:00
static void print_status_info (
UnitStatusInfo * i ,
bool * ellipsized ) {
2010-07-10 15:42:24 +02:00
ExecStatusInfo * p ;
2010-08-11 15:19:31 +02:00
const char * on , * off , * ss ;
2010-08-25 03:13:44 +02:00
usec_t timestamp ;
2012-11-23 22:51:55 +01:00
char since1 [ FORMAT_TIMESTAMP_RELATIVE_MAX ] , * s1 ;
2010-08-25 03:13:44 +02:00
char since2 [ FORMAT_TIMESTAMP_MAX ] , * s2 ;
2012-05-22 23:08:24 +02:00
const char * path ;
2013-01-14 18:16:50 +01:00
int flags =
arg_all * OUTPUT_SHOW_ALL |
( ! on_tty ( ) | | pager_have ( ) ) * OUTPUT_FULL_WIDTH |
on_tty ( ) * OUTPUT_COLOR |
! arg_quiet * OUTPUT_WARN_CUTOFF |
arg_full * OUTPUT_FULL_WIDTH ;
2013-04-02 05:09:35 +02:00
char * * t , * * t2 ;
2010-07-10 15:42:24 +02:00
2010-07-05 02:40:39 +02:00
assert ( i ) ;
/* This shows pretty information about a unit. See
* print_property ( ) for a low - level property printer */
printf ( " %s " , strna ( i - > id ) ) ;
if ( i - > description & & ! streq_ptr ( i - > id , i - > description ) )
printf ( " - %s " , i - > description ) ;
printf ( " \n " ) ;
2010-10-12 04:04:54 +02:00
if ( i - > following )
2013-06-09 20:02:32 +02:00
printf ( " Follow: unit currently follows state of %s \n " , i - > following ) ;
2010-10-12 04:04:54 +02:00
2011-12-06 01:14:36 +01:00
if ( streq_ptr ( i - > load_state , " error " ) ) {
2013-08-02 07:59:02 +02:00
on = ansi_highlight_red ( ) ;
off = ansi_highlight_off ( ) ;
2010-08-13 01:28:05 +02:00
} else
on = off = " " ;
2012-05-22 23:08:24 +02:00
path = i - > source_path ? i - > source_path : i - > fragment_path ;
2011-07-31 18:13:03 +02:00
if ( i - > load_error )
2013-06-09 20:02:32 +02:00
printf ( " Loaded: %s%s%s (Reason: %s) \n " ,
on , strna ( i - > load_state ) , off , i - > load_error ) ;
2012-05-22 23:08:24 +02:00
else if ( path & & i - > unit_file_state )
2013-06-09 20:02:32 +02:00
printf ( " Loaded: %s%s%s (%s; %s) \n " ,
on , strna ( i - > load_state ) , off , path , i - > unit_file_state ) ;
2012-05-22 23:08:24 +02:00
else if ( path )
2013-06-09 20:02:32 +02:00
printf ( " Loaded: %s%s%s (%s) \n " ,
on , strna ( i - > load_state ) , off , path ) ;
2010-07-05 02:40:39 +02:00
else
2013-06-09 20:02:32 +02:00
printf ( " Loaded: %s%s%s \n " ,
on , strna ( i - > load_state ) , off ) ;
2010-07-05 02:40:39 +02:00
2013-04-05 19:58:04 +02:00
if ( ! strv_isempty ( i - > dropin_paths ) ) {
2013-11-07 05:49:04 +01:00
_cleanup_free_ char * dir = NULL ;
2013-04-05 19:58:04 +02:00
bool last = false ;
2013-11-07 05:49:04 +01:00
char * * dropin ;
2013-04-05 19:58:04 +02:00
STRV_FOREACH ( dropin , i - > dropin_paths ) {
if ( ! dir | | last ) {
2013-06-09 20:02:32 +02:00
printf ( dir ? " " : " Drop-In: " ) ;
2013-04-05 19:58:04 +02:00
free ( dir ) ;
2013-11-07 05:49:04 +01:00
dir = NULL ;
2013-04-05 19:58:04 +02:00
if ( path_get_parent ( * dropin , & dir ) < 0 ) {
log_oom ( ) ;
return ;
}
2013-06-09 20:02:32 +02:00
printf ( " %s \n %s " , dir ,
2013-04-05 19:58:04 +02:00
draw_special_char ( DRAW_TREE_RIGHT ) ) ;
}
last = ! ( * ( dropin + 1 ) & & startswith ( * ( dropin + 1 ) , dir ) ) ;
printf ( " %s%s " , path_get_file_name ( * dropin ) , last ? " \n " : " , " ) ;
}
}
2010-08-11 15:19:31 +02:00
ss = streq_ptr ( i - > active_state , i - > sub_state ) ? NULL : i - > sub_state ;
2010-08-31 00:23:34 +02:00
if ( streq_ptr ( i - > active_state , " failed " ) ) {
2013-08-02 07:59:02 +02:00
on = ansi_highlight_red ( ) ;
off = ansi_highlight_off ( ) ;
2010-08-11 15:19:31 +02:00
} else if ( streq_ptr ( i - > active_state , " active " ) | | streq_ptr ( i - > active_state , " reloading " ) ) {
2013-08-02 07:59:02 +02:00
on = ansi_highlight_green ( ) ;
off = ansi_highlight_off ( ) ;
2010-08-11 15:19:31 +02:00
} else
on = off = " " ;
if ( ss )
2013-06-09 20:02:32 +02:00
printf ( " Active: %s%s (%s)%s " ,
on , strna ( i - > active_state ) , ss , off ) ;
2010-08-11 15:19:31 +02:00
else
2013-06-09 20:02:32 +02:00
printf ( " Active: %s%s%s " ,
on , strna ( i - > active_state ) , off ) ;
2010-07-05 02:40:39 +02:00
2012-02-03 02:01:35 +01:00
if ( ! isempty ( i - > result ) & & ! streq ( i - > result , " success " ) )
printf ( " (Result: %s) " , i - > result ) ;
2010-08-25 03:13:44 +02:00
timestamp = ( streq_ptr ( i - > active_state , " active " ) | |
streq_ptr ( i - > active_state , " reloading " ) ) ? i - > active_enter_timestamp :
( streq_ptr ( i - > active_state , " inactive " ) | |
2010-08-31 00:23:34 +02:00
streq_ptr ( i - > active_state , " failed " ) ) ? i - > inactive_enter_timestamp :
2010-08-25 03:13:44 +02:00
streq_ptr ( i - > active_state , " activating " ) ? i - > inactive_exit_timestamp :
i - > active_exit_timestamp ;
2012-11-23 22:12:59 +01:00
s1 = format_timestamp_relative ( since1 , sizeof ( since1 ) , timestamp ) ;
2010-08-25 03:13:44 +02:00
s2 = format_timestamp ( since2 , sizeof ( since2 ) , timestamp ) ;
if ( s1 )
2010-10-12 04:05:29 +02:00
printf ( " since %s; %s \n " , s2 , s1 ) ;
2010-08-25 03:13:44 +02:00
else if ( s2 )
2010-10-12 04:05:29 +02:00
printf ( " since %s \n " , s2 ) ;
2010-08-25 03:13:44 +02:00
else
printf ( " \n " ) ;
2011-03-09 23:58:17 +01:00
if ( ! i - > condition_result & & i - > condition_timestamp > 0 ) {
2012-11-23 22:12:59 +01:00
s1 = format_timestamp_relative ( since1 , sizeof ( since1 ) , i - > condition_timestamp ) ;
2011-03-09 23:58:17 +01:00
s2 = format_timestamp ( since2 , sizeof ( since2 ) , i - > condition_timestamp ) ;
systemd,systemctl: export condition status and show failing condition
$ systemctl --user status hoohoo
hoohoo.service
Loaded: loaded (/home/zbyszek/.config/systemd/user/hoohoo.service; static)
Active: inactive (dead)
start condition failed at Tue 2013-06-25 18:08:42 EDT; 1s ago
ConditionPathExists=/tmp/hoo was not met
Full information is exported over D-Bus:
[(condition, trigger, negate, param, state),...]
where state is one of "failed" (<0), "untested" (0), "OK" (>0).
I've decided to use 0 for "untested", because it might be useful to
differentiate different types of failure later on, without breaking
compatibility.
systemctl shows the failing condition, if there was a non-trigger
failing condition, or says "none of the trigger conditions were met",
because there're often many trigger conditions, and they must all
fail for the condition to fail, so printing them all would consume
a lot of space, and bring unnecessary attention to something that is
quite low-level.
2013-06-25 22:09:07 +02:00
printf ( " start condition failed at %s%s%s \n " ,
s2 , s1 ? " ; " : " " , s1 ? s1 : " " ) ;
if ( i - > failed_condition_trigger )
printf ( " none of the trigger conditions were met \n " ) ;
else if ( i - > failed_condition )
printf ( " %s=%s%s was not met \n " ,
i - > failed_condition ,
i - > failed_condition_negate ? " ! " : " " ,
i - > failed_condition_param ) ;
2011-03-09 23:58:17 +01:00
}
2010-07-05 02:40:39 +02:00
if ( i - > sysfs_path )
2013-06-09 20:02:32 +02:00
printf ( " Device: %s \n " , i - > sysfs_path ) ;
2010-10-28 22:11:45 +02:00
if ( i - > where )
2013-06-09 20:02:32 +02:00
printf ( " Where: %s \n " , i - > where ) ;
2010-10-28 22:11:45 +02:00
if ( i - > what )
2013-06-09 20:02:32 +02:00
printf ( " What: %s \n " , i - > what ) ;
2012-05-21 15:12:18 +02:00
2013-04-02 05:09:35 +02:00
STRV_FOREACH ( t , i - > documentation )
2013-06-09 20:02:32 +02:00
printf ( " %*s %s \n " , 9 , t = = i - > documentation ? " Docs: " : " " , * t ) ;
2012-05-21 15:12:18 +02:00
2013-04-02 05:09:35 +02:00
STRV_FOREACH_PAIR ( t , t2 , i - > listen )
2013-06-09 20:02:32 +02:00
printf ( " %*s %s (%s) \n " , 9 , t = = i - > listen ? " Listen: " : " " , * t2 , * t ) ;
2013-04-01 22:09:45 +02:00
2010-07-10 00:55:44 +02:00
if ( i - > accept )
2013-06-09 20:02:32 +02:00
printf ( " Accepted: %u; Connected: %u \n " , i - > n_accepted , i - > n_connections ) ;
2010-07-05 02:40:39 +02:00
2010-07-10 15:42:24 +02:00
LIST_FOREACH ( exec , p , i - > exec ) {
2013-04-02 05:09:35 +02:00
_cleanup_free_ char * argv = NULL ;
2011-01-20 18:22:03 +01:00
bool good ;
2010-07-10 15:42:24 +02:00
/* Only show exited processes here */
if ( p - > code = = 0 )
continue ;
2013-04-02 05:09:35 +02:00
argv = strv_join ( p - > argv , " " ) ;
2013-06-09 20:02:32 +02:00
printf ( " Process: %u %s=%s " , p - > pid , p - > name , strna ( argv ) ) ;
2010-07-10 15:42:24 +02:00
2012-08-13 13:58:01 +02:00
good = is_clean_exit_lsb ( p - > code , p - > status , NULL ) ;
2011-01-20 18:22:03 +01:00
if ( ! good ) {
2013-08-02 07:59:02 +02:00
on = ansi_highlight_red ( ) ;
off = ansi_highlight_off ( ) ;
2011-01-20 18:22:03 +01:00
} else
on = off = " " ;
printf ( " %s(code=%s, " , on , sigchld_code_to_string ( p - > code ) ) ;
2010-08-19 03:18:49 +02:00
if ( p - > code = = CLD_EXITED ) {
const char * c ;
2010-07-10 15:42:24 +02:00
printf ( " status=%i " , p - > status ) ;
2010-08-19 03:18:49 +02:00
2012-05-22 23:08:24 +02:00
c = exit_status_to_string ( p - > status , EXIT_STATUS_SYSTEMD ) ;
if ( c )
2010-08-19 03:18:49 +02:00
printf ( " /%s " , c ) ;
} else
2010-07-10 15:42:24 +02:00
printf ( " signal=%s " , signal_to_string ( p - > status ) ) ;
2011-01-20 18:22:03 +01:00
printf ( " )%s \n " , off ) ;
2010-07-10 15:42:24 +02:00
if ( i - > main_pid = = p - > pid & &
i - > start_timestamp = = p - > start_timestamp & &
i - > exit_timestamp = = p - > start_timestamp )
/* Let's not show this twice */
i - > main_pid = 0 ;
if ( p - > pid = = i - > control_pid )
i - > control_pid = 0 ;
}
2010-07-05 02:40:39 +02:00
if ( i - > main_pid > 0 | | i - > control_pid > 0 ) {
if ( i - > main_pid > 0 ) {
2013-06-09 20:02:32 +02:00
printf ( " Main PID: %u " , ( unsigned ) i - > main_pid ) ;
2010-07-05 02:40:39 +02:00
if ( i - > running ) {
2013-04-02 05:09:35 +02:00
_cleanup_free_ char * comm = NULL ;
get_process_comm ( i - > main_pid , & comm ) ;
if ( comm )
printf ( " (%s) " , comm ) ;
2010-08-09 16:50:18 +02:00
} else if ( i - > exit_code > 0 ) {
2010-07-05 02:40:39 +02:00
printf ( " (code=%s, " , sigchld_code_to_string ( i - > exit_code ) ) ;
2010-08-19 03:18:49 +02:00
if ( i - > exit_code = = CLD_EXITED ) {
const char * c ;
2010-07-05 02:40:39 +02:00
printf ( " status=%i " , i - > exit_status ) ;
2010-08-19 03:18:49 +02:00
2012-05-22 23:08:24 +02:00
c = exit_status_to_string ( i - > exit_status , EXIT_STATUS_SYSTEMD ) ;
if ( c )
2010-08-19 03:18:49 +02:00
printf ( " /%s " , c ) ;
} else
2010-07-10 15:42:24 +02:00
printf ( " signal=%s " , signal_to_string ( i - > exit_status ) ) ;
2010-08-09 16:50:18 +02:00
printf ( " ) " ) ;
}
2010-07-05 02:40:39 +02:00
2013-04-02 05:09:35 +02:00
if ( i - > control_pid > 0 )
printf ( " ; " ) ;
}
2010-07-05 02:40:39 +02:00
if ( i - > control_pid > 0 ) {
2013-04-02 05:09:35 +02:00
_cleanup_free_ char * c = NULL ;
2010-07-05 02:40:39 +02:00
2013-06-09 20:02:32 +02:00
printf ( " %8s: %u " , i - > main_pid ? " " : " Control " , ( unsigned ) i - > control_pid ) ;
2010-07-05 02:40:39 +02:00
2013-04-02 05:09:35 +02:00
get_process_comm ( i - > control_pid , & c ) ;
if ( c )
printf ( " (%s) " , c ) ;
2010-07-05 02:40:39 +02:00
}
printf ( " \n " ) ;
}
2010-07-11 01:20:46 +02:00
if ( i - > status_text )
2013-06-09 20:02:32 +02:00
printf ( " Status: \" %s \" \n " , i - > status_text ) ;
2010-07-11 01:20:46 +02:00
2013-06-27 04:14:27 +02:00
if ( i - > control_group & &
2013-07-11 19:15:01 +02:00
( i - > main_pid > 0 | | i - > control_pid > 0 | | cg_is_empty_recursive ( SYSTEMD_CGROUP_CONTROLLER , i - > control_group , false ) = = 0 ) ) {
2010-07-08 06:08:32 +02:00
unsigned c ;
2013-06-27 04:14:27 +02:00
printf ( " CGroup: %s \n " , i - > control_group ) ;
2010-07-08 06:08:32 +02:00
2013-11-08 14:06:46 +01:00
if ( arg_transport = = BUS_TRANSPORT_LOCAL | | arg_transport = = BUS_TRANSPORT_CONTAINER ) {
2012-04-16 18:56:18 +02:00
unsigned k = 0 ;
pid_t extra [ 2 ] ;
2013-06-09 20:02:32 +02:00
char prefix [ ] = " " ;
2012-04-16 18:56:18 +02:00
c = columns ( ) ;
2013-04-05 03:14:32 +02:00
if ( c > sizeof ( prefix ) - 1 )
c - = sizeof ( prefix ) - 1 ;
2011-03-12 01:03:13 +01:00
else
c = 0 ;
2010-07-08 06:08:32 +02:00
2012-04-16 18:56:18 +02:00
if ( i - > main_pid > 0 )
extra [ k + + ] = i - > main_pid ;
if ( i - > control_pid > 0 )
extra [ k + + ] = i - > control_pid ;
2013-07-01 00:02:41 +02:00
show_cgroup_and_extra ( SYSTEMD_CGROUP_CONTROLLER , i - > control_group , prefix ,
2013-04-05 03:14:32 +02:00
c , false , extra , k , flags ) ;
2011-03-12 01:03:13 +01:00
}
2010-07-05 03:06:02 +02:00
}
2010-07-17 00:57:51 +02:00
2013-11-07 05:49:04 +01:00
if ( i - > id & & arg_transport = = BUS_TRANSPORT_LOCAL ) {
2012-01-04 04:00:14 +01:00
printf ( " \n " ) ;
2013-03-14 00:30:05 +01:00
show_journal_by_unit ( stdout ,
i - > id ,
arg_output ,
0 ,
i - > inactive_exit_timestamp_monotonic ,
arg_lines ,
getuid ( ) ,
flags ,
2013-08-04 01:38:13 +02:00
arg_scope = = UNIT_FILE_SYSTEM ,
ellipsized ) ;
2012-01-04 04:00:14 +01:00
}
2012-01-03 21:08:28 +01:00
2010-07-17 00:57:51 +02:00
if ( i - > need_daemon_reload )
2013-05-31 02:28:09 +02:00
printf ( " \n %sWarning:%s Unit file changed on disk, 'systemctl %sdaemon-reload' recommended. \n " ,
2013-08-02 07:59:02 +02:00
ansi_highlight_red ( ) ,
ansi_highlight_off ( ) ,
2013-05-31 02:28:09 +02:00
arg_scope = = UNIT_FILE_SYSTEM ? " " : " --user " ) ;
2010-07-05 02:40:39 +02:00
}
2012-06-04 19:48:32 +02:00
static void show_unit_help ( UnitStatusInfo * i ) {
2012-05-31 04:11:57 +02:00
char * * p ;
assert ( i ) ;
if ( ! i - > documentation ) {
log_info ( " Documentation for %s not known. " , i - > id ) ;
return ;
}
STRV_FOREACH ( p , i - > documentation ) {
if ( startswith ( * p , " man: " ) ) {
const char * args [ 4 ] = { " man " , NULL , NULL , NULL } ;
2013-11-08 13:54:46 +01:00
_cleanup_free_ char * page = NULL , * section = NULL ;
char * e = NULL ;
2012-05-31 04:11:57 +02:00
pid_t pid ;
2013-11-08 13:54:46 +01:00
size_t k ;
2012-05-31 04:11:57 +02:00
k = strlen ( * p ) ;
if ( ( * p ) [ k - 1 ] = = ' ) ' )
e = strrchr ( * p , ' ( ' ) ;
if ( e ) {
page = strndup ( ( * p ) + 4 , e - * p - 4 ) ;
section = strndup ( e + 1 , * p + k - e - 2 ) ;
2013-02-14 19:32:19 +01:00
if ( ! page | | ! section ) {
2012-07-25 23:55:59 +02:00
log_oom ( ) ;
2012-05-31 04:11:57 +02:00
return ;
}
args [ 1 ] = section ;
args [ 2 ] = page ;
} else
args [ 1 ] = * p + 4 ;
pid = fork ( ) ;
if ( pid < 0 ) {
log_error ( " Failed to fork: %m " ) ;
continue ;
}
if ( pid = = 0 ) {
/* Child */
execvp ( args [ 0 ] , ( char * * ) args ) ;
log_error ( " Failed to execute man: %m " ) ;
_exit ( EXIT_FAILURE ) ;
}
wait_for_terminate ( pid , NULL ) ;
} else
2012-06-25 22:57:20 +02:00
log_info ( " Can't show: %s " , * p ) ;
2012-05-31 04:11:57 +02:00
}
}
2013-11-07 05:49:04 +01:00
static int status_property ( const char * name , sd_bus_message * m , UnitStatusInfo * i , const char * contents ) {
int r ;
2010-07-05 02:40:39 +02:00
2011-07-08 21:39:10 +02:00
assert ( name ) ;
2013-11-07 05:49:04 +01:00
assert ( m ) ;
2011-07-08 21:39:10 +02:00
assert ( i ) ;
2013-11-07 05:49:04 +01:00
switch ( contents [ 0 ] ) {
2010-07-05 02:40:39 +02:00
2013-11-07 05:49:04 +01:00
case SD_BUS_TYPE_STRING : {
2010-07-05 02:40:39 +02:00
const char * s ;
2013-11-07 05:49:04 +01:00
r = sd_bus_message_read ( m , " s " , & s ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2010-07-05 02:40:39 +02:00
2011-07-08 21:39:10 +02:00
if ( ! isempty ( s ) ) {
2010-07-05 02:40:39 +02:00
if ( streq ( name , " Id " ) )
i - > id = s ;
else if ( streq ( name , " LoadState " ) )
i - > load_state = s ;
else if ( streq ( name , " ActiveState " ) )
i - > active_state = s ;
else if ( streq ( name , " SubState " ) )
i - > sub_state = s ;
else if ( streq ( name , " Description " ) )
i - > description = s ;
else if ( streq ( name , " FragmentPath " ) )
2012-05-22 23:08:24 +02:00
i - > fragment_path = s ;
else if ( streq ( name , " SourcePath " ) )
i - > source_path = s ;
2013-07-03 09:38:35 +02:00
# ifndef NOLEGACY
2013-07-01 00:02:41 +02:00
else if ( streq ( name , " DefaultControlGroup " ) ) {
const char * e ;
e = startswith ( s , SYSTEMD_CGROUP_CONTROLLER " : " ) ;
if ( e )
i - > control_group = e ;
}
2013-06-27 04:14:27 +02:00
# endif
else if ( streq ( name , " ControlGroup " ) )
i - > control_group = s ;
2010-07-05 02:40:39 +02:00
else if ( streq ( name , " StatusText " ) )
i - > status_text = s ;
2013-06-25 13:06:51 +02:00
else if ( streq ( name , " PIDFile " ) )
i - > pid_file = s ;
2010-07-05 02:40:39 +02:00
else if ( streq ( name , " SysFSPath " ) )
i - > sysfs_path = s ;
else if ( streq ( name , " Where " ) )
i - > where = s ;
else if ( streq ( name , " What " ) )
i - > what = s ;
2010-10-12 04:04:54 +02:00
else if ( streq ( name , " Following " ) )
i - > following = s ;
2011-07-31 18:28:02 +02:00
else if ( streq ( name , " UnitFileState " ) )
i - > unit_file_state = s ;
2012-02-03 02:01:35 +01:00
else if ( streq ( name , " Result " ) )
i - > result = s ;
2010-07-05 02:40:39 +02:00
}
break ;
}
2013-11-07 05:49:04 +01:00
case SD_BUS_TYPE_BOOLEAN : {
int b ;
2010-07-10 00:55:44 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_read ( m , " b " , & b ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2010-07-10 00:55:44 +02:00
if ( streq ( name , " Accept " ) )
i - > accept = b ;
2010-07-17 00:57:51 +02:00
else if ( streq ( name , " NeedDaemonReload " ) )
i - > need_daemon_reload = b ;
2011-03-09 23:58:17 +01:00
else if ( streq ( name , " ConditionResult " ) )
i - > condition_result = b ;
2010-07-10 00:55:44 +02:00
break ;
}
2013-11-07 05:49:04 +01:00
case SD_BUS_TYPE_UINT32 : {
2010-07-05 02:40:39 +02:00
uint32_t u ;
2013-11-07 05:49:04 +01:00
r = sd_bus_message_read ( m , " u " , & u ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2010-07-05 02:40:39 +02:00
if ( streq ( name , " MainPID " ) ) {
if ( u > 0 ) {
i - > main_pid = ( pid_t ) u ;
i - > running = true ;
}
} else if ( streq ( name , " ControlPID " ) )
i - > control_pid = ( pid_t ) u ;
else if ( streq ( name , " ExecMainPID " ) ) {
if ( u > 0 )
i - > main_pid = ( pid_t ) u ;
} else if ( streq ( name , " NAccepted " ) )
i - > n_accepted = u ;
else if ( streq ( name , " NConnections " ) )
i - > n_connections = u ;
break ;
}
2013-11-07 05:49:04 +01:00
case SD_BUS_TYPE_INT32 : {
2010-07-05 02:40:39 +02:00
int32_t j ;
2013-11-07 05:49:04 +01:00
r = sd_bus_message_read ( m , " i " , & j ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2010-07-05 02:40:39 +02:00
if ( streq ( name , " ExecMainCode " ) )
i - > exit_code = ( int ) j ;
else if ( streq ( name , " ExecMainStatus " ) )
i - > exit_status = ( int ) j ;
break ;
}
2013-11-07 05:49:04 +01:00
case SD_BUS_TYPE_UINT64 : {
2010-07-05 02:40:39 +02:00
uint64_t u ;
2013-11-07 05:49:04 +01:00
r = sd_bus_message_read ( m , " t " , & u ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2010-07-05 02:40:39 +02:00
if ( streq ( name , " ExecMainStartTimestamp " ) )
i - > start_timestamp = ( usec_t ) u ;
else if ( streq ( name , " ExecMainExitTimestamp " ) )
i - > exit_timestamp = ( usec_t ) u ;
2010-08-25 03:13:44 +02:00
else if ( streq ( name , " ActiveEnterTimestamp " ) )
i - > active_enter_timestamp = ( usec_t ) u ;
else if ( streq ( name , " InactiveEnterTimestamp " ) )
i - > inactive_enter_timestamp = ( usec_t ) u ;
else if ( streq ( name , " InactiveExitTimestamp " ) )
i - > inactive_exit_timestamp = ( usec_t ) u ;
2012-01-04 18:33:36 +01:00
else if ( streq ( name , " InactiveExitTimestampMonotonic " ) )
i - > inactive_exit_timestamp_monotonic = ( usec_t ) u ;
2010-08-25 03:13:44 +02:00
else if ( streq ( name , " ActiveExitTimestamp " ) )
i - > active_exit_timestamp = ( usec_t ) u ;
2011-03-09 23:58:17 +01:00
else if ( streq ( name , " ConditionTimestamp " ) )
i - > condition_timestamp = ( usec_t ) u ;
2010-07-05 02:40:39 +02:00
break ;
}
2010-07-10 15:42:24 +02:00
2013-11-07 05:49:04 +01:00
case SD_BUS_TYPE_ARRAY :
2010-07-10 15:42:24 +02:00
2013-11-07 05:49:04 +01:00
if ( contents [ 1 ] = = SD_BUS_TYPE_STRUCT_BEGIN & & startswith ( name , " Exec " ) ) {
_cleanup_free_ ExecStatusInfo * info = NULL ;
2010-07-10 15:42:24 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_enter_container ( m , SD_BUS_TYPE_ARRAY , " (sasbttttuii) " ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2010-07-10 15:42:24 +02:00
2013-11-07 05:49:04 +01:00
info = new0 ( ExecStatusInfo , 1 ) ;
if ( ! info )
return log_oom ( ) ;
2010-07-10 15:42:24 +02:00
2013-11-07 05:49:04 +01:00
while ( ( r = exec_status_info_deserialize ( m , info ) ) > 0 ) {
2011-01-20 13:24:24 +01:00
2013-11-07 05:49:04 +01:00
info - > name = strdup ( name ) ;
if ( ! info - > name )
log_oom ( ) ;
2010-07-10 15:42:24 +02:00
2013-10-14 06:10:14 +02:00
LIST_PREPEND ( exec , i - > exec , info ) ;
2010-07-10 15:42:24 +02:00
2013-11-07 05:49:04 +01:00
info = new0 ( ExecStatusInfo , 1 ) ;
if ( ! info )
log_oom ( ) ;
2012-05-21 15:12:18 +02:00
}
2013-04-01 22:09:45 +02:00
2013-11-07 05:49:04 +01:00
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2013-04-01 22:09:45 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_exit_container ( m ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2013-04-01 22:09:45 +02:00
2013-11-07 05:49:04 +01:00
return 0 ;
2013-04-01 22:09:45 +02:00
2013-11-07 05:49:04 +01:00
} else if ( contents [ 1 ] = = SD_BUS_TYPE_STRUCT_BEGIN & & streq ( name , " Listen " ) ) {
const char * type , * path ;
2013-04-02 05:09:35 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_enter_container ( m , SD_BUS_TYPE_ARRAY , " (ss) " ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2013-04-01 22:09:45 +02:00
2013-11-07 05:49:04 +01:00
while ( ( r = sd_bus_message_read ( m , " (ss) " , & type , & path ) ) > 0 ) {
2013-04-01 22:09:45 +02:00
2013-11-07 05:49:04 +01:00
r = strv_extend ( & i - > listen , type ) ;
if ( r < 0 )
return r ;
2013-04-01 22:09:45 +02:00
2013-11-07 05:49:04 +01:00
r = strv_extend ( & i - > listen , path ) ;
if ( r < 0 )
return r ;
}
2013-04-05 19:58:04 +02:00
if ( r < 0 )
2013-11-07 05:49:04 +01:00
return bus_log_parse_error ( r ) ;
2013-04-05 19:58:04 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_exit_container ( m ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2012-05-21 15:12:18 +02:00
2013-11-07 05:49:04 +01:00
return 0 ;
2012-05-21 15:12:18 +02:00
2013-11-07 05:49:04 +01:00
} else if ( contents [ 1 ] = = SD_BUS_TYPE_STRING & & streq ( name , " DropInPaths " ) ) {
2012-05-21 15:12:18 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_read_strv ( m , & i - > dropin_paths ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2012-05-21 15:12:18 +02:00
2013-11-07 05:49:04 +01:00
} else if ( contents [ 1 ] = = SD_BUS_TYPE_STRING & & streq ( name , " Documentation " ) ) {
2012-05-21 15:12:18 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_read_strv ( m , & i - > documentation ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
systemd,systemctl: export condition status and show failing condition
$ systemctl --user status hoohoo
hoohoo.service
Loaded: loaded (/home/zbyszek/.config/systemd/user/hoohoo.service; static)
Active: inactive (dead)
start condition failed at Tue 2013-06-25 18:08:42 EDT; 1s ago
ConditionPathExists=/tmp/hoo was not met
Full information is exported over D-Bus:
[(condition, trigger, negate, param, state),...]
where state is one of "failed" (<0), "untested" (0), "OK" (>0).
I've decided to use 0 for "untested", because it might be useful to
differentiate different types of failure later on, without breaking
compatibility.
systemctl shows the failing condition, if there was a non-trigger
failing condition, or says "none of the trigger conditions were met",
because there're often many trigger conditions, and they must all
fail for the condition to fail, so printing them all would consume
a lot of space, and bring unnecessary attention to something that is
quite low-level.
2013-06-25 22:09:07 +02:00
2013-11-07 05:49:04 +01:00
} else if ( contents [ 1 ] = = SD_BUS_TYPE_STRUCT_BEGIN & & streq ( name , " Conditions " ) ) {
const char * cond , * param ;
int trigger , negate ;
int32_t state ;
systemd,systemctl: export condition status and show failing condition
$ systemctl --user status hoohoo
hoohoo.service
Loaded: loaded (/home/zbyszek/.config/systemd/user/hoohoo.service; static)
Active: inactive (dead)
start condition failed at Tue 2013-06-25 18:08:42 EDT; 1s ago
ConditionPathExists=/tmp/hoo was not met
Full information is exported over D-Bus:
[(condition, trigger, negate, param, state),...]
where state is one of "failed" (<0), "untested" (0), "OK" (>0).
I've decided to use 0 for "untested", because it might be useful to
differentiate different types of failure later on, without breaking
compatibility.
systemctl shows the failing condition, if there was a non-trigger
failing condition, or says "none of the trigger conditions were met",
because there're often many trigger conditions, and they must all
fail for the condition to fail, so printing them all would consume
a lot of space, and bring unnecessary attention to something that is
quite low-level.
2013-06-25 22:09:07 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_enter_container ( m , SD_BUS_TYPE_ARRAY , " (sbbsi) " ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
while ( ( r = sd_bus_message_read ( m , " (sbbsi) " , & cond , & trigger , & negate , & param , & state ) ) > 0 ) {
log_debug ( " %s %d %d %s %d " , cond , trigger , negate , param , state ) ;
if ( state < 0 & & ( ! trigger | | ! i - > failed_condition ) ) {
i - > failed_condition = cond ;
i - > failed_condition_trigger = trigger ;
i - > failed_condition_negate = negate ;
i - > failed_condition_param = param ;
}
2010-07-10 15:42:24 +02:00
}
2013-11-07 05:49:04 +01:00
if ( r < 0 )
return bus_log_parse_error ( r ) ;
r = sd_bus_message_exit_container ( m ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
} else
goto skip ;
2010-07-10 15:42:24 +02:00
break ;
2011-07-31 18:13:03 +02:00
2013-11-07 05:49:04 +01:00
case SD_BUS_TYPE_STRUCT_BEGIN :
2011-07-31 18:13:03 +02:00
if ( streq ( name , " LoadError " ) ) {
const char * n , * message ;
2013-11-07 05:49:04 +01:00
r = sd_bus_message_read ( m , " (ss) " , & n , & message ) ;
2011-07-31 18:13:03 +02:00
if ( r < 0 )
2013-11-07 05:49:04 +01:00
return bus_log_parse_error ( r ) ;
2011-07-31 18:13:03 +02:00
if ( ! isempty ( message ) )
i - > load_error = message ;
2013-11-07 05:49:04 +01:00
} else
goto skip ;
2011-07-31 18:13:03 +02:00
break ;
2013-11-07 05:49:04 +01:00
default :
goto skip ;
2011-07-31 18:13:03 +02:00
}
2013-11-07 05:49:04 +01:00
return 0 ;
skip :
r = sd_bus_message_skip ( m , contents ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2010-07-05 02:40:39 +02:00
return 0 ;
}
2013-11-07 05:49:04 +01:00
static int print_property ( const char * name , sd_bus_message * m , const char * contents ) {
int r ;
2010-07-04 03:43:57 +02:00
assert ( name ) ;
2013-11-07 05:49:04 +01:00
assert ( m ) ;
2010-07-04 03:43:57 +02:00
2010-07-05 02:40:39 +02:00
/* This is a low-level property printer, see
* print_status_info ( ) for the nicer output */
2013-04-11 04:40:58 +02:00
if ( arg_properties & & ! strv_find ( arg_properties , name ) )
2010-07-04 03:43:57 +02:00
return 0 ;
2013-11-07 05:49:04 +01:00
switch ( contents [ 0 ] ) {
2010-07-04 03:43:57 +02:00
2013-11-07 05:49:04 +01:00
case SD_BUS_TYPE_STRUCT_BEGIN :
2010-07-04 03:43:57 +02:00
2013-11-07 05:49:04 +01:00
if ( contents [ 1 ] = = SD_BUS_TYPE_UINT32 & & streq ( name , " Job " ) ) {
2010-07-04 03:43:57 +02:00
uint32_t u ;
2013-11-07 05:49:04 +01:00
r = sd_bus_message_read ( m , " (uo) " , & u , NULL ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2010-07-04 03:43:57 +02:00
2013-11-07 05:49:04 +01:00
if ( u > 0 )
2010-07-04 03:43:57 +02:00
printf ( " %s=%u \n " , name , ( unsigned ) u ) ;
else if ( arg_all )
printf ( " %s= \n " , name ) ;
return 0 ;
2013-11-07 05:49:04 +01:00
} else if ( contents [ 1 ] = = SD_BUS_TYPE_STRING & & streq ( name , " Unit " ) ) {
2010-07-04 03:43:57 +02:00
const char * s ;
2013-11-07 05:49:04 +01:00
r = sd_bus_message_read ( m , " (so) " , & s , NULL ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2010-07-04 03:43:57 +02:00
2013-11-07 05:49:04 +01:00
if ( arg_all | | ! isempty ( s ) )
2010-07-04 03:43:57 +02:00
printf ( " %s=%s \n " , name , s ) ;
return 0 ;
2013-11-07 05:49:04 +01:00
} else if ( contents [ 1 ] = = SD_BUS_TYPE_STRING & & streq ( name , " LoadError " ) ) {
2011-07-31 18:13:03 +02:00
const char * a = NULL , * b = NULL ;
2013-11-07 05:49:04 +01:00
r = sd_bus_message_read ( m , " (ss) " , & a , & b ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2011-07-31 18:13:03 +02:00
if ( arg_all | | ! isempty ( a ) | | ! isempty ( b ) )
printf ( " %s=%s \" %s \" \n " , name , strempty ( a ) , strempty ( b ) ) ;
2011-07-31 18:28:33 +02:00
return 0 ;
2010-07-04 03:43:57 +02:00
}
break ;
2013-11-07 05:49:04 +01:00
case SD_BUS_TYPE_ARRAY :
2010-07-04 03:43:57 +02:00
2013-11-07 05:49:04 +01:00
if ( contents [ 1 ] = = SD_BUS_TYPE_STRUCT_BEGIN & & streq ( name , " EnvironmentFiles " ) ) {
const char * path ;
int ignore ;
2011-03-04 03:44:43 +01:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_enter_container ( m , SD_BUS_TYPE_ARRAY , " (sb) " ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2011-03-04 03:44:43 +01:00
2013-11-07 05:49:04 +01:00
while ( ( r = sd_bus_message_read ( m , " (sb) " , & path , & ignore ) ) > 0 )
printf ( " EnvironmentFile=%s (ignore_errors=%s) \n " , path , yes_no ( ignore ) ) ;
2011-03-04 03:44:43 +01:00
2013-11-07 05:49:04 +01:00
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2011-03-04 03:44:43 +01:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_exit_container ( m ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2011-03-04 03:44:43 +01:00
return 0 ;
2013-11-07 05:49:04 +01:00
} else if ( contents [ 1 ] = = SD_BUS_TYPE_STRUCT_BEGIN & & streq ( name , " Paths " ) ) {
const char * type , * path ;
2013-04-01 22:09:45 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_enter_container ( m , SD_BUS_TYPE_ARRAY , " (ss) " ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2010-07-04 04:23:48 +02:00
2013-11-07 05:49:04 +01:00
while ( ( r = sd_bus_message_read ( m , " (ss) " , & type , & path ) ) > 0 )
printf ( " %s=%s \n " , type , path ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2010-07-04 04:23:48 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_exit_container ( m ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2010-07-04 04:23:48 +02:00
2010-07-04 04:37:03 +02:00
return 0 ;
2010-07-10 15:42:24 +02:00
2013-11-07 05:49:04 +01:00
} else if ( contents [ 1 ] = = SD_BUS_TYPE_STRUCT_BEGIN & & streq ( name , " Listen " ) ) {
const char * type , * path ;
2013-04-01 22:09:45 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_enter_container ( m , SD_BUS_TYPE_ARRAY , " (ss) " ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2013-04-01 22:09:45 +02:00
2013-11-07 05:49:04 +01:00
while ( ( r = sd_bus_message_read ( m , " (ss) " , & type , & path ) ) > 0 )
printf ( " Listen%s=%s \n " , type , path ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2013-04-01 22:09:45 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_exit_container ( m ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2013-04-01 22:09:45 +02:00
return 0 ;
2013-11-07 05:49:04 +01:00
} else if ( contents [ 1 ] = = SD_BUS_TYPE_STRUCT_BEGIN & & streq ( name , " Timers " ) ) {
const char * base ;
uint64_t value , next_elapse ;
2010-07-04 04:37:03 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_enter_container ( m , SD_BUS_TYPE_ARRAY , " (stt) " ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2010-07-04 21:18:06 +02:00
2013-11-07 05:49:04 +01:00
while ( ( r = sd_bus_message_read ( m , " (stt) " , & base , & value , & next_elapse ) ) > 0 ) {
char timespan1 [ FORMAT_TIMESPAN_MAX ] , timespan2 [ FORMAT_TIMESPAN_MAX ] ;
2010-07-04 20:38:14 +02:00
2013-11-07 05:49:04 +01:00
printf ( " %s={ value=%s ; next_elapse=%s } \n " ,
base ,
format_timespan ( timespan1 , sizeof ( timespan1 ) , value , 0 ) ,
format_timespan ( timespan2 , sizeof ( timespan2 ) , next_elapse , 0 ) ) ;
2010-07-04 20:38:14 +02:00
}
2013-11-07 05:49:04 +01:00
if ( r < 0 )
return bus_log_parse_error ( r ) ;
r = sd_bus_message_exit_container ( m ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2010-07-04 20:38:14 +02:00
return 0 ;
2013-11-07 05:49:04 +01:00
} else if ( contents [ 1 ] = = SD_BUS_TYPE_STRUCT_BEGIN & & startswith ( name , " Exec " ) ) {
ExecStatusInfo info = { } ;
r = sd_bus_message_enter_container ( m , SD_BUS_TYPE_ARRAY , " (sasbttttuii) " ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
while ( ( r = exec_status_info_deserialize ( m , & info ) ) > 0 ) {
char timestamp1 [ FORMAT_TIMESTAMP_MAX ] , timestamp2 [ FORMAT_TIMESTAMP_MAX ] ;
_cleanup_free_ char * tt ;
tt = strv_join ( info . argv , " " ) ;
printf ( " %s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s } \n " ,
name ,
strna ( info . path ) ,
strna ( tt ) ,
yes_no ( info . ignore ) ,
strna ( format_timestamp ( timestamp1 , sizeof ( timestamp1 ) , info . start_timestamp ) ) ,
strna ( format_timestamp ( timestamp2 , sizeof ( timestamp2 ) , info . exit_timestamp ) ) ,
( unsigned ) info . pid ,
sigchld_code_to_string ( info . code ) ,
info . status ,
info . code = = CLD_EXITED ? " " : " / " ,
strempty ( info . code = = CLD_EXITED ? NULL : signal_to_string ( info . status ) ) ) ;
2010-07-04 20:38:14 +02:00
2010-07-10 15:42:24 +02:00
free ( info . path ) ;
strv_free ( info . argv ) ;
2013-11-07 05:49:04 +01:00
zero ( info ) ;
2010-07-04 04:37:03 +02:00
}
2013-11-07 05:49:04 +01:00
r = sd_bus_message_exit_container ( m ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2010-07-04 03:43:57 +02:00
return 0 ;
2013-06-27 04:14:27 +02:00
2013-11-07 05:49:04 +01:00
} else if ( contents [ 1 ] = = SD_BUS_TYPE_STRUCT_BEGIN & & streq ( name , " DeviceAllow " ) ) {
const char * path , * rwm ;
2013-06-27 04:14:27 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_enter_container ( m , SD_BUS_TYPE_ARRAY , " (ss) " ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2013-06-27 04:14:27 +02:00
2013-11-07 05:49:04 +01:00
while ( ( r = sd_bus_message_read ( m , " (ss) " , & path , & rwm ) ) > 0 )
printf ( " %s=%s %s \n " , name , strna ( path ) , strna ( rwm ) ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2013-06-27 04:14:27 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_exit_container ( m ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2013-06-27 04:14:27 +02:00
return 0 ;
2013-11-07 05:49:04 +01:00
} else if ( contents [ 1 ] = = SD_BUS_TYPE_STRUCT_BEGIN & & streq ( name , " BlockIODeviceWeight " ) ) {
const char * path ;
uint64_t weight ;
2013-08-27 07:36:55 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_enter_container ( m , SD_BUS_TYPE_ARRAY , " (st) " ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2013-08-27 07:36:55 +02:00
2013-11-07 05:49:04 +01:00
while ( ( r = sd_bus_message_read ( m , " (st) " , & path , & weight ) ) > 0 )
printf ( " %s=%s % " PRIu64 " \n " , name , strna ( path ) , weight ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2013-08-27 07:36:55 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_exit_container ( m ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2013-08-27 07:36:55 +02:00
return 0 ;
2013-11-07 05:49:04 +01:00
} else if ( contents [ 1 ] = = SD_BUS_TYPE_STRUCT_BEGIN & & ( streq ( name , " BlockIOReadBandwidth " ) | | streq ( name , " BlockIOWriteBandwidth " ) ) ) {
const char * path ;
uint64_t bandwidth ;
2013-06-27 04:14:27 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_enter_container ( m , SD_BUS_TYPE_ARRAY , " (st) " ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2013-06-27 04:14:27 +02:00
2013-11-07 05:49:04 +01:00
while ( ( r = sd_bus_message_read ( m , " (st) " , & path , & bandwidth ) ) > 0 )
printf ( " %s=%s % " PRIu64 " \n " , name , strna ( path ) , bandwidth ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2013-06-27 04:14:27 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_exit_container ( m ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2013-06-27 04:14:27 +02:00
return 0 ;
2010-07-04 03:43:57 +02:00
}
break ;
}
2013-11-07 05:49:04 +01:00
r = bus_print_property ( name , m , arg_all ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
if ( r = = 0 ) {
r = sd_bus_message_skip ( m , contents ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2011-07-08 21:39:10 +02:00
2013-11-07 05:49:04 +01:00
if ( arg_all )
printf ( " %s=[unprintable] \n " , name ) ;
}
2010-07-04 03:43:57 +02:00
return 0 ;
}
2013-11-07 05:49:04 +01:00
static int show_one (
const char * verb ,
sd_bus * bus ,
const char * path ,
bool show_properties ,
bool * new_line ,
bool * ellipsized ) {
_cleanup_bus_message_unref_ sd_bus_message * reply = NULL ;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL ;
2013-03-25 00:59:00 +01:00
UnitStatusInfo info = { } ;
2010-07-10 15:42:24 +02:00
ExecStatusInfo * p ;
2013-11-07 05:49:04 +01:00
int r ;
2010-07-04 03:43:57 +02:00
assert ( path ) ;
2010-07-05 02:40:39 +02:00
assert ( new_line ) ;
2010-07-04 03:43:57 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_call_method (
2012-08-08 01:32:30 +02:00
bus ,
" org.freedesktop.systemd1 " ,
path ,
" org.freedesktop.DBus.Properties " ,
" GetAll " ,
2013-11-07 05:49:04 +01:00
& error ,
2012-08-08 01:32:30 +02:00
& reply ,
2013-11-07 05:49:04 +01:00
" s " , " " ) ;
if ( r < 0 ) {
log_error ( " Failed to get properties: %s " , bus_error_message ( & error , r ) ) ;
2013-01-14 02:11:22 +01:00
return r ;
2010-07-04 03:43:57 +02:00
}
2013-11-07 05:49:04 +01:00
r = sd_bus_message_enter_container ( reply , SD_BUS_TYPE_ARRAY , " {sv} " ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2010-07-04 03:43:57 +02:00
2010-07-05 02:40:39 +02:00
if ( * new_line )
printf ( " \n " ) ;
* new_line = true ;
2013-11-07 05:49:04 +01:00
while ( ( r = sd_bus_message_enter_container ( reply , SD_BUS_TYPE_DICT_ENTRY , " sv " ) ) > 0 ) {
const char * name , * contents ;
2010-07-01 01:06:58 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_read ( reply , " s " , & name ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2010-07-04 03:43:57 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_peek_type ( reply , NULL , & contents ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
r = sd_bus_message_enter_container ( reply , SD_BUS_TYPE_VARIANT , contents ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2010-07-04 03:43:57 +02:00
2010-07-05 02:40:39 +02:00
if ( show_properties )
2013-11-07 05:49:04 +01:00
r = print_property ( name , reply , contents ) ;
2010-07-05 02:40:39 +02:00
else
2013-11-07 05:49:04 +01:00
r = status_property ( name , reply , & info , contents ) ;
if ( r < 0 )
return r ;
2010-07-04 03:43:57 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_exit_container ( reply ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
r = sd_bus_message_exit_container ( reply ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2010-07-04 03:43:57 +02:00
}
2013-11-07 05:49:04 +01:00
if ( r < 0 )
return bus_log_parse_error ( r ) ;
r = sd_bus_message_exit_container ( reply ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2010-07-04 03:43:57 +02:00
2010-08-25 03:13:09 +02:00
r = 0 ;
2012-05-31 04:11:57 +02:00
if ( ! show_properties ) {
2012-06-04 19:48:32 +02:00
if ( streq ( verb , " help " ) )
show_unit_help ( & info ) ;
2012-05-31 04:11:57 +02:00
else
2013-08-04 01:38:13 +02:00
print_status_info ( & info , ellipsized ) ;
2012-05-31 04:11:57 +02:00
}
2010-08-25 03:13:09 +02:00
2012-05-21 15:12:18 +02:00
strv_free ( info . documentation ) ;
2013-04-05 19:58:04 +02:00
strv_free ( info . dropin_paths ) ;
2013-04-01 22:09:45 +02:00
strv_free ( info . listen ) ;
2012-05-21 15:12:18 +02:00
2010-08-31 21:05:54 +02:00
if ( ! streq_ptr ( info . active_state , " active " ) & &
2010-11-21 22:40:03 +01:00
! streq_ptr ( info . active_state , " reloading " ) & &
2013-06-25 16:25:38 +02:00
streq ( verb , " status " ) ) {
2010-08-31 21:05:54 +02:00
/* According to LSB: "program not running" */
2013-06-25 13:06:51 +02:00
/* 0: program is running or service is OK
* 1 : program is dead and / var / run pid file exists
* 2 : program is dead and / var / lock lock file exists
* 3 : program is not running
* 4 : program or service status is unknown
*/
2013-06-25 16:25:38 +02:00
if ( info . pid_file & & access ( info . pid_file , F_OK ) = = 0 )
2013-06-25 13:06:51 +02:00
r = 1 ;
else
r = 3 ;
2013-07-02 13:24:48 +02:00
}
2010-07-05 02:40:39 +02:00
2010-07-10 15:42:24 +02:00
while ( ( p = info . exec ) ) {
2013-10-14 06:10:14 +02:00
LIST_REMOVE ( exec , info . exec , p ) ;
2010-07-10 15:42:24 +02:00
exec_status_info_free ( p ) ;
}
2010-07-04 03:43:57 +02:00
return r ;
}
2013-11-07 05:49:04 +01:00
static int show_one_by_pid (
const char * verb ,
sd_bus * bus ,
uint32_t pid ,
bool * new_line ,
bool * ellipsized ) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL ;
_cleanup_bus_message_unref_ sd_bus_message * reply = NULL ;
2012-05-21 12:54:43 +02:00
const char * path = NULL ;
int r ;
2013-11-07 05:49:04 +01:00
r = sd_bus_call_method (
2012-08-08 01:32:30 +02:00
bus ,
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
" GetUnitByPID " ,
2013-11-07 05:49:04 +01:00
& error ,
2012-08-08 01:32:30 +02:00
& reply ,
2013-11-07 05:49:04 +01:00
" u " , pid ) ;
if ( r < 0 ) {
log_error ( " Failed to get unit for PID %lu: %s " , ( unsigned long ) pid , bus_error_message ( & error , r ) ) ;
2013-02-14 19:32:19 +01:00
return r ;
2012-05-21 12:54:43 +02:00
}
2013-11-07 05:49:04 +01:00
r = sd_bus_message_read ( reply , " o " , & path ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
return show_one ( verb , bus , path , false , new_line , ellipsized ) ;
2012-05-21 12:54:43 +02:00
}
2013-11-07 05:49:04 +01:00
static int show_all (
const char * verb ,
sd_bus * bus ,
bool show_properties ,
bool * new_line ,
bool * ellipsized ) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL ;
_cleanup_bus_message_unref_ sd_bus_message * reply = NULL ;
_cleanup_free_ UnitInfo * unit_infos = NULL ;
const UnitInfo * u ;
unsigned c ;
2013-02-14 22:55:24 +01:00
int r ;
2013-11-07 05:49:04 +01:00
r = get_unit_list ( bus , & reply , & unit_infos ) ;
2013-02-14 22:55:24 +01:00
if ( r < 0 )
return r ;
2013-11-07 05:49:04 +01:00
c = ( unsigned ) r ;
qsort_safe ( unit_infos , c , sizeof ( UnitInfo ) , compare_unit_info ) ;
2013-04-12 00:59:18 +02:00
2013-02-14 22:55:24 +01:00
for ( u = unit_infos ; u < unit_infos + c ; u + + ) {
2013-04-18 09:11:22 +02:00
_cleanup_free_ char * p = NULL ;
2013-02-14 22:55:24 +01:00
if ( ! output_show_unit ( u ) )
continue ;
p = unit_dbus_path_from_name ( u - > id ) ;
if ( ! p )
return log_oom ( ) ;
printf ( " %s -> '%s' \n " , u - > id , p ) ;
2013-08-04 01:38:13 +02:00
r = show_one ( verb , bus , p , show_properties , new_line , ellipsized ) ;
2013-02-14 22:55:24 +01:00
if ( r ! = 0 )
return r ;
}
return 0 ;
}
2013-11-07 05:49:04 +01:00
static int show ( sd_bus * bus , char * * args ) {
2012-05-21 12:54:43 +02:00
int r , ret = 0 ;
2013-02-14 22:55:24 +01:00
bool show_properties , show_status , new_line = false ;
2011-07-25 04:58:02 +02:00
char * * name ;
2013-08-04 01:38:13 +02:00
bool ellipsized = false ;
2010-07-04 03:43:57 +02:00
assert ( bus ) ;
assert ( args ) ;
2012-05-31 04:11:57 +02:00
show_properties = streq ( args [ 0 ] , " show " ) ;
2013-02-14 22:55:24 +01:00
show_status = streq ( args [ 0 ] , " status " ) ;
2010-07-05 02:40:39 +02:00
2011-01-04 01:04:20 +01:00
if ( show_properties )
2011-07-07 02:34:35 +02:00
pager_open_if_enabled ( ) ;
2011-01-04 01:04:20 +01:00
2013-01-14 02:11:22 +01:00
/* If no argument is specified inspect the manager itself */
2010-07-04 03:43:57 +02:00
2013-01-14 02:11:22 +01:00
if ( show_properties & & strv_length ( args ) < = 1 )
2013-08-04 01:38:13 +02:00
return show_one ( args [ 0 ] , bus , " /org/freedesktop/systemd1 " , show_properties , & new_line , & ellipsized ) ;
2010-07-04 03:43:57 +02:00
2013-02-14 22:55:24 +01:00
if ( show_status & & strv_length ( args ) < = 1 )
2013-08-04 01:38:13 +02:00
ret = show_all ( args [ 0 ] , bus , false , & new_line , & ellipsized ) ;
else
STRV_FOREACH ( name , args + 1 ) {
uint32_t id ;
2010-07-04 03:43:57 +02:00
2013-08-04 01:38:13 +02:00
if ( safe_atou32 ( * name , & id ) < 0 ) {
_cleanup_free_ char * p = NULL , * n = NULL ;
/* Interpret as unit name */
2010-07-04 03:43:57 +02:00
2013-08-04 01:38:13 +02:00
n = unit_name_mangle ( * name ) ;
if ( ! n )
return log_oom ( ) ;
2013-01-14 02:11:22 +01:00
2013-08-04 01:38:13 +02:00
p = unit_dbus_path_from_name ( n ) ;
if ( ! p )
return log_oom ( ) ;
2010-07-04 03:43:57 +02:00
2013-08-04 01:38:13 +02:00
r = show_one ( args [ 0 ] , bus , p , show_properties , & new_line , & ellipsized ) ;
if ( r ! = 0 )
ret = r ;
2010-07-06 20:14:51 +02:00
2013-08-04 01:38:13 +02:00
} else if ( show_properties ) {
_cleanup_free_ char * p = NULL ;
2010-08-13 02:07:22 +02:00
2013-08-04 01:38:13 +02:00
/* Interpret as job id */
if ( asprintf ( & p , " /org/freedesktop/systemd1/job/%u " , id ) < 0 )
return log_oom ( ) ;
2010-07-04 03:43:57 +02:00
2013-08-04 01:38:13 +02:00
r = show_one ( args [ 0 ] , bus , p , show_properties , & new_line , & ellipsized ) ;
if ( r ! = 0 )
ret = r ;
2010-07-04 03:43:57 +02:00
2013-08-04 01:38:13 +02:00
} else {
/* Interpret as PID */
r = show_one_by_pid ( args [ 0 ] , bus , id , & new_line , & ellipsized ) ;
if ( r ! = 0 )
ret = r ;
}
2010-07-04 03:43:57 +02:00
}
2013-08-04 01:38:13 +02:00
if ( ellipsized & & ! arg_quiet )
printf ( " Hint: Some lines were ellipsized, use -l to show in full. \n " ) ;
2010-07-04 03:43:57 +02:00
2010-08-31 21:05:54 +02:00
return ret ;
2010-07-01 01:06:58 +02:00
}
2013-11-07 05:49:04 +01:00
static int append_assignment ( sd_bus_message * m , const char * assignment ) {
2013-06-27 21:14:56 +02:00
const char * eq ;
char * field ;
int r ;
2013-11-07 05:49:04 +01:00
assert ( m ) ;
2013-06-27 21:14:56 +02:00
assert ( assignment ) ;
eq = strchr ( assignment , ' = ' ) ;
if ( ! eq ) {
log_error ( " Not an assignment: %s " , assignment ) ;
return - EINVAL ;
}
field = strndupa ( assignment , eq - assignment ) ;
eq + + ;
2013-11-07 05:49:04 +01:00
r = sd_bus_message_append_basic ( m , SD_BUS_TYPE_STRING , field ) ;
if ( r < 0 )
return bus_log_create_error ( r ) ;
2013-06-27 21:14:56 +02:00
if ( streq ( field , " CPUAccounting " ) | |
streq ( field , " MemoryAccounting " ) | |
streq ( field , " BlockIOAccounting " ) ) {
r = parse_boolean ( eq ) ;
if ( r < 0 ) {
log_error ( " Failed to parse boolean assignment %s. " , assignment ) ;
return - EINVAL ;
}
2013-11-07 05:49:04 +01:00
r = sd_bus_message_append ( m , " v " , " b " , r ) ;
2013-06-27 21:50:35 +02:00
2013-09-17 21:58:00 +02:00
} else if ( streq ( field , " MemoryLimit " ) ) {
2013-06-27 21:50:35 +02:00
off_t bytes ;
r = parse_bytes ( eq , & bytes ) ;
if ( r < 0 ) {
log_error ( " Failed to parse bytes specification %s " , assignment ) ;
return - EINVAL ;
}
2013-11-07 05:49:04 +01:00
r = sd_bus_message_append ( m , " v " , " t " , ( uint64_t ) bytes ) ;
2013-06-27 21:50:35 +02:00
} else if ( streq ( field , " CPUShares " ) | | streq ( field , " BlockIOWeight " ) ) {
uint64_t u ;
r = safe_atou64 ( eq , & u ) ;
if ( r < 0 ) {
log_error ( " Failed to parse %s value %s. " , field , eq ) ;
return - EINVAL ;
}
2013-11-07 05:49:04 +01:00
r = sd_bus_message_append ( m , " v " , " t " , u ) ;
2013-06-27 23:13:17 +02:00
2013-11-07 05:49:04 +01:00
} else if ( streq ( field , " DevicePolicy " ) )
r = sd_bus_message_append ( m , " v " , " s " , eq ) ;
2013-06-27 23:13:17 +02:00
2013-11-07 05:49:04 +01:00
else if ( streq ( field , " DeviceAllow " ) ) {
2013-06-27 23:13:17 +02:00
2013-11-07 05:49:04 +01:00
if ( isempty ( eq ) )
r = sd_bus_message_append ( m , " v " , " a(ss) " , 0 ) ;
else {
2013-06-27 23:13:17 +02:00
const char * path , * rwm ;
char * e ;
e = strchr ( eq , ' ' ) ;
if ( e ) {
path = strndupa ( eq , e - eq ) ;
rwm = e + 1 ;
} else {
path = eq ;
rwm = " " ;
}
2013-08-30 04:56:02 +02:00
if ( ! path_startswith ( path , " /dev " ) ) {
log_error ( " %s is not a device file in /dev. " , path ) ;
return - EINVAL ;
}
2013-11-07 05:49:04 +01:00
r = sd_bus_message_append ( m , " v " , " a(ss) " , 1 , path , rwm ) ;
2013-06-27 23:13:17 +02:00
}
2013-08-30 04:56:02 +02:00
} else if ( streq ( field , " BlockIOReadBandwidth " ) | | streq ( field , " BlockIOWriteBandwidth " ) ) {
2013-11-07 05:49:04 +01:00
if ( isempty ( eq ) )
r = sd_bus_message_append ( m , " v " , " a(st) " , 0 ) ;
else {
2013-08-30 04:56:02 +02:00
const char * path , * bandwidth ;
off_t bytes ;
char * e ;
e = strchr ( eq , ' ' ) ;
if ( e ) {
path = strndupa ( eq , e - eq ) ;
bandwidth = e + 1 ;
} else {
log_error ( " Failed to parse %s value %s. " , field , eq ) ;
return - EINVAL ;
}
if ( ! path_startswith ( path , " /dev " ) ) {
log_error ( " %s is not a device file in /dev. " , path ) ;
return - EINVAL ;
}
r = parse_bytes ( bandwidth , & bytes ) ;
if ( r < 0 ) {
log_error ( " Failed to parse byte value %s. " , bandwidth ) ;
return - EINVAL ;
}
2013-11-07 05:49:04 +01:00
r = sd_bus_message_append ( m , " v " , " a(st) " , 1 , path , ( uint64_t ) bytes ) ;
2013-08-30 04:56:02 +02:00
}
2013-08-27 07:36:54 +02:00
} else if ( streq ( field , " BlockIODeviceWeight " ) ) {
2013-11-07 05:49:04 +01:00
if ( isempty ( eq ) )
r = sd_bus_message_append ( m , " v " , " a(st) " , 0 ) ;
else {
2013-08-27 07:36:54 +02:00
const char * path , * weight ;
uint64_t u ;
char * e ;
e = strchr ( eq , ' ' ) ;
if ( e ) {
path = strndupa ( eq , e - eq ) ;
weight = e + 1 ;
} else {
log_error ( " Failed to parse %s value %s. " , field , eq ) ;
return - EINVAL ;
}
if ( ! path_startswith ( path , " /dev " ) ) {
log_error ( " %s is not a device file in /dev. " , path ) ;
return - EINVAL ;
}
r = safe_atou64 ( weight , & u ) ;
if ( r < 0 ) {
log_error ( " Failed to parse %s value %s. " , field , weight ) ;
return - EINVAL ;
}
2013-11-07 05:49:04 +01:00
r = sd_bus_message_append ( m , " v " , " a(st) " , path , u ) ;
2013-08-27 07:36:54 +02:00
}
2013-06-27 21:14:56 +02:00
} else {
log_error ( " Unknown assignment %s. " , assignment ) ;
return - EINVAL ;
}
2013-11-07 05:49:04 +01:00
if ( r < 0 )
return bus_log_create_error ( r ) ;
2013-06-27 21:14:56 +02:00
return 0 ;
}
2013-11-07 05:49:04 +01:00
static int set_property ( sd_bus * bus , char * * args ) {
_cleanup_bus_message_unref_ sd_bus_message * m = NULL ;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL ;
2013-09-27 00:11:54 +02:00
_cleanup_free_ char * n = NULL ;
2013-06-27 21:14:56 +02:00
char * * i ;
int r ;
2013-11-07 05:49:04 +01:00
r = sd_bus_message_new_method_call (
bus ,
2013-06-27 21:14:56 +02:00
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
2013-11-07 05:49:04 +01:00
" SetUnitProperties " ,
& m ) ;
if ( r < 0 )
return bus_log_create_error ( r ) ;
2013-06-27 21:14:56 +02:00
2013-09-27 00:11:54 +02:00
n = unit_name_mangle ( args [ 1 ] ) ;
if ( ! n )
return log_oom ( ) ;
2013-11-07 05:49:04 +01:00
r = sd_bus_message_append ( m , " sb " , n , arg_runtime ) ;
if ( r < 0 )
return bus_log_create_error ( r ) ;
2013-06-27 21:14:56 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_open_container ( m , SD_BUS_TYPE_ARRAY , " (sv) " ) ;
if ( r < 0 )
return bus_log_create_error ( r ) ;
2013-06-27 21:14:56 +02:00
2013-11-07 05:49:04 +01:00
STRV_FOREACH ( i , args + 2 ) {
r = sd_bus_message_open_container ( m , SD_BUS_TYPE_STRUCT , " sv " ) ;
if ( r < 0 )
return bus_log_create_error ( r ) ;
2013-06-27 21:14:56 +02:00
2013-11-07 05:49:04 +01:00
r = append_assignment ( m , * i ) ;
2013-06-27 21:14:56 +02:00
if ( r < 0 )
return r ;
2013-11-07 05:49:04 +01:00
r = sd_bus_message_close_container ( m ) ;
if ( r < 0 )
return bus_log_create_error ( r ) ;
2013-06-27 21:14:56 +02:00
}
2013-11-07 05:49:04 +01:00
r = sd_bus_message_close_container ( m ) ;
if ( r < 0 )
return bus_log_create_error ( r ) ;
2013-06-27 21:14:56 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_send_with_reply_and_block ( bus , m , - 1 , & error , NULL ) ;
if ( r < 0 ) {
log_error ( " Failed to set unit properties on %s: %s " , n , bus_error_message ( & error , r ) ) ;
return r ;
2013-06-27 21:14:56 +02:00
}
return 0 ;
}
2013-11-07 05:49:04 +01:00
static int snapshot ( sd_bus * bus , char * * args ) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL ;
_cleanup_bus_message_unref_ sd_bus_message * reply = NULL ;
_cleanup_free_ char * n = NULL , * id = NULL ;
const char * path ;
2010-06-15 02:51:55 +02:00
int r ;
2013-01-14 02:11:57 +01:00
if ( strv_length ( args ) > 1 )
2013-06-17 21:33:26 +02:00
n = unit_name_mangle_with_suffix ( args [ 1 ] , " .snapshot " ) ;
2013-01-14 02:11:57 +01:00
else
n = strdup ( " " ) ;
if ( ! n )
return log_oom ( ) ;
2010-06-15 02:51:55 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_call_method (
2012-08-08 01:32:30 +02:00
bus ,
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
" CreateSnapshot " ,
2013-11-07 05:49:04 +01:00
& error ,
2012-08-08 01:32:30 +02:00
& reply ,
2013-11-07 05:49:04 +01:00
" sb " , n , false ) ;
if ( r < 0 ) {
log_error ( " Failed to create snapshot: %s " , bus_error_message ( & error , r ) ) ;
2013-01-14 02:11:57 +01:00
return r ;
2010-06-15 02:51:55 +02:00
}
2013-11-07 05:49:04 +01:00
r = sd_bus_message_read ( reply , " o " , & path ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2013-01-10 22:45:45 +01:00
2013-11-07 05:49:04 +01:00
r = sd_bus_get_property_string (
2012-08-08 01:32:30 +02:00
bus ,
" org.freedesktop.systemd1 " ,
path ,
2013-11-07 05:49:04 +01:00
" org.freedesktop.systemd1.Unit " ,
" Id " ,
& error ,
& id ) ;
if ( r < 0 ) {
log_error ( " Failed to get ID of snapshot: %s " , bus_error_message ( & error , r ) ) ;
2013-01-14 02:11:57 +01:00
return r ;
2010-06-15 02:51:55 +02:00
}
2010-07-01 01:06:58 +02:00
if ( ! arg_quiet )
puts ( id ) ;
2010-06-15 02:51:55 +02:00
2013-01-14 02:11:57 +01:00
return 0 ;
2010-06-15 02:51:55 +02:00
}
2013-11-07 05:49:04 +01:00
static int delete_snapshot ( sd_bus * bus , char * * args ) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL ;
2011-07-25 04:58:02 +02:00
char * * name ;
2013-11-07 05:49:04 +01:00
int r ;
2010-07-02 03:51:05 +02:00
assert ( args ) ;
2011-07-25 04:58:02 +02:00
STRV_FOREACH ( name , args + 1 ) {
2013-01-10 22:45:45 +01:00
_cleanup_free_ char * n = NULL ;
2010-07-02 03:51:05 +02:00
2013-06-17 21:33:26 +02:00
n = unit_name_mangle_with_suffix ( * name , " .snapshot " ) ;
2013-01-14 02:11:57 +01:00
if ( ! n )
return log_oom ( ) ;
2013-11-07 05:49:04 +01:00
r = sd_bus_call_method (
2012-08-08 01:32:30 +02:00
bus ,
2012-06-22 13:08:48 +02:00
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
2013-01-10 22:45:45 +01:00
" RemoveSnapshot " ,
2013-11-07 05:49:04 +01:00
& error ,
2012-08-08 01:32:30 +02:00
NULL ,
2013-11-07 05:49:04 +01:00
" s " , n ) ;
if ( r < 0 ) {
log_error ( " Failed to remove snapshot %s: %s " , n , bus_error_message ( & error , r ) ) ;
2013-01-10 22:45:45 +01:00
return r ;
2013-11-07 05:49:04 +01:00
}
2010-07-02 03:51:05 +02:00
}
2013-01-10 22:45:45 +01:00
return 0 ;
2010-07-02 03:51:05 +02:00
}
2013-11-07 05:49:04 +01:00
static int daemon_reload ( sd_bus * bus , char * * args ) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL ;
2010-06-15 02:51:55 +02:00
const char * method ;
2013-11-07 05:49:04 +01:00
int r ;
2010-06-15 02:51:55 +02:00
2010-06-17 22:57:28 +02:00
if ( arg_action = = ACTION_RELOAD )
method = " Reload " ;
else if ( arg_action = = ACTION_REEXEC )
method = " Reexecute " ;
else {
assert ( arg_action = = ACTION_SYSTEMCTL ) ;
method =
2010-10-14 00:56:12 +02:00
streq ( args [ 0 ] , " clear-jobs " ) | |
streq ( args [ 0 ] , " cancel " ) ? " ClearJobs " :
streq ( args [ 0 ] , " daemon-reexec " ) ? " Reexecute " :
streq ( args [ 0 ] , " reset-failed " ) ? " ResetFailed " :
streq ( args [ 0 ] , " halt " ) ? " Halt " :
streq ( args [ 0 ] , " poweroff " ) ? " PowerOff " :
streq ( args [ 0 ] , " reboot " ) ? " Reboot " :
streq ( args [ 0 ] , " kexec " ) ? " KExec " :
streq ( args [ 0 ] , " exit " ) ? " Exit " :
/* "daemon-reload" */ " Reload " ;
2010-06-17 22:57:28 +02:00
}
2010-06-15 02:51:55 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_call_method (
2012-08-08 01:32:30 +02:00
bus ,
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
method ,
2012-08-10 17:32:19 +02:00
& error ,
2013-11-07 05:49:04 +01:00
NULL ,
NULL ) ;
2012-08-08 01:32:30 +02:00
if ( r = = - ENOENT & & arg_action ! = ACTION_SYSTEMCTL )
/* There's always a fallback possible for
* legacy actions . */
r = - EADDRNOTAVAIL ;
2013-07-10 20:44:21 +02:00
else if ( ( r = = - ETIMEDOUT | | r = = - ECONNRESET ) & & streq ( method , " Reexecute " ) )
/* On reexecution, we expect a disconnect, not a
* reply */
2012-08-08 01:32:30 +02:00
r = 0 ;
2013-01-14 02:11:57 +01:00
else if ( r < 0 )
2013-11-07 05:49:04 +01:00
log_error ( " Failed to execute operation: %s " , bus_error_message ( & error , r ) ) ;
2010-06-15 02:51:55 +02:00
return r ;
}
2013-11-07 05:49:04 +01:00
static int reset_failed ( sd_bus * bus , char * * args ) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL ;
2013-01-14 02:11:22 +01:00
char * * name ;
2013-11-07 05:49:04 +01:00
int r ;
2010-07-18 04:58:01 +02:00
2011-07-25 04:58:02 +02:00
if ( strv_length ( args ) < = 1 )
return daemon_reload ( bus , args ) ;
2010-07-18 04:58:01 +02:00
2011-07-25 04:58:02 +02:00
STRV_FOREACH ( name , args + 1 ) {
2013-01-14 02:11:22 +01:00
_cleanup_free_ char * n ;
2012-08-08 01:32:30 +02:00
n = unit_name_mangle ( * name ) ;
2013-01-14 02:11:22 +01:00
if ( ! n )
return log_oom ( ) ;
2013-11-07 05:49:04 +01:00
r = sd_bus_call_method (
2012-08-08 01:32:30 +02:00
bus ,
2012-06-22 13:08:48 +02:00
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
2012-08-08 01:32:30 +02:00
" ResetFailedUnit " ,
2013-11-07 05:49:04 +01:00
& error ,
2012-08-08 01:32:30 +02:00
NULL ,
2013-11-07 05:49:04 +01:00
" s " , n ) ;
if ( r < 0 ) {
log_error ( " Failed to reset failed state of unit %s: %s " , n , bus_error_message ( & error , r ) ) ;
2013-01-14 02:11:22 +01:00
return r ;
2013-11-07 05:49:04 +01:00
}
2010-07-18 04:58:01 +02:00
}
2013-01-14 02:11:22 +01:00
return 0 ;
2010-07-18 04:58:01 +02:00
}
2013-11-07 05:49:04 +01:00
static int show_environment ( sd_bus * bus , char * * args ) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL ;
_cleanup_bus_message_unref_ sd_bus_message * reply = NULL ;
const char * text ;
2010-06-15 02:51:55 +02:00
int r ;
2011-07-07 02:34:35 +02:00
pager_open_if_enabled ( ) ;
2011-01-04 01:04:20 +01:00
2013-11-07 05:49:04 +01:00
r = sd_bus_get_property (
2012-08-08 01:32:30 +02:00
bus ,
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
2013-11-07 05:49:04 +01:00
" org.freedesktop.systemd1.Manager " ,
" Environment " ,
& error ,
2012-08-08 01:32:30 +02:00
& reply ,
2013-11-07 05:49:04 +01:00
" as " ) ;
if ( r < 0 ) {
log_error ( " Failed to get environment: %s " , bus_error_message ( & error , r ) ) ;
2013-01-14 02:11:22 +01:00
return r ;
2010-06-15 02:51:55 +02:00
}
2013-11-07 05:49:04 +01:00
r = sd_bus_message_enter_container ( reply , SD_BUS_TYPE_ARRAY , " s " ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2010-06-15 02:51:55 +02:00
2013-11-07 05:49:04 +01:00
while ( ( r = sd_bus_message_read_basic ( reply , SD_BUS_TYPE_STRING , & text ) ) > 0 )
2013-01-14 02:11:22 +01:00
puts ( text ) ;
2013-11-07 05:49:04 +01:00
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2010-06-15 02:51:55 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_exit_container ( reply ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2010-06-15 02:51:55 +02:00
2013-01-14 02:11:22 +01:00
return 0 ;
2010-06-15 02:51:55 +02:00
}
2013-11-07 05:49:04 +01:00
static int switch_root ( sd_bus * bus , char * * args ) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL ;
2012-11-21 23:22:03 +01:00
_cleanup_free_ char * init = NULL ;
2013-11-07 05:49:04 +01:00
const char * root ;
unsigned l ;
int r ;
2012-05-11 17:35:46 +02:00
l = strv_length ( args ) ;
if ( l < 2 | | l > 3 ) {
log_error ( " Wrong number of arguments. " ) ;
return - EINVAL ;
}
root = args [ 1 ] ;
2012-11-21 23:22:03 +01:00
if ( l > = 3 )
init = strdup ( args [ 2 ] ) ;
else {
parse_env_file ( " /proc/cmdline " , WHITESPACE ,
" init " , & init ,
NULL ) ;
if ( ! init )
init = strdup ( " " ) ;
}
2013-11-07 05:49:04 +01:00
2013-01-14 02:11:22 +01:00
if ( ! init )
return log_oom ( ) ;
2012-11-21 23:22:03 +01:00
log_debug ( " switching root - root: %s; init: %s " , root , init ) ;
2012-05-11 17:35:46 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_call_method (
2012-08-08 01:32:30 +02:00
bus ,
2012-05-11 17:35:46 +02:00
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
2012-08-08 01:32:30 +02:00
" SwitchRoot " ,
2013-11-07 05:49:04 +01:00
& error ,
2012-08-08 01:32:30 +02:00
NULL ,
2013-11-07 05:49:04 +01:00
" ss " , root , init ) ;
if ( r < 0 ) {
log_error ( " Failed to switch root: %s " , bus_error_message ( & error , r ) ) ;
return r ;
}
return 0 ;
2012-05-11 17:35:46 +02:00
}
2013-11-07 05:49:04 +01:00
static int set_environment ( sd_bus * bus , char * * args ) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL ;
_cleanup_bus_message_unref_ sd_bus_message * m = NULL ;
2010-06-15 02:51:55 +02:00
const char * method ;
2012-10-19 04:53:12 +02:00
int r ;
assert ( bus ) ;
2013-01-11 23:59:41 +01:00
assert ( args ) ;
2010-06-15 02:51:55 +02:00
method = streq ( args [ 0 ] , " set-environment " )
? " SetEnvironment "
: " UnsetEnvironment " ;
2013-11-07 05:49:04 +01:00
r = sd_bus_message_new_method_call (
bus ,
2012-10-19 04:53:12 +02:00
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
2013-11-07 05:49:04 +01:00
method ,
& m ) ;
if ( r < 0 )
return bus_log_create_error ( r ) ;
2010-06-15 02:51:55 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_append_strv ( m , args + 1 ) ;
2012-10-19 04:53:12 +02:00
if ( r < 0 )
2013-11-07 05:49:04 +01:00
return bus_log_create_error ( r ) ;
2010-06-15 02:51:55 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_send_with_reply_and_block ( bus , m , - 1 , & error , NULL ) ;
if ( r < 0 ) {
log_error ( " Failed to set environment: %s " , bus_error_message ( & error , r ) ) ;
return r ;
2010-06-15 02:51:55 +02:00
}
2013-01-14 02:11:22 +01:00
return 0 ;
2010-06-15 02:51:55 +02:00
}
2013-10-02 16:42:42 +02:00
static int enable_sysv_units ( const char * verb , char * * args ) {
2011-07-25 04:58:02 +02:00
int r = 0 ;
2010-07-24 00:53:33 +02:00
2013-01-04 22:32:31 +01:00
# if defined(HAVE_SYSV_COMPAT) && defined(HAVE_CHKCONFIG)
2011-07-25 04:58:02 +02:00
unsigned f = 1 , t = 1 ;
2013-10-27 12:45:52 +01:00
_cleanup_lookup_paths_free_ LookupPaths paths = { } ;
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
if ( arg_scope ! = UNIT_FILE_SYSTEM )
return 0 ;
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
if ( ! streq ( verb , " enable " ) & &
! streq ( verb , " disable " ) & &
! streq ( verb , " is-enabled " ) )
return 0 ;
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
/* Processes all SysV units, and reshuffles the array so that
* afterwards only the native units remain */
2010-07-24 00:53:33 +02:00
2012-09-18 17:11:12 +02:00
r = lookup_paths_init ( & paths , SYSTEMD_SYSTEM , false , NULL , NULL , NULL ) ;
2011-07-25 04:58:02 +02:00
if ( r < 0 )
return r ;
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
r = 0 ;
2013-10-02 16:42:42 +02:00
for ( f = 0 ; args [ f ] ; f + + ) {
2011-07-25 04:58:02 +02:00
const char * name ;
2013-04-18 09:11:22 +02:00
_cleanup_free_ char * p = NULL , * q = NULL ;
2011-07-25 04:58:02 +02:00
bool found_native = false , found_sysv ;
unsigned c = 1 ;
const char * argv [ 6 ] = { " /sbin/chkconfig " , NULL , NULL , NULL , NULL } ;
2013-04-17 12:03:20 +02:00
char * * k , * l ;
2011-07-25 04:58:02 +02:00
int j ;
pid_t pid ;
siginfo_t status ;
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
name = args [ f ] ;
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
if ( ! endswith ( name , " .service " ) )
continue ;
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
if ( path_is_absolute ( name ) )
continue ;
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
STRV_FOREACH ( k , paths . unit_path ) {
if ( ! isempty ( arg_root ) )
asprintf ( & p , " %s/%s/%s " , arg_root , * k , name ) ;
else
asprintf ( & p , " %s/%s " , * k , name ) ;
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
if ( ! p ) {
2012-07-25 23:55:59 +02:00
r = log_oom ( ) ;
2011-07-25 04:58:02 +02:00
goto finish ;
}
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
found_native = access ( p , F_OK ) > = 0 ;
free ( p ) ;
2013-04-17 12:03:20 +02:00
p = NULL ;
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
if ( found_native )
break ;
}
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
if ( found_native )
continue ;
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
if ( ! isempty ( arg_root ) )
asprintf ( & p , " %s/ " SYSTEM_SYSVINIT_PATH " /%s " , arg_root , name ) ;
else
asprintf ( & p , SYSTEM_SYSVINIT_PATH " /%s " , name ) ;
if ( ! p ) {
2012-07-25 23:55:59 +02:00
r = log_oom ( ) ;
2011-07-25 04:58:02 +02:00
goto finish ;
}
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
p [ strlen ( p ) - sizeof ( " .service " ) + 1 ] = 0 ;
found_sysv = access ( p , F_OK ) > = 0 ;
2010-07-24 00:53:33 +02:00
2013-04-17 12:03:20 +02:00
if ( ! found_sysv )
2011-07-25 04:58:02 +02:00
continue ;
2010-10-06 02:33:40 +02:00
2011-07-25 04:58:02 +02:00
/* Mark this entry, so that we don't try enabling it as native unit */
args [ f ] = ( char * ) " " ;
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
log_info ( " %s is not a native service, redirecting to /sbin/chkconfig. " , name ) ;
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
if ( ! isempty ( arg_root ) )
argv [ c + + ] = q = strappend ( " --root= " , arg_root ) ;
2010-07-24 00:53:33 +02:00
2012-05-07 21:36:12 +02:00
argv [ c + + ] = path_get_file_name ( p ) ;
2011-07-25 04:58:02 +02:00
argv [ c + + ] =
streq ( verb , " enable " ) ? " on " :
streq ( verb , " disable " ) ? " off " : " --level=5 " ;
argv [ c ] = NULL ;
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
l = strv_join ( ( char * * ) argv , " " ) ;
if ( ! l ) {
2012-07-25 23:55:59 +02:00
r = log_oom ( ) ;
2011-07-25 04:58:02 +02:00
goto finish ;
}
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
log_info ( " Executing %s " , l ) ;
free ( l ) ;
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
pid = fork ( ) ;
if ( pid < 0 ) {
log_error ( " Failed to fork: %m " ) ;
r = - errno ;
goto finish ;
} else if ( pid = = 0 ) {
/* Child */
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
execv ( argv [ 0 ] , ( char * * ) argv ) ;
_exit ( EXIT_FAILURE ) ;
}
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
j = wait_for_terminate ( pid , & status ) ;
if ( j < 0 ) {
log_error ( " Failed to wait for child: %s " , strerror ( - r ) ) ;
r = j ;
goto finish ;
}
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
if ( status . si_code = = CLD_EXITED ) {
if ( streq ( verb , " is-enabled " ) ) {
if ( status . si_status = = 0 ) {
if ( ! arg_quiet )
puts ( " enabled " ) ;
r = 1 ;
} else {
if ( ! arg_quiet )
puts ( " disabled " ) ;
}
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
} else if ( status . si_status ! = 0 ) {
r = - EINVAL ;
goto finish ;
}
} else {
r = - EPROTO ;
goto finish ;
}
2010-07-24 00:53:33 +02:00
}
2011-07-25 04:58:02 +02:00
finish :
/* Drop all SysV units */
2013-10-02 16:42:42 +02:00
for ( f = 0 , t = 0 ; args [ f ] ; f + + ) {
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
if ( isempty ( args [ f ] ) )
2010-07-24 00:53:33 +02:00
continue ;
2011-07-25 04:58:02 +02:00
args [ t + + ] = args [ f ] ;
}
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
args [ t ] = NULL ;
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
# endif
return r ;
}
2010-07-24 00:53:33 +02:00
2012-09-13 22:35:18 +02:00
static int mangle_names ( char * * original_names , char * * * mangled_names ) {
2012-09-13 22:42:22 +02:00
char * * i , * * l , * * name ;
2012-09-13 22:35:18 +02:00
2012-09-13 22:42:22 +02:00
l = new ( char * , strv_length ( original_names ) + 1 ) ;
if ( ! l )
2012-09-13 22:35:18 +02:00
return log_oom ( ) ;
2012-09-13 22:42:22 +02:00
i = l ;
2012-09-13 22:35:18 +02:00
STRV_FOREACH ( name , original_names ) {
2012-10-15 14:51:27 +02:00
/* When enabling units qualified path names are OK,
* too , hence allow them explicitly . */
if ( is_path ( * name ) )
* i = strdup ( * name ) ;
else
* i = unit_name_mangle ( * name ) ;
2012-09-13 22:42:22 +02:00
if ( ! * i ) {
strv_free ( l ) ;
2012-09-13 22:35:18 +02:00
return log_oom ( ) ;
2012-09-13 22:42:22 +02:00
}
i + + ;
2012-09-13 22:35:18 +02:00
}
2012-09-13 22:42:22 +02:00
* i = NULL ;
* mangled_names = l ;
2012-09-13 22:35:18 +02:00
return 0 ;
}
2013-11-07 05:49:04 +01:00
static int enable_unit ( sd_bus * bus , char * * args ) {
_cleanup_bus_message_unref_ sd_bus_message * reply = NULL , * m = NULL ;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL ;
_cleanup_strv_free_ char * * mangled_names = NULL ;
2011-07-25 04:58:02 +02:00
const char * verb = args [ 0 ] ;
UnitFileChange * changes = NULL ;
unsigned n_changes = 0 , i ;
int carries_install_info = - 1 ;
int r ;
2010-07-24 00:53:33 +02:00
2012-02-09 10:05:15 +01:00
if ( ! args [ 1 ] )
return 0 ;
2013-05-17 16:03:36 +02:00
r = mangle_names ( args + 1 , & mangled_names ) ;
if ( r < 0 )
2013-10-02 16:42:42 +02:00
return r ;
r = enable_sysv_units ( verb , mangled_names ) ;
if ( r < 0 )
return r ;
2013-05-17 16:03:36 +02:00
2011-07-25 04:58:02 +02:00
if ( ! bus | | avoid_bus ( ) ) {
if ( streq ( verb , " enable " ) ) {
2013-05-17 16:03:36 +02:00
r = unit_file_enable ( arg_scope , arg_runtime , arg_root , mangled_names , arg_force , & changes , & n_changes ) ;
2011-07-25 04:58:02 +02:00
carries_install_info = r ;
} else if ( streq ( verb , " disable " ) )
2013-05-17 16:03:36 +02:00
r = unit_file_disable ( arg_scope , arg_runtime , arg_root , mangled_names , & changes , & n_changes ) ;
2011-07-25 04:58:02 +02:00
else if ( streq ( verb , " reenable " ) ) {
2013-05-17 16:03:36 +02:00
r = unit_file_reenable ( arg_scope , arg_runtime , arg_root , mangled_names , arg_force , & changes , & n_changes ) ;
2011-07-25 04:58:02 +02:00
carries_install_info = r ;
} else if ( streq ( verb , " link " ) )
2013-05-17 16:03:36 +02:00
r = unit_file_link ( arg_scope , arg_runtime , arg_root , mangled_names , arg_force , & changes , & n_changes ) ;
2011-07-25 04:58:02 +02:00
else if ( streq ( verb , " preset " ) ) {
2013-05-17 16:03:36 +02:00
r = unit_file_preset ( arg_scope , arg_runtime , arg_root , mangled_names , arg_force , & changes , & n_changes ) ;
2011-07-25 04:58:02 +02:00
carries_install_info = r ;
} else if ( streq ( verb , " mask " ) )
2013-05-17 16:03:36 +02:00
r = unit_file_mask ( arg_scope , arg_runtime , arg_root , mangled_names , arg_force , & changes , & n_changes ) ;
2011-07-25 04:58:02 +02:00
else if ( streq ( verb , " unmask " ) )
2013-05-17 16:03:36 +02:00
r = unit_file_unmask ( arg_scope , arg_runtime , arg_root , mangled_names , & changes , & n_changes ) ;
2013-05-28 11:05:48 +02:00
else if ( streq ( verb , " set-default " ) )
r = unit_file_set_default ( arg_scope , arg_root , args [ 1 ] , & changes , & n_changes ) ;
2011-07-25 04:58:02 +02:00
else
assert_not_reached ( " Unknown verb " ) ;
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
if ( r < 0 ) {
log_error ( " Operation failed: %s " , strerror ( - r ) ) ;
goto finish ;
2010-07-24 00:53:33 +02:00
}
2012-01-21 03:44:11 +01:00
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 ) ;
}
2010-07-24 00:53:33 +02:00
}
2012-10-17 16:03:49 +02:00
r = 0 ;
2011-07-25 04:58:02 +02:00
} else {
2013-11-07 05:49:04 +01:00
const char * method , * type , * path , * source ;
int expect_carries_install_info = false ;
bool send_force = true ;
2011-07-25 04:58:02 +02:00
if ( streq ( verb , " enable " ) ) {
method = " EnableUnitFiles " ;
expect_carries_install_info = true ;
} else if ( streq ( verb , " disable " ) ) {
method = " DisableUnitFiles " ;
send_force = false ;
} else if ( streq ( verb , " reenable " ) ) {
method = " ReenableUnitFiles " ;
expect_carries_install_info = true ;
} else if ( streq ( verb , " link " ) )
method = " LinkUnitFiles " ;
else if ( streq ( verb , " preset " ) ) {
method = " PresetUnitFiles " ;
expect_carries_install_info = true ;
} else if ( streq ( verb , " mask " ) )
method = " MaskUnitFiles " ;
else if ( streq ( verb , " unmask " ) ) {
method = " UnmaskUnitFiles " ;
send_force = false ;
2013-05-28 11:05:48 +02:00
} else if ( streq ( verb , " set-default " ) ) {
method = " SetDefaultTarget " ;
2011-07-25 04:58:02 +02:00
} else
assert_not_reached ( " Unknown verb " ) ;
2013-11-07 05:49:04 +01:00
r = sd_bus_message_new_method_call (
bus ,
2011-07-25 04:58:02 +02:00
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
2013-11-07 05:49:04 +01:00
method ,
& m ) ;
if ( r < 0 )
return bus_log_create_error ( r ) ;
2010-07-24 00:53:33 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_append_strv ( m , mangled_names ) ;
if ( r < 0 )
return bus_log_create_error ( r ) ;
2010-07-24 00:53:33 +02:00
2013-11-07 05:49:04 +01:00
r = sd_bus_message_append ( m , " b " , arg_runtime ) ;
if ( r < 0 )
return bus_log_create_error ( r ) ;
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
if ( send_force ) {
2013-11-07 05:49:04 +01:00
r = sd_bus_message_append ( m , " b " , arg_force ) ;
if ( r < 0 )
return bus_log_create_error ( r ) ;
2010-07-24 00:53:33 +02:00
}
2013-11-07 05:49:04 +01:00
r = sd_bus_send_with_reply_and_block ( bus , m , - 0 , & error , & reply ) ;
if ( r < 0 ) {
log_error ( " Failed to execute operation: %s " , bus_error_message ( & error , r ) ) ;
return r ;
2011-07-25 04:58:02 +02:00
}
2011-06-24 15:02:57 +02:00
2011-07-25 04:58:02 +02:00
if ( expect_carries_install_info ) {
2013-11-07 05:49:04 +01:00
r = sd_bus_message_read ( reply , " b " , & carries_install_info ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2010-07-24 00:53:33 +02:00
}
2013-11-07 05:49:04 +01:00
r = sd_bus_message_enter_container ( reply , SD_BUS_TYPE_ARRAY , " (sss) " ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2010-11-21 22:17:04 +01:00
2013-11-07 05:49:04 +01:00
while ( ( r = sd_bus_message_read ( reply , " (sss) " , & type , & path , & source ) ) > 0 ) {
2012-01-21 03:44:11 +01:00
if ( ! arg_quiet ) {
if ( streq ( type , " symlink " ) )
log_info ( " ln -s '%s' '%s' " , source , path ) ;
else
log_info ( " rm '%s' " , path ) ;
}
2011-07-25 04:58:02 +02:00
}
2013-11-07 05:49:04 +01:00
if ( r < 0 )
return bus_log_parse_error ( r ) ;
r = sd_bus_message_exit_container ( reply ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2011-06-13 14:19:47 +02:00
2011-07-25 04:58:02 +02:00
/* Try to reload if enabeld */
2013-03-01 14:04:18 +01:00
if ( ! arg_no_reload )
2011-07-25 04:58:02 +02:00
r = daemon_reload ( bus , args ) ;
2013-11-07 05:49:04 +01:00
else
r = 0 ;
2011-06-13 14:19:53 +02:00
}
2011-04-16 03:29:54 +02:00
2011-07-25 04:58:02 +02:00
if ( carries_install_info = = 0 )
2013-02-27 15:01:06 +01:00
log_warning ( " The unit files have no [Install] section. They are not meant to be enabled \n "
" using systemctl. \n "
" Possible reasons for having this kind of units are: \n "
" 1) A unit may be statically enabled by being symlinked from another unit's \n "
" .wants/ or .requires/ directory. \n "
" 2) A unit's purpose may be to act as a helper for some other unit which has \n "
" a requirement dependency on it. \n "
" 3) A unit may be started when needed via activation (socket, path, timer, \n "
" D-Bus, udev, scripted systemctl call, ...). \n " ) ;
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
finish :
unit_file_changes_free ( changes , n_changes ) ;
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
return r ;
2010-07-24 00:53:33 +02:00
}
2013-11-07 05:49:04 +01:00
static int unit_is_enabled ( sd_bus * bus , char * * args ) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL ;
_cleanup_strv_free_ char * * mangled_names = NULL ;
2011-07-25 04:58:02 +02:00
bool enabled ;
char * * name ;
2013-11-07 05:49:04 +01:00
int r ;
2010-07-24 00:53:33 +02:00
2013-10-02 16:42:42 +02:00
r = mangle_names ( args + 1 , & mangled_names ) ;
if ( r < 0 )
return r ;
r = enable_sysv_units ( args [ 0 ] , mangled_names ) ;
2011-07-25 04:58:02 +02:00
if ( r < 0 )
return r ;
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
enabled = r > 0 ;
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
if ( ! bus | | avoid_bus ( ) ) {
2010-07-24 00:53:33 +02:00
2013-10-02 16:42:42 +02:00
STRV_FOREACH ( name , mangled_names ) {
2011-07-25 04:58:02 +02:00
UnitFileState state ;
2010-07-24 00:53:33 +02:00
2013-10-02 16:42:42 +02:00
state = unit_file_get_state ( arg_scope , arg_root , * name ) ;
2013-11-08 13:54:46 +01:00
if ( state < 0 ) {
log_error ( " Failed to get unit file state for %s: %s " , * name , strerror ( - state ) ) ;
2013-02-14 19:32:19 +01:00
return state ;
2013-11-08 13:54:46 +01:00
}
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
if ( state = = UNIT_FILE_ENABLED | |
state = = UNIT_FILE_ENABLED_RUNTIME | |
state = = UNIT_FILE_STATIC )
enabled = true ;
if ( ! arg_quiet )
puts ( unit_file_state_to_string ( state ) ) ;
2010-10-06 02:33:40 +02:00
}
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
} else {
2013-10-02 16:42:42 +02:00
STRV_FOREACH ( name , mangled_names ) {
2013-11-07 05:49:04 +01:00
_cleanup_bus_message_unref_ sd_bus_message * reply = NULL ;
2011-07-25 04:58:02 +02:00
const char * s ;
2011-03-04 19:48:38 +01:00
2013-11-07 05:49:04 +01:00
r = sd_bus_call_method (
2012-08-08 01:32:30 +02:00
bus ,
2011-07-25 04:58:02 +02:00
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
2012-08-08 01:32:30 +02:00
" GetUnitFileState " ,
2013-11-07 05:49:04 +01:00
& error ,
2012-08-08 01:32:30 +02:00
& reply ,
2013-11-07 05:49:04 +01:00
" s " , name ) ;
if ( r < 0 ) {
log_error ( " Failed to get unit file state for %s: %s " , * name , bus_error_message ( & error , r ) ) ;
2013-02-14 19:32:19 +01:00
return r ;
2010-07-24 00:53:33 +02:00
}
2013-11-07 05:49:04 +01:00
r = sd_bus_message_read ( reply , " s " , & s ) ;
if ( r < 0 )
return bus_log_parse_error ( r ) ;
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
if ( streq ( s , " enabled " ) | |
streq ( s , " enabled-runtime " ) | |
streq ( s , " static " ) )
enabled = true ;
if ( ! arg_quiet )
puts ( s ) ;
2010-10-13 03:13:23 +02:00
}
2010-07-24 00:53:33 +02:00
}
2013-11-07 05:49:04 +01:00
return ! enabled ;
2010-07-24 00:53:33 +02:00
}
2010-06-17 22:57:28 +02:00
static int systemctl_help ( void ) {
2010-06-15 02:51:55 +02:00
2011-07-25 04:58:02 +02:00
pager_open_if_enabled ( ) ;
2010-06-24 00:08:42 +02:00
printf ( " %s [OPTIONS...] {COMMAND} ... \n \n "
2011-07-25 04:58:02 +02:00
" Query or send control commands to the systemd manager. \n \n "
2010-10-22 16:11:50 +02:00
" -h --help Show this help \n "
" --version Show package version \n "
2013-11-07 05:49:04 +01:00
" --system Connect to system manager \n "
" --user Connect to user service manager \n "
" -H --host=[USER@]HOST \n "
" Operate on remote host \n "
" -M --machine=CONTAINER \n "
" Operate on local container \n "
2010-10-22 16:11:50 +02:00
" -t --type=TYPE List only units of a particular type \n "
2013-07-26 17:11:41 +02:00
" --state=STATE List only units with particular LOAD or SUB or ACTIVE state \n "
2010-10-22 16:11:50 +02:00
" -p --property=NAME Show only properties by this name \n "
2013-04-18 02:10:44 +02:00
" -a --all Show all loaded units/properties, including dead/empty \n "
" ones. To list all units installed on the system, use \n "
" the 'list-unit-files' command instead. \n "
2013-04-24 05:49:46 +02:00
" --reverse Show reverse dependencies with 'list-dependencies' \n "
2013-06-17 11:36:35 +02:00
" -l --full Don't ellipsize unit names on output \n "
2010-10-22 16:11:50 +02:00
" --fail When queueing a new job, fail if conflicting jobs are \n "
" pending \n "
2013-07-26 17:11:41 +02:00
" --irreversible When queueing a new job, make sure it cannot be implicitly \n "
" cancelled \n "
2011-02-16 21:59:31 +01:00
" --ignore-dependencies \n "
" When queueing a new job, ignore all its dependencies \n "
2013-07-26 17:11:41 +02:00
" --show-types When showing sockets, explicitly show their type \n "
2013-01-11 04:24:05 +01:00
" -i --ignore-inhibitors \n "
" When shutting down or sleeping, ignore inhibitors \n "
2011-03-12 01:03:13 +01:00
" --kill-who=WHO Who to send signal to \n "
" -s --signal=SIGNAL Which signal to send \n "
2010-10-22 16:11:50 +02:00
" -q --quiet Suppress output \n "
" --no-block Do not wait until operation finished \n "
" --no-wall Don't send wall message before halt/power-off/reboot \n "
" --no-reload When enabling/disabling unit files, don't reload daemon \n "
" configuration \n "
2011-09-27 00:48:40 +02:00
" --no-legend Do not print a legend (column headers and hints) \n "
2011-07-07 04:19:03 +02:00
" --no-pager Do not pipe output into a pager \n "
2010-10-26 05:29:39 +02:00
" --no-ask-password \n "
" Do not ask for system passwords \n "
2011-03-12 01:03:13 +01:00
" --global Enable/disable unit files globally \n "
2013-07-26 17:11:41 +02:00
" --runtime Enable unit files only temporarily until next reboot \n "
2010-10-22 16:11:50 +02:00
" -f --force When enabling unit files, override existing symlinks \n "
" When shutting down, execute action immediately \n "
2011-07-25 04:58:02 +02:00
" --root=PATH Enable unit files in the specified root directory \n "
2013-11-01 20:46:49 +01:00
" -n --lines=INTEGER Number of journal entries to show \n "
2012-01-13 02:58:45 +01:00
" -o --output=STRING Change journal output mode (short, short-monotonic, \n "
2012-10-11 02:37:10 +02:00
" verbose, export, json, json-pretty, json-sse, cat) \n \n "
2011-07-23 04:20:22 +02:00
" Unit Commands: \n "
2011-07-25 04:58:02 +02:00
" list-units List loaded units \n "
2013-06-04 16:57:47 +02:00
" list-sockets List loaded sockets ordered by address \n "
2010-07-24 00:53:33 +02:00
" start [NAME...] Start (activate) one or more units \n "
" stop [NAME...] Stop (deactivate) one or more units \n "
2010-06-15 02:51:55 +02:00
" reload [NAME...] Reload one or more units \n "
2010-07-13 20:20:36 +02:00
" restart [NAME...] Start or restart one or more units \n "
" try-restart [NAME...] Restart one or more units if active \n "
2012-12-03 15:45:53 +01:00
" reload-or-restart [NAME...] Reload one or more units if possible, \n "
2010-07-13 20:20:36 +02:00
" otherwise start or restart \n "
2012-12-03 15:45:53 +01:00
" reload-or-try-restart [NAME...] Reload one or more units if possible, \n "
2010-07-13 20:20:36 +02:00
" otherwise restart if active \n "
2010-06-15 02:51:55 +02:00
" isolate [NAME] Start one unit and stop all others \n "
2010-10-22 16:11:50 +02:00
" kill [NAME...] Send signal to processes of a unit \n "
2010-07-24 00:53:33 +02:00
" is-active [NAME...] Check whether units are active \n "
2012-12-27 17:39:48 +01:00
" is-failed [NAME...] Check whether units are failed \n "
2010-08-13 02:15:10 +02:00
" status [NAME...|PID...] Show runtime status of one or more units \n "
2010-07-13 20:20:36 +02:00
" show [NAME...|JOB...] Show properties of one or more \n "
2010-07-24 00:53:33 +02:00
" units/jobs or the manager \n "
2013-06-27 21:14:56 +02:00
" set-property [NAME] [ASSIGNMENT...] \n "
" Sets one or more properties of a unit \n "
2013-01-17 21:34:11 +01:00
" help [NAME...|PID...] Show manual for one or more units \n "
2010-08-31 00:23:34 +02:00
" reset-failed [NAME...] Reset failed state for all, one, or more \n "
" units \n "
2013-01-17 21:34:11 +01:00
" list-dependencies [NAME] Recursively show units which are required \n "
2013-04-24 05:49:46 +02:00
" or wanted by this unit or by which this \n "
" unit is required or wanted \n \n "
2011-07-23 04:20:22 +02:00
" Unit File Commands: \n "
2011-07-25 04:58:02 +02:00
" list-unit-files List installed unit files \n "
2010-07-24 00:53:33 +02:00
" enable [NAME...] Enable one or more unit files \n "
" disable [NAME...] Disable one or more unit files \n "
2011-07-25 04:58:02 +02:00
" reenable [NAME...] Reenable one or more unit files \n "
" preset [NAME...] Enable/disable one or more unit files \n "
" based on preset configuration \n "
2013-07-26 17:11:41 +02:00
" is-enabled [NAME...] Check whether unit files are enabled \n \n "
2011-07-25 04:58:02 +02:00
" mask [NAME...] Mask one or more units \n "
" unmask [NAME...] Unmask one or more units \n "
" link [PATH...] Link one or more units files into \n "
" the search path \n "
2013-05-28 11:05:48 +02:00
" get-default Get the name of the default target \n "
2013-08-08 21:12:03 +02:00
" set-default NAME Set the default target \n \n "
2011-07-23 04:20:22 +02:00
" Job Commands: \n "
2010-07-04 03:43:57 +02:00
" list-jobs List jobs \n "
2011-07-23 04:20:22 +02:00
" cancel [JOB...] Cancel all, one, or more jobs \n \n "
" Snapshot Commands: \n "
2010-06-15 02:51:55 +02:00
" snapshot [NAME] Create a snapshot \n "
2011-07-23 04:20:22 +02:00
" delete [NAME...] Remove one or more snapshots \n \n "
" Environment Commands: \n "
2010-06-15 02:51:55 +02:00
" show-environment Dump environment \n "
" set-environment [NAME=VALUE...] Set one or more environment variables \n "
2013-07-26 16:59:55 +02:00
" unset-environment [NAME...] Unset one or more environment variables \n \n "
2011-07-23 04:20:22 +02:00
" Manager Lifecycle Commands: \n "
" daemon-reload Reload systemd manager configuration \n "
" daemon-reexec Reexecute systemd manager \n \n "
" System Commands: \n "
2010-10-14 00:56:12 +02:00
" default Enter system default mode \n "
" rescue Enter system rescue mode \n "
" emergency Enter system emergency mode \n "
2010-06-18 04:22:59 +02:00
" halt Shut down and halt the system \n "
2010-06-24 00:08:42 +02:00
" poweroff Shut down and power-off the system \n "
2013-11-06 09:02:41 +01:00
" reboot [ARG] Shut down and reboot the system \n "
2010-10-14 00:56:12 +02:00
" kexec Shut down and reboot the system with kexec \n "
2012-05-05 02:06:58 +02:00
" exit Request user instance exit \n "
2012-05-11 17:35:46 +02:00
" switch-root [ROOT] [INIT] Change to a different root file system \n "
2012-05-05 02:06:58 +02:00
" suspend Suspend the system \n "
2012-10-28 00:49:04 +02:00
" hibernate Hibernate the system \n "
" hybrid-sleep Hibernate and suspend the system \n " ,
2010-06-16 21:54:17 +02:00
program_invocation_short_name ) ;
2010-06-15 02:51:55 +02:00
return 0 ;
}
2010-06-17 22:57:28 +02:00
static int halt_help ( void ) {
2013-11-06 09:02:41 +01:00
printf ( " %s [OPTIONS...]%s \n \n "
2010-06-17 22:57:28 +02:00
" %s the system. \n \n "
" --help Show this help \n "
" --halt Halt the machine \n "
" -p --poweroff Switch off the machine \n "
" --reboot Reboot the machine \n "
2010-06-24 00:08:42 +02:00
" -f --force Force immediate halt/power-off/reboot \n "
" -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record \n "
2010-06-17 22:57:28 +02:00
" -d --no-wtmp Don't write wtmp record \n "
2010-06-24 00:08:42 +02:00
" --no-wall Don't send wall message before halt/power-off/reboot \n " ,
2010-06-17 22:57:28 +02:00
program_invocation_short_name ,
2013-11-06 09:02:41 +01:00
arg_action = = ACTION_REBOOT ? " [ARG] " : " " ,
2010-06-17 22:57:28 +02:00
arg_action = = ACTION_REBOOT ? " Reboot " :
arg_action = = ACTION_POWEROFF ? " Power off " :
" Halt " ) ;
return 0 ;
}
static int shutdown_help ( void ) {
2010-08-16 22:40:11 +02:00
printf ( " %s [OPTIONS...] [TIME] [WALL...] \n \n "
2010-06-17 22:57:28 +02:00
" Shut down the system. \n \n "
" --help Show this help \n "
" -H --halt Halt the machine \n "
" -P --poweroff Power-off the machine \n "
" -r --reboot Reboot the machine \n "
2012-05-16 22:49:30 +02:00
" -h Equivalent to --poweroff, overridden by --halt \n "
2010-06-24 00:08:42 +02:00
" -k Don't halt/power-off/reboot, just send warnings \n "
2010-08-16 15:37:52 +02:00
" --no-wall Don't send wall message before halt/power-off/reboot \n "
" -c Cancel a pending shutdown \n " ,
2010-06-17 22:57:28 +02:00
program_invocation_short_name ) ;
return 0 ;
}
static int telinit_help ( void ) {
2010-06-24 00:08:42 +02:00
printf ( " %s [OPTIONS...] {COMMAND} \n \n "
2010-06-18 04:22:59 +02:00
" Send control commands to the init daemon. \n \n "
" --help Show this help \n "
2010-06-24 00:08:42 +02:00
" --no-wall Don't send wall message before halt/power-off/reboot \n \n "
2010-06-17 22:57:28 +02:00
" Commands: \n "
" 0 Power-off the machine \n "
" 6 Reboot the machine \n "
2010-06-18 04:22:59 +02:00
" 2, 3, 4, 5 Start runlevelX.target unit \n "
" 1, s, S Enter rescue mode \n "
" q, Q Reload init daemon configuration \n "
" u, U Reexecute init daemon \n " ,
2010-06-17 22:57:28 +02:00
program_invocation_short_name ) ;
return 0 ;
}
static int runlevel_help ( void ) {
2010-06-24 00:08:42 +02:00
printf ( " %s [OPTIONS...] \n \n "
2010-06-17 22:57:28 +02:00
" Prints the previous and current runlevel of the init system. \n \n "
" --help Show this help \n " ,
program_invocation_short_name ) ;
return 0 ;
}
2012-11-15 11:54:57 +01:00
static int help_types ( void ) {
int i ;
2013-03-29 22:59:35 +01:00
const char * t ;
2012-11-15 11:54:57 +01:00
puts ( " Available unit types: " ) ;
2013-03-29 22:59:35 +01:00
for ( i = 0 ; i < _UNIT_TYPE_MAX ; i + + ) {
t = unit_type_to_string ( i ) ;
if ( t )
puts ( t ) ;
}
2012-11-15 11:54:57 +01:00
return 0 ;
}
2010-06-17 22:57:28 +02:00
static int systemctl_parse_argv ( int argc , char * argv [ ] ) {
2010-06-15 02:51:55 +02:00
enum {
2010-07-11 03:59:18 +02:00
ARG_FAIL = 0x100 ,
2013-04-24 05:49:46 +02:00
ARG_REVERSE ,
ARG_AFTER ,
ARG_BEFORE ,
2013-04-12 00:59:18 +02:00
ARG_SHOW_TYPES ,
2013-02-22 11:21:37 +01:00
ARG_IRREVERSIBLE ,
2011-02-16 21:59:31 +01:00
ARG_IGNORE_DEPENDENCIES ,
2010-09-06 02:42:49 +02:00
ARG_VERSION ,
2010-11-15 22:12:41 +01:00
ARG_USER ,
2010-06-15 02:51:55 +02:00
ARG_SYSTEM ,
2010-07-24 00:53:33 +02:00
ARG_GLOBAL ,
2010-07-01 00:32:29 +02:00
ARG_NO_BLOCK ,
2011-09-27 00:48:40 +02:00
ARG_NO_LEGEND ,
2011-01-04 00:47:40 +01:00
ARG_NO_PAGER ,
2010-07-16 02:56:00 +02:00
ARG_NO_WALL ,
2011-06-24 15:02:57 +02:00
ARG_ROOT ,
2010-07-24 00:53:33 +02:00
ARG_NO_RELOAD ,
2010-10-26 05:29:39 +02:00
ARG_KILL_WHO ,
2011-02-16 20:34:59 +01:00
ARG_NO_ASK_PASSWORD ,
2011-07-25 04:58:02 +02:00
ARG_FAILED ,
2012-01-04 18:33:36 +01:00
ARG_RUNTIME ,
2013-05-03 12:52:19 +02:00
ARG_FORCE ,
2013-07-18 13:24:12 +02:00
ARG_PLAIN ,
ARG_STATE
2010-06-15 02:51:55 +02:00
} ;
static const struct option options [ ] = {
2013-07-26 16:34:52 +02:00
{ " help " , no_argument , NULL , ' h ' } ,
{ " version " , no_argument , NULL , ARG_VERSION } ,
{ " type " , required_argument , NULL , ' t ' } ,
{ " property " , required_argument , NULL , ' p ' } ,
{ " all " , no_argument , NULL , ' a ' } ,
{ " reverse " , no_argument , NULL , ARG_REVERSE } ,
{ " after " , no_argument , NULL , ARG_AFTER } ,
{ " before " , no_argument , NULL , ARG_BEFORE } ,
{ " show-types " , no_argument , NULL , ARG_SHOW_TYPES } ,
{ " failed " , no_argument , NULL , ARG_FAILED } , /* compatibility only */
{ " full " , no_argument , NULL , ' l ' } ,
{ " fail " , no_argument , NULL , ARG_FAIL } ,
{ " irreversible " , no_argument , NULL , ARG_IRREVERSIBLE } ,
{ " ignore-dependencies " , no_argument , NULL , ARG_IGNORE_DEPENDENCIES } ,
{ " ignore-inhibitors " , no_argument , NULL , ' i ' } ,
{ " user " , no_argument , NULL , ARG_USER } ,
{ " system " , no_argument , NULL , ARG_SYSTEM } ,
{ " global " , no_argument , NULL , ARG_GLOBAL } ,
{ " no-block " , no_argument , NULL , ARG_NO_BLOCK } ,
{ " no-legend " , no_argument , NULL , ARG_NO_LEGEND } ,
{ " no-pager " , no_argument , NULL , ARG_NO_PAGER } ,
{ " no-wall " , no_argument , NULL , ARG_NO_WALL } ,
{ " quiet " , no_argument , NULL , ' q ' } ,
{ " root " , required_argument , NULL , ARG_ROOT } ,
{ " force " , no_argument , NULL , ARG_FORCE } ,
{ " no-reload " , no_argument , NULL , ARG_NO_RELOAD } ,
{ " kill-who " , required_argument , NULL , ARG_KILL_WHO } ,
{ " signal " , required_argument , NULL , ' s ' } ,
{ " no-ask-password " , no_argument , NULL , ARG_NO_ASK_PASSWORD } ,
{ " host " , required_argument , NULL , ' H ' } ,
2013-11-07 05:49:04 +01:00
{ " machine " , required_argument , NULL , ' M ' } ,
2013-07-26 16:34:52 +02:00
{ " runtime " , no_argument , NULL , ARG_RUNTIME } ,
{ " lines " , required_argument , NULL , ' n ' } ,
{ " output " , required_argument , NULL , ' o ' } ,
{ " plain " , no_argument , NULL , ARG_PLAIN } ,
{ " state " , required_argument , NULL , ARG_STATE } ,
2013-11-06 18:28:39 +01:00
{ }
2010-06-15 02:51:55 +02:00
} ;
int c ;
2010-06-17 22:57:28 +02:00
assert ( argc > = 0 ) ;
2010-06-15 02:51:55 +02:00
assert ( argv ) ;
2013-11-07 05:49:04 +01:00
while ( ( c = getopt_long ( argc , argv , " ht:p:alqfs:H:M:n:o:i " , options , NULL ) ) > = 0 ) {
2010-06-15 02:51:55 +02:00
switch ( c ) {
case ' h ' :
2013-11-06 18:28:39 +01:00
return systemctl_help ( ) ;
2010-09-06 02:42:49 +02:00
case ARG_VERSION :
puts ( PACKAGE_STRING ) ;
2010-09-06 03:11:24 +02:00
puts ( SYSTEMD_FEATURES ) ;
2010-09-06 02:42:49 +02:00
return 0 ;
2010-06-15 02:51:55 +02:00
2013-04-11 04:40:58 +02:00
case ' t ' : {
char * word , * state ;
size_t size ;
2012-11-15 11:54:57 +01:00
2013-04-11 04:40:58 +02:00
FOREACH_WORD_SEPARATOR ( word , size , optarg , " , " , state ) {
2013-04-18 09:11:22 +02:00
_cleanup_free_ char * type ;
2013-04-11 04:40:58 +02:00
type = strndup ( word , size ) ;
if ( ! type )
return - ENOMEM ;
if ( streq ( type , " help " ) ) {
help_types ( ) ;
return 0 ;
}
if ( unit_type_from_string ( type ) > = 0 ) {
if ( strv_push ( & arg_types , type ) )
return log_oom ( ) ;
type = NULL ;
continue ;
}
2013-07-18 13:24:12 +02:00
/* It's much nicer to use --state= for
* load states , but let ' s support this
* in - - types = too for compatibility
* with old versions */
2013-04-11 04:40:58 +02:00
if ( unit_load_state_from_string ( optarg ) > = 0 ) {
2013-07-18 13:24:12 +02:00
if ( strv_push ( & arg_states , type ) < 0 )
2013-04-11 04:40:58 +02:00
return log_oom ( ) ;
type = NULL ;
continue ;
}
2013-04-15 04:37:54 +02:00
log_error ( " Unknown unit type or load state '%s'. " , type ) ;
2013-04-11 04:40:58 +02:00
log_info ( " Use -t help to see a list of allowed values. " ) ;
return - EINVAL ;
2012-07-10 18:03:03 +02:00
}
2013-04-11 04:40:58 +02:00
break ;
}
2010-07-23 05:24:05 +02:00
case ' p ' : {
2013-02-16 23:20:28 +01:00
/* Make sure that if the empty property list
was specified , we won ' t show any properties . */
2013-04-11 04:40:58 +02:00
if ( isempty ( optarg ) & & ! arg_properties ) {
2013-11-08 13:54:46 +01:00
arg_properties = new0 ( char * , 1 ) ;
2013-04-11 04:40:58 +02:00
if ( ! arg_properties )
return log_oom ( ) ;
} else {
char * word , * state ;
size_t size ;
2013-02-16 23:20:28 +01:00
2013-04-11 04:40:58 +02:00
FOREACH_WORD_SEPARATOR ( word , size , optarg , " , " , state ) {
char * prop ;
2013-02-16 23:20:28 +01:00
2013-04-11 04:40:58 +02:00
prop = strndup ( word , size ) ;
if ( ! prop )
return log_oom ( ) ;
2010-07-23 05:24:05 +02:00
2013-07-18 13:24:12 +02:00
if ( strv_push ( & arg_properties , prop ) < 0 ) {
2013-04-11 04:40:58 +02:00
free ( prop ) ;
return log_oom ( ) ;
}
}
2013-02-16 23:20:28 +01:00
}
2010-07-04 03:43:57 +02:00
/* If the user asked for a particular
* property , show it to him , even if it is
* empty . */
arg_all = true ;
2013-02-16 23:20:28 +01:00
2010-07-04 03:43:57 +02:00
break ;
2010-07-23 05:24:05 +02:00
}
2010-07-04 03:43:57 +02:00
2010-06-15 02:51:55 +02:00
case ' a ' :
arg_all = true ;
break ;
2013-04-24 05:49:46 +02:00
case ARG_REVERSE :
arg_dependency = DEPENDENCY_REVERSE ;
break ;
case ARG_AFTER :
arg_dependency = DEPENDENCY_AFTER ;
break ;
case ARG_BEFORE :
arg_dependency = DEPENDENCY_BEFORE ;
break ;
2013-04-12 00:59:18 +02:00
case ARG_SHOW_TYPES :
arg_show_types = true ;
break ;
2010-07-11 03:59:18 +02:00
case ARG_FAIL :
2011-02-16 21:59:31 +01:00
arg_job_mode = " fail " ;
break ;
2013-02-22 11:21:37 +01:00
case ARG_IRREVERSIBLE :
arg_job_mode = " replace-irreversibly " ;
break ;
2011-02-16 21:59:31 +01:00
case ARG_IGNORE_DEPENDENCIES :
arg_job_mode = " ignore-dependencies " ;
2010-06-15 02:51:55 +02:00
break ;
2010-11-15 22:12:41 +01:00
case ARG_USER :
2011-07-25 04:58:02 +02:00
arg_scope = UNIT_FILE_USER ;
2010-06-15 02:51:55 +02:00
break ;
case ARG_SYSTEM :
2011-07-25 04:58:02 +02:00
arg_scope = UNIT_FILE_SYSTEM ;
break ;
case ARG_GLOBAL :
arg_scope = UNIT_FILE_GLOBAL ;
2010-06-15 02:51:55 +02:00
break ;
2010-07-01 00:32:29 +02:00
case ARG_NO_BLOCK :
arg_no_block = true ;
2010-06-15 02:51:55 +02:00
break ;
2011-09-27 00:48:40 +02:00
case ARG_NO_LEGEND :
arg_no_legend = true ;
break ;
2011-01-04 00:47:40 +01:00
case ARG_NO_PAGER :
arg_no_pager = true ;
break ;
2011-01-02 00:25:57 +01:00
2010-06-18 04:22:59 +02:00
case ARG_NO_WALL :
arg_no_wall = true ;
break ;
2011-06-24 15:02:57 +02:00
case ARG_ROOT :
arg_root = optarg ;
break ;
2013-06-17 11:36:35 +02:00
case ' l ' :
2010-07-20 20:33:19 +02:00
arg_full = true ;
break ;
2011-02-16 20:34:59 +01:00
case ARG_FAILED :
2013-07-18 13:24:12 +02:00
if ( strv_extend ( & arg_states , " failed " ) < 0 )
return log_oom ( ) ;
2011-02-16 20:34:59 +01:00
break ;
2010-07-01 01:06:58 +02:00
case ' q ' :
arg_quiet = true ;
break ;
2012-04-03 14:43:48 +02:00
case ARG_FORCE :
arg_force + + ;
break ;
2010-10-14 03:19:13 +02:00
case ' f ' :
2012-02-15 20:05:49 +01:00
arg_force + + ;
2010-07-24 00:53:33 +02:00
break ;
case ARG_NO_RELOAD :
arg_no_reload = true ;
break ;
2010-10-22 16:11:50 +02:00
case ARG_KILL_WHO :
arg_kill_who = optarg ;
break ;
case ' s ' :
if ( ( arg_signal = signal_from_string_try_harder ( optarg ) ) < 0 ) {
log_error ( " Failed to parse signal string %s. " , optarg ) ;
return - EINVAL ;
}
break ;
2010-10-26 05:29:39 +02:00
case ARG_NO_ASK_PASSWORD :
arg_ask_password = false ;
break ;
2013-11-07 05:49:04 +01:00
case ' H ' :
arg_transport = BUS_TRANSPORT_REMOTE ;
arg_host = optarg ;
2011-03-12 01:03:13 +01:00
break ;
2013-11-07 05:49:04 +01:00
case ' M ' :
arg_transport = BUS_TRANSPORT_CONTAINER ;
arg_host = optarg ;
2011-03-12 01:03:13 +01:00
break ;
2011-07-25 04:58:02 +02:00
case ARG_RUNTIME :
arg_runtime = true ;
break ;
2012-01-04 18:33:36 +01:00
case ' n ' :
if ( safe_atou ( optarg , & arg_lines ) < 0 ) {
log_error ( " Failed to parse lines '%s' " , optarg ) ;
return - EINVAL ;
}
break ;
case ' o ' :
arg_output = output_mode_from_string ( optarg ) ;
if ( arg_output < 0 ) {
log_error ( " Unknown output '%s'. " , optarg ) ;
return - EINVAL ;
}
break ;
2013-01-11 04:24:05 +01:00
case ' i ' :
arg_ignore_inhibitors = true ;
break ;
2013-05-03 12:52:19 +02:00
case ARG_PLAIN :
arg_plain = true ;
break ;
2013-07-18 13:24:12 +02:00
case ARG_STATE : {
char * word , * state ;
size_t size ;
FOREACH_WORD_SEPARATOR ( word , size , optarg , " , " , state ) {
char * s ;
s = strndup ( word , size ) ;
if ( ! s )
return log_oom ( ) ;
if ( strv_push ( & arg_states , s ) < 0 ) {
free ( s ) ;
return log_oom ( ) ;
}
}
break ;
}
2010-06-15 02:51:55 +02:00
case ' ? ' :
return - EINVAL ;
default :
2013-11-06 18:28:39 +01:00
assert_not_reached ( " Unhandled option " ) ;
2010-06-15 02:51:55 +02:00
}
}
2013-11-07 05:49:04 +01:00
if ( arg_transport ! = BUS_TRANSPORT_LOCAL & & arg_scope ! = UNIT_FILE_SYSTEM ) {
2011-03-12 01:03:13 +01:00
log_error ( " Cannot access user instance remotely. " ) ;
return - EINVAL ;
}
2010-06-15 02:51:55 +02:00
return 1 ;
}
2010-06-17 22:57:28 +02:00
static int halt_parse_argv ( int argc , char * argv [ ] ) {
enum {
ARG_HELP = 0x100 ,
ARG_HALT ,
2010-06-18 04:22:59 +02:00
ARG_REBOOT ,
ARG_NO_WALL
2010-06-17 22:57:28 +02:00
} ;
static const struct option options [ ] = {
{ " help " , no_argument , NULL , ARG_HELP } ,
{ " halt " , no_argument , NULL , ARG_HALT } ,
{ " poweroff " , no_argument , NULL , ' p ' } ,
{ " reboot " , no_argument , NULL , ARG_REBOOT } ,
{ " force " , no_argument , NULL , ' f ' } ,
{ " wtmp-only " , no_argument , NULL , ' w ' } ,
{ " no-wtmp " , no_argument , NULL , ' d ' } ,
2010-06-18 04:22:59 +02:00
{ " no-wall " , no_argument , NULL , ARG_NO_WALL } ,
2013-11-06 18:28:39 +01:00
{ }
2010-06-17 22:57:28 +02:00
} ;
2013-11-06 09:02:41 +01:00
int c , r , runlevel ;
2010-06-17 22:57:28 +02:00
assert ( argc > = 0 ) ;
assert ( argv ) ;
if ( utmp_get_runlevel ( & runlevel , NULL ) > = 0 )
if ( runlevel = = ' 0 ' | | runlevel = = ' 6 ' )
2012-05-03 16:17:39 +02:00
arg_force = 2 ;
2010-06-17 22:57:28 +02:00
while ( ( c = getopt_long ( argc , argv , " pfwdnih " , options , NULL ) ) > = 0 ) {
switch ( c ) {
case ARG_HELP :
2013-11-06 18:28:39 +01:00
return halt_help ( ) ;
2010-06-17 22:57:28 +02:00
case ARG_HALT :
arg_action = ACTION_HALT ;
break ;
case ' p ' :
2010-08-05 14:00:00 +02:00
if ( arg_action ! = ACTION_REBOOT )
arg_action = ACTION_POWEROFF ;
2010-06-17 22:57:28 +02:00
break ;
case ARG_REBOOT :
arg_action = ACTION_REBOOT ;
break ;
case ' f ' :
2012-05-03 16:17:39 +02:00
arg_force = 2 ;
2010-06-17 22:57:28 +02:00
break ;
case ' w ' :
arg_dry = true ;
break ;
case ' d ' :
arg_no_wtmp = true ;
break ;
2010-06-18 04:22:59 +02:00
case ARG_NO_WALL :
arg_no_wall = true ;
break ;
2010-06-17 22:57:28 +02:00
case ' i ' :
case ' h ' :
2012-09-06 00:32:57 +02:00
case ' n ' :
2010-06-17 22:57:28 +02:00
/* Compatibility nops */
break ;
case ' ? ' :
return - EINVAL ;
default :
2013-11-06 18:28:39 +01:00
assert_not_reached ( " Unhandled option " ) ;
2010-06-17 22:57:28 +02:00
}
}
2013-11-06 09:02:41 +01:00
if ( arg_action = = ACTION_REBOOT & & argc = = optind + 1 ) {
r = write_string_file ( REBOOT_PARAM_FILE , argv [ optind ] ) ;
if ( r < 0 ) {
log_error ( " Failed to write reboot param to "
REBOOT_PARAM_FILE " : %s " , strerror ( - r ) ) ;
return r ;
}
} else if ( optind < argc ) {
2010-06-17 22:57:28 +02:00
log_error ( " Too many arguments. " ) ;
return - EINVAL ;
}
return 1 ;
}
2010-08-16 15:37:52 +02:00
static int parse_time_spec ( const char * t , usec_t * _u ) {
assert ( t ) ;
assert ( _u ) ;
if ( streq ( t , " now " ) )
* _u = 0 ;
2011-07-02 20:41:36 +02:00
else if ( ! strchr ( t , ' : ' ) ) {
2010-08-16 15:37:52 +02:00
uint64_t u ;
2011-07-02 20:41:36 +02:00
if ( safe_atou64 ( t , & u ) < 0 )
2010-08-16 15:37:52 +02:00
return - EINVAL ;
* _u = now ( CLOCK_REALTIME ) + USEC_PER_MINUTE * u ;
} else {
char * e = NULL ;
long hour , minute ;
2013-03-25 00:59:00 +01:00
struct tm tm = { } ;
2010-08-16 15:37:52 +02:00
time_t s ;
usec_t n ;
errno = 0 ;
hour = strtol ( t , & e , 10 ) ;
2013-03-28 14:24:15 +01:00
if ( errno > 0 | | * e ! = ' : ' | | hour < 0 | | hour > 23 )
2010-08-16 15:37:52 +02:00
return - EINVAL ;
minute = strtol ( e + 1 , & e , 10 ) ;
2013-03-28 14:24:15 +01:00
if ( errno > 0 | | * e ! = 0 | | minute < 0 | | minute > 59 )
2010-08-16 15:37:52 +02:00
return - EINVAL ;
n = now ( CLOCK_REALTIME ) ;
2010-08-16 22:40:11 +02:00
s = ( time_t ) ( n / USEC_PER_SEC ) ;
2010-08-16 15:37:52 +02:00
assert_se ( localtime_r ( & s , & tm ) ) ;
tm . tm_hour = ( int ) hour ;
tm . tm_min = ( int ) minute ;
2010-08-16 22:40:11 +02:00
tm . tm_sec = 0 ;
2010-08-16 15:37:52 +02:00
assert_se ( s = mktime ( & tm ) ) ;
* _u = ( usec_t ) s * USEC_PER_SEC ;
while ( * _u < = n )
* _u + = USEC_PER_DAY ;
}
return 0 ;
}
2010-06-17 22:57:28 +02:00
static int shutdown_parse_argv ( int argc , char * argv [ ] ) {
enum {
ARG_HELP = 0x100 ,
2010-06-18 04:22:59 +02:00
ARG_NO_WALL
2010-06-17 22:57:28 +02:00
} ;
static const struct option options [ ] = {
{ " help " , no_argument , NULL , ARG_HELP } ,
{ " halt " , no_argument , NULL , ' H ' } ,
{ " poweroff " , no_argument , NULL , ' P ' } ,
{ " reboot " , no_argument , NULL , ' r ' } ,
2012-04-11 02:04:46 +02:00
{ " kexec " , no_argument , NULL , ' K ' } , /* not documented extension */
2010-06-18 04:22:59 +02:00
{ " no-wall " , no_argument , NULL , ARG_NO_WALL } ,
2013-11-06 18:28:39 +01:00
{ }
2010-06-17 22:57:28 +02:00
} ;
2010-08-16 15:37:52 +02:00
int c , r ;
2010-06-17 22:57:28 +02:00
assert ( argc > = 0 ) ;
assert ( argv ) ;
2010-08-16 15:37:52 +02:00
while ( ( c = getopt_long ( argc , argv , " HPrhkt:afFc " , options , NULL ) ) > = 0 ) {
2010-06-17 22:57:28 +02:00
switch ( c ) {
case ARG_HELP :
2013-11-06 18:28:39 +01:00
return shutdown_help ( ) ;
2010-06-17 22:57:28 +02:00
case ' H ' :
arg_action = ACTION_HALT ;
break ;
case ' P ' :
arg_action = ACTION_POWEROFF ;
break ;
case ' r ' :
2011-02-20 21:09:07 +01:00
if ( kexec_loaded ( ) )
arg_action = ACTION_KEXEC ;
else
arg_action = ACTION_REBOOT ;
2010-06-17 22:57:28 +02:00
break ;
2012-04-11 02:04:46 +02:00
case ' K ' :
arg_action = ACTION_KEXEC ;
break ;
2010-06-17 22:57:28 +02:00
case ' h ' :
if ( arg_action ! = ACTION_HALT )
arg_action = ACTION_POWEROFF ;
break ;
case ' k ' :
arg_dry = true ;
break ;
2010-06-18 04:22:59 +02:00
case ARG_NO_WALL :
arg_no_wall = true ;
break ;
2010-06-17 22:57:28 +02:00
case ' t ' :
case ' a ' :
/* Compatibility nops */
break ;
2010-08-16 15:37:52 +02:00
case ' c ' :
arg_action = ACTION_CANCEL_SHUTDOWN ;
break ;
2010-06-17 22:57:28 +02:00
case ' ? ' :
return - EINVAL ;
default :
2013-11-06 18:28:39 +01:00
assert_not_reached ( " Unhandled option " ) ;
2010-06-17 22:57:28 +02:00
}
}
2012-07-30 17:25:39 +02:00
if ( argc > optind & & arg_action ! = ACTION_CANCEL_SHUTDOWN ) {
2012-04-11 00:36:44 +02:00
r = parse_time_spec ( argv [ optind ] , & arg_when ) ;
if ( r < 0 ) {
2010-08-16 15:37:52 +02:00
log_error ( " Failed to parse time specification: %s " , argv [ optind ] ) ;
return r ;
}
2010-08-16 17:12:35 +02:00
} else
2010-08-16 22:40:11 +02:00
arg_when = now ( CLOCK_REALTIME ) + USEC_PER_MINUTE ;
2010-06-18 20:23:39 +02:00
2012-07-30 17:25:39 +02:00
if ( argc > optind & & arg_action = = ACTION_CANCEL_SHUTDOWN )
/* No time argument for shutdown cancel */
arg_wall = argv + optind ;
else if ( argc > optind + 1 )
/* We skip the time argument */
2010-06-17 22:57:28 +02:00
arg_wall = argv + optind + 1 ;
optind = argc ;
return 1 ;
}
static int telinit_parse_argv ( int argc , char * argv [ ] ) {
enum {
ARG_HELP = 0x100 ,
2010-06-18 04:22:59 +02:00
ARG_NO_WALL
2010-06-17 22:57:28 +02:00
} ;
static const struct option options [ ] = {
{ " help " , no_argument , NULL , ARG_HELP } ,
2010-06-18 04:22:59 +02:00
{ " no-wall " , no_argument , NULL , ARG_NO_WALL } ,
2013-11-06 18:28:39 +01:00
{ }
2010-06-17 22:57:28 +02:00
} ;
static const struct {
char from ;
enum action to ;
} table [ ] = {
{ ' 0 ' , ACTION_POWEROFF } ,
{ ' 6 ' , ACTION_REBOOT } ,
2010-06-18 02:28:35 +02:00
{ ' 1 ' , ACTION_RESCUE } ,
2010-06-17 22:57:28 +02:00
{ ' 2 ' , ACTION_RUNLEVEL2 } ,
{ ' 3 ' , ACTION_RUNLEVEL3 } ,
{ ' 4 ' , ACTION_RUNLEVEL4 } ,
{ ' 5 ' , ACTION_RUNLEVEL5 } ,
{ ' s ' , ACTION_RESCUE } ,
{ ' S ' , ACTION_RESCUE } ,
{ ' q ' , ACTION_RELOAD } ,
{ ' Q ' , ACTION_RELOAD } ,
{ ' u ' , ACTION_REEXEC } ,
{ ' U ' , ACTION_REEXEC }
} ;
unsigned i ;
int c ;
assert ( argc > = 0 ) ;
assert ( argv ) ;
while ( ( c = getopt_long ( argc , argv , " " , options , NULL ) ) > = 0 ) {
switch ( c ) {
case ARG_HELP :
2013-11-06 18:28:39 +01:00
return telinit_help ( ) ;
2010-06-17 22:57:28 +02:00
2010-06-18 04:22:59 +02:00
case ARG_NO_WALL :
arg_no_wall = true ;
break ;
2010-06-17 22:57:28 +02:00
case ' ? ' :
return - EINVAL ;
default :
2013-11-06 18:28:39 +01:00
assert_not_reached ( " Unhandled option " ) ;
2010-06-17 22:57:28 +02:00
}
}
if ( optind > = argc ) {
2010-06-24 04:55:57 +02:00
telinit_help ( ) ;
2010-06-17 22:57:28 +02:00
return - EINVAL ;
}
if ( optind + 1 < argc ) {
log_error ( " Too many arguments. " ) ;
return - EINVAL ;
}
if ( strlen ( argv [ optind ] ) ! = 1 ) {
log_error ( " Expected single character argument. " ) ;
return - EINVAL ;
}
for ( i = 0 ; i < ELEMENTSOF ( table ) ; i + + )
if ( table [ i ] . from = = argv [ optind ] [ 0 ] )
break ;
if ( i > = ELEMENTSOF ( table ) ) {
2012-06-22 13:08:48 +02:00
log_error ( " Unknown command '%s'. " , argv [ optind ] ) ;
2010-06-17 22:57:28 +02:00
return - EINVAL ;
}
arg_action = table [ i ] . to ;
optind + + ;
return 1 ;
}
static int runlevel_parse_argv ( int argc , char * argv [ ] ) {
enum {
ARG_HELP = 0x100 ,
} ;
static const struct option options [ ] = {
{ " help " , no_argument , NULL , ARG_HELP } ,
2013-11-06 18:28:39 +01:00
{ }
2010-06-17 22:57:28 +02:00
} ;
int c ;
assert ( argc > = 0 ) ;
assert ( argv ) ;
while ( ( c = getopt_long ( argc , argv , " " , options , NULL ) ) > = 0 ) {
switch ( c ) {
case ARG_HELP :
2013-11-06 18:28:39 +01:00
return runlevel_help ( ) ;
2010-06-17 22:57:28 +02:00
return 0 ;
case ' ? ' :
return - EINVAL ;
default :
2013-11-06 18:28:39 +01:00
assert_not_reached ( " Unhandled option " ) ;
2010-06-17 22:57:28 +02:00
}
}
if ( optind < argc ) {
log_error ( " Too many arguments. " ) ;
return - EINVAL ;
}
return 1 ;
}
static int parse_argv ( int argc , char * argv [ ] ) {
assert ( argc > = 0 ) ;
assert ( argv ) ;
if ( program_invocation_short_name ) {
if ( strstr ( program_invocation_short_name , " halt " ) ) {
arg_action = ACTION_HALT ;
return halt_parse_argv ( argc , argv ) ;
} else if ( strstr ( program_invocation_short_name , " poweroff " ) ) {
arg_action = ACTION_POWEROFF ;
return halt_parse_argv ( argc , argv ) ;
} else if ( strstr ( program_invocation_short_name , " reboot " ) ) {
2011-02-20 21:09:07 +01:00
if ( kexec_loaded ( ) )
arg_action = ACTION_KEXEC ;
else
arg_action = ACTION_REBOOT ;
2010-06-17 22:57:28 +02:00
return halt_parse_argv ( argc , argv ) ;
} else if ( strstr ( program_invocation_short_name , " shutdown " ) ) {
arg_action = ACTION_POWEROFF ;
return shutdown_parse_argv ( argc , argv ) ;
} else if ( strstr ( program_invocation_short_name , " init " ) ) {
2010-07-24 02:33:38 +02:00
if ( sd_booted ( ) > 0 ) {
2013-11-07 05:49:04 +01:00
arg_action = _ACTION_INVALID ;
2010-07-24 02:33:38 +02:00
return telinit_parse_argv ( argc , argv ) ;
} else {
/* Hmm, so some other init system is
* running , we need to forward this
* request to it . For now we simply
* guess that it is Upstart . */
2013-03-23 01:04:53 +01:00
execv ( TELINIT , argv ) ;
2010-07-24 02:33:38 +02:00
log_error ( " Couldn't find an alternative telinit implementation to spawn. " ) ;
return - EIO ;
}
2010-06-17 22:57:28 +02:00
} else if ( strstr ( program_invocation_short_name , " runlevel " ) ) {
arg_action = ACTION_RUNLEVEL ;
return runlevel_parse_argv ( argc , argv ) ;
}
}
arg_action = ACTION_SYSTEMCTL ;
return systemctl_parse_argv ( argc , argv ) ;
}
2013-05-03 04:51:50 +02:00
_pure_ static int action_to_runlevel ( void ) {
2010-06-18 04:44:53 +02:00
static const char table [ _ACTION_MAX ] = {
[ ACTION_HALT ] = ' 0 ' ,
[ ACTION_POWEROFF ] = ' 0 ' ,
[ ACTION_REBOOT ] = ' 6 ' ,
[ ACTION_RUNLEVEL2 ] = ' 2 ' ,
[ ACTION_RUNLEVEL3 ] = ' 3 ' ,
[ ACTION_RUNLEVEL4 ] = ' 4 ' ,
[ ACTION_RUNLEVEL5 ] = ' 5 ' ,
[ ACTION_RESCUE ] = ' 1 '
} ;
2010-06-18 19:16:14 +02:00
assert ( arg_action < _ACTION_MAX ) ;
return table [ arg_action ] ;
}
static int talk_initctl ( void ) {
2013-11-08 13:54:46 +01:00
struct init_request request = {
. magic = INIT_MAGIC ,
. sleeptime = 0 ,
. cmd = INIT_CMD_RUNLVL
} ;
2013-04-18 09:11:22 +02:00
_cleanup_close_ int fd = - 1 ;
2010-06-18 19:16:14 +02:00
char rl ;
2013-11-08 13:54:46 +01:00
int r ;
2010-06-18 04:44:53 +02:00
2013-03-14 00:40:01 +01:00
rl = action_to_runlevel ( ) ;
if ( ! rl )
2010-06-18 04:44:53 +02:00
return 0 ;
2010-06-18 19:16:14 +02:00
request . runlevel = rl ;
2013-03-14 00:40:01 +01:00
fd = open ( INIT_FIFO , O_WRONLY | O_NDELAY | O_CLOEXEC | O_NOCTTY ) ;
if ( fd < 0 ) {
2010-06-18 19:16:14 +02:00
if ( errno = = ENOENT )
return 0 ;
2010-06-18 04:44:53 +02:00
2010-06-18 19:16:14 +02:00
log_error ( " Failed to open " INIT_FIFO " : %m " ) ;
2010-06-18 04:44:53 +02:00
return - errno ;
2010-06-18 19:16:14 +02:00
}
2010-06-18 04:44:53 +02:00
2010-06-18 19:16:14 +02:00
errno = 0 ;
2010-06-18 04:44:53 +02:00
r = loop_write ( fd , & request , sizeof ( request ) , false ) ! = sizeof ( request ) ;
2013-03-14 00:40:01 +01:00
if ( r ) {
2010-06-18 19:16:14 +02:00
log_error ( " Failed to write to " INIT_FIFO " : %m " ) ;
2013-04-12 00:57:42 +02:00
return errno > 0 ? - errno : - EIO ;
2010-06-18 19:16:14 +02:00
}
2010-06-18 04:44:53 +02:00
return 1 ;
2010-06-17 22:57:28 +02:00
}
2013-11-08 17:07:07 +01:00
static int systemctl_main ( sd_bus * bus , int argc , char * argv [ ] , int bus_error ) {
2010-06-15 02:51:55 +02:00
static const struct {
const char * verb ;
const enum {
MORE ,
LESS ,
EQUAL
} argc_cmp ;
const int argc ;
2013-11-07 05:49:04 +01:00
int ( * const dispatch ) ( sd_bus * bus , char * * args ) ;
2010-06-15 02:51:55 +02:00
} verbs [ ] = {
2010-07-24 00:53:33 +02:00
{ " list-units " , LESS , 1 , list_units } ,
2011-07-25 04:58:02 +02:00
{ " list-unit-files " , EQUAL , 1 , list_unit_files } ,
2013-04-12 00:59:18 +02:00
{ " list-sockets " , LESS , 1 , list_sockets } ,
2010-07-24 00:53:33 +02:00
{ " list-jobs " , EQUAL , 1 , list_jobs } ,
{ " clear-jobs " , EQUAL , 1 , daemon_reload } ,
{ " cancel " , MORE , 2 , cancel_job } ,
{ " start " , MORE , 2 , start_unit } ,
{ " stop " , MORE , 2 , start_unit } ,
2011-03-17 03:41:51 +01:00
{ " condstop " , MORE , 2 , start_unit } , /* For compatibility with ALTLinux */
2010-07-24 00:53:33 +02:00
{ " reload " , MORE , 2 , start_unit } ,
{ " restart " , MORE , 2 , start_unit } ,
{ " try-restart " , MORE , 2 , start_unit } ,
{ " reload-or-restart " , MORE , 2 , start_unit } ,
{ " reload-or-try-restart " , MORE , 2 , start_unit } ,
{ " force-reload " , MORE , 2 , start_unit } , /* For compatibility with SysV */
2011-03-01 22:19:08 +01:00
{ " condreload " , MORE , 2 , start_unit } , /* For compatibility with ALTLinux */
2010-07-24 00:53:33 +02:00
{ " condrestart " , MORE , 2 , start_unit } , /* For compatibility with RH */
{ " isolate " , EQUAL , 2 , start_unit } ,
2010-10-22 16:11:50 +02:00
{ " kill " , MORE , 2 , kill_unit } ,
2012-12-27 17:39:48 +01:00
{ " is-active " , MORE , 2 , check_unit_active } ,
{ " check " , MORE , 2 , check_unit_active } ,
{ " is-failed " , MORE , 2 , check_unit_failed } ,
2010-07-24 00:53:33 +02:00
{ " show " , MORE , 1 , show } ,
2013-02-14 22:55:24 +01:00
{ " status " , MORE , 1 , show } ,
2012-06-04 19:48:32 +02:00
{ " help " , MORE , 2 , show } ,
2010-07-24 00:53:33 +02:00
{ " snapshot " , LESS , 2 , snapshot } ,
{ " delete " , MORE , 2 , delete_snapshot } ,
{ " daemon-reload " , EQUAL , 1 , daemon_reload } ,
{ " daemon-reexec " , EQUAL , 1 , daemon_reload } ,
2013-11-07 05:49:04 +01:00
{ " show-environment " , EQUAL , 1 , show_environment } ,
2010-07-24 00:53:33 +02:00
{ " set-environment " , MORE , 2 , set_environment } ,
{ " unset-environment " , MORE , 2 , set_environment } ,
{ " halt " , EQUAL , 1 , start_special } ,
{ " poweroff " , EQUAL , 1 , start_special } ,
{ " reboot " , EQUAL , 1 , start_special } ,
2010-10-14 00:56:12 +02:00
{ " kexec " , EQUAL , 1 , start_special } ,
2012-05-05 02:06:58 +02:00
{ " suspend " , EQUAL , 1 , start_special } ,
{ " hibernate " , EQUAL , 1 , start_special } ,
2012-10-28 00:49:04 +02:00
{ " hybrid-sleep " , EQUAL , 1 , start_special } ,
2010-07-24 00:53:33 +02:00
{ " default " , EQUAL , 1 , start_special } ,
{ " rescue " , EQUAL , 1 , start_special } ,
{ " emergency " , EQUAL , 1 , start_special } ,
2010-10-14 00:56:12 +02:00
{ " exit " , EQUAL , 1 , start_special } ,
2010-08-31 00:23:34 +02:00
{ " reset-failed " , MORE , 1 , reset_failed } ,
2010-07-24 00:53:33 +02:00
{ " enable " , MORE , 2 , enable_unit } ,
{ " disable " , MORE , 2 , enable_unit } ,
2011-07-25 04:58:02 +02:00
{ " is-enabled " , MORE , 2 , unit_is_enabled } ,
{ " reenable " , MORE , 2 , enable_unit } ,
{ " preset " , MORE , 2 , enable_unit } ,
{ " mask " , MORE , 2 , enable_unit } ,
{ " unmask " , MORE , 2 , enable_unit } ,
2012-05-11 17:35:46 +02:00
{ " link " , MORE , 2 , enable_unit } ,
{ " switch-root " , MORE , 2 , switch_root } ,
2013-01-18 00:36:12 +01:00
{ " list-dependencies " , LESS , 2 , list_dependencies } ,
2013-05-28 11:05:48 +02:00
{ " set-default " , EQUAL , 2 , enable_unit } ,
{ " get-default " , LESS , 1 , get_default } ,
2013-06-27 21:14:56 +02:00
{ " set-property " , MORE , 3 , set_property } ,
2010-06-15 02:51:55 +02:00
} ;
2010-06-17 22:57:28 +02:00
int left ;
2010-06-15 02:51:55 +02:00
unsigned i ;
2010-06-17 22:57:28 +02:00
assert ( argc > = 0 ) ;
assert ( argv ) ;
2010-06-15 02:51:55 +02:00
left = argc - optind ;
if ( left < = 0 )
/* Special rule: no arguments means "list-units" */
i = 0 ;
else {
2012-06-04 19:48:32 +02:00
if ( streq ( argv [ optind ] , " help " ) & & ! argv [ optind + 1 ] ) {
log_error ( " This command expects one or more "
" unit names. Did you mean --help? " ) ;
return - EINVAL ;
2010-07-01 01:06:58 +02:00
}
2010-06-15 02:51:55 +02:00
for ( i = 0 ; i < ELEMENTSOF ( verbs ) ; i + + )
if ( streq ( argv [ optind ] , verbs [ i ] . verb ) )
break ;
if ( i > = ELEMENTSOF ( verbs ) ) {
2012-06-22 13:08:48 +02:00
log_error ( " Unknown operation '%s'. " , argv [ optind ] ) ;
2010-06-17 22:57:28 +02:00
return - EINVAL ;
2010-06-15 02:51:55 +02:00
}
}
switch ( verbs [ i ] . argc_cmp ) {
case EQUAL :
if ( left ! = verbs [ i ] . argc ) {
log_error ( " Invalid number of arguments. " ) ;
2010-06-17 22:57:28 +02:00
return - EINVAL ;
2010-06-15 02:51:55 +02:00
}
break ;
case MORE :
if ( left < verbs [ i ] . argc ) {
log_error ( " Too few arguments. " ) ;
2010-06-17 22:57:28 +02:00
return - EINVAL ;
2010-06-15 02:51:55 +02:00
}
break ;
case LESS :
if ( left > verbs [ i ] . argc ) {
log_error ( " Too many arguments. " ) ;
2010-06-17 22:57:28 +02:00
return - EINVAL ;
2010-06-15 02:51:55 +02:00
}
break ;
default :
assert_not_reached ( " Unknown comparison operator. " ) ;
}
2010-07-24 00:53:33 +02:00
/* Require a bus connection for all operations but
* enable / disable */
2011-07-25 04:58:02 +02:00
if ( ! streq ( verbs [ i ] . verb , " enable " ) & &
! streq ( verbs [ i ] . verb , " disable " ) & &
2011-12-14 22:23:56 +01:00
! streq ( verbs [ i ] . verb , " is-enabled " ) & &
2011-11-22 21:45:34 +01:00
! streq ( verbs [ i ] . verb , " list-unit-files " ) & &
2011-07-25 04:58:02 +02:00
! streq ( verbs [ i ] . verb , " reenable " ) & &
! streq ( verbs [ i ] . verb , " preset " ) & &
! streq ( verbs [ i ] . verb , " mask " ) & &
! streq ( verbs [ i ] . verb , " unmask " ) & &
2013-05-28 11:05:48 +02:00
! streq ( verbs [ i ] . verb , " link " ) & &
! streq ( verbs [ i ] . verb , " set-default " ) & &
! streq ( verbs [ i ] . verb , " get-default " ) ) {
2011-04-06 01:35:56 +02:00
if ( running_in_chroot ( ) > 0 ) {
log_info ( " Running in chroot, ignoring request. " ) ;
return 0 ;
}
2012-05-03 16:29:15 +02:00
if ( ( ( ! streq ( verbs [ i ] . verb , " reboot " ) & &
2012-05-04 01:02:32 +02:00
! streq ( verbs [ i ] . verb , " halt " ) & &
! streq ( verbs [ i ] . verb , " poweroff " ) ) | | arg_force < = 0 ) & & ! bus ) {
2013-11-08 17:07:07 +01:00
log_error ( " Failed to get D-Bus connection: %s " , strerror ( - bus_error ) ) ;
2011-09-29 15:31:53 +02:00
return - EIO ;
}
} else {
2011-07-25 04:58:02 +02:00
if ( ! bus & & ! avoid_bus ( ) ) {
2013-11-08 17:07:07 +01:00
log_error ( " Failed to get D-Bus connection: %s " , strerror ( - bus_error ) ) ;
2011-04-06 01:35:56 +02:00
return - EIO ;
}
2010-07-24 00:53:33 +02:00
}
2011-07-25 04:58:02 +02:00
return verbs [ i ] . dispatch ( bus , argv + optind ) ;
2010-06-17 22:57:28 +02:00
}
2011-07-02 23:09:59 +02:00
static int send_shutdownd ( usec_t t , char mode , bool dry_run , bool warn , const char * message ) {
2013-11-08 13:54:46 +01:00
2013-03-25 00:59:00 +01:00
struct sd_shutdown_command c = {
. usec = t ,
. mode = mode ,
. dry_run = dry_run ,
. warn_wall = warn ,
} ;
2013-11-08 13:54:46 +01:00
2013-03-25 00:59:00 +01:00
union sockaddr_union sockaddr = {
. un . sun_family = AF_UNIX ,
. un . sun_path = " /run/systemd/shutdownd " ,
} ;
2013-11-08 13:54:46 +01:00
struct iovec iovec [ 2 ] = { {
. iov_base = ( char * ) & c ,
2013-03-25 00:59:00 +01:00
. iov_len = offsetof ( struct sd_shutdown_command , wall_message ) ,
2013-11-08 13:54:46 +01:00
} } ;
2013-03-25 00:59:00 +01:00
struct msghdr msghdr = {
. msg_name = & sockaddr ,
. msg_namelen = offsetof ( struct sockaddr_un , sun_path )
+ sizeof ( " /run/systemd/shutdownd " ) - 1 ,
. msg_iov = iovec ,
. msg_iovlen = 1 ,
} ;
2012-04-11 02:04:46 +02:00
2013-11-08 13:54:46 +01:00
_cleanup_close_ int fd ;
2012-04-11 02:04:46 +02:00
fd = socket ( AF_UNIX , SOCK_DGRAM | SOCK_CLOEXEC , 0 ) ;
if ( fd < 0 )
return - errno ;
2010-08-16 15:37:52 +02:00
2013-03-25 00:59:00 +01:00
if ( ! isempty ( message ) ) {
2012-04-11 02:04:46 +02:00
iovec [ 1 ] . iov_base = ( char * ) message ;
iovec [ 1 ] . iov_len = strlen ( message ) ;
2013-03-25 00:59:00 +01:00
msghdr . msg_iovlen + + ;
2012-04-11 02:04:46 +02:00
}
2010-08-16 15:37:52 +02:00
2013-02-14 19:32:19 +01:00
if ( sendmsg ( fd , & msghdr , MSG_NOSIGNAL ) < 0 )
2010-08-16 15:37:52 +02:00
return - errno ;
return 0 ;
}
2013-11-07 05:49:04 +01:00
static int reload_with_fallback ( sd_bus * bus ) {
2010-06-17 22:57:28 +02:00
if ( bus ) {
/* First, try systemd via D-Bus. */
2011-08-31 03:31:27 +02:00
if ( daemon_reload ( bus , NULL ) > = 0 )
2010-06-17 22:57:28 +02:00
return 0 ;
}
/* Nothing else worked, so let's try signals */
assert ( arg_action = = ACTION_RELOAD | | arg_action = = ACTION_REEXEC ) ;
if ( kill ( 1 , arg_action = = ACTION_RELOAD ? SIGHUP : SIGTERM ) < 0 ) {
log_error ( " kill() failed: %m " ) ;
return - errno ;
}
return 0 ;
}
2013-11-07 05:49:04 +01:00
static int start_with_fallback ( sd_bus * bus ) {
2010-06-17 22:57:28 +02:00
if ( bus ) {
/* First, try systemd via D-Bus. */
2011-07-25 04:58:02 +02:00
if ( start_unit ( bus , NULL ) > = 0 )
2010-07-11 04:22:00 +02:00
goto done ;
2010-06-17 22:57:28 +02:00
}
/* Nothing else worked, so let's try
* / dev / initctl */
2010-08-13 04:53:00 +02:00
if ( talk_initctl ( ) > 0 )
2010-07-11 04:22:00 +02:00
goto done ;
2010-06-18 19:16:14 +02:00
log_error ( " Failed to talk to init daemon. " ) ;
return - EIO ;
2010-07-11 04:22:00 +02:00
done :
warn_wall ( arg_action ) ;
return 0 ;
2010-06-17 22:57:28 +02:00
}
2012-07-22 14:42:09 +02:00
static _noreturn_ void halt_now ( enum action a ) {
2012-02-15 20:05:49 +01:00
2013-11-06 09:02:41 +01:00
_cleanup_free_ char * param = NULL ;
2012-02-15 20:05:49 +01:00
/* Make sure C-A-D is handled by the kernel from this
* point on . . . */
reboot ( RB_ENABLE_CAD ) ;
2012-02-29 22:22:15 +01:00
switch ( a ) {
2012-02-15 20:05:49 +01:00
case ACTION_HALT :
log_info ( " Halting. " ) ;
reboot ( RB_HALT_SYSTEM ) ;
break ;
case ACTION_POWEROFF :
log_info ( " Powering off. " ) ;
reboot ( RB_POWER_OFF ) ;
break ;
case ACTION_REBOOT :
2013-11-08 13:54:46 +01:00
2013-11-06 09:02:41 +01:00
if ( read_one_line_file ( REBOOT_PARAM_FILE , & param ) = = 0 ) {
log_info ( " Rebooting with arg '%s'. " , param ) ;
syscall ( SYS_reboot , LINUX_REBOOT_MAGIC1 , LINUX_REBOOT_MAGIC2 ,
LINUX_REBOOT_CMD_RESTART2 , param ) ;
} else {
log_info ( " Rebooting. " ) ;
reboot ( RB_AUTOBOOT ) ;
}
2012-02-15 20:05:49 +01:00
break ;
default :
assert_not_reached ( " Unknown halt action. " ) ;
}
assert_not_reached ( " Uh? This shouldn't happen. " ) ;
}
2013-11-07 05:49:04 +01:00
static int halt_main ( sd_bus * bus ) {
2010-06-17 22:57:28 +02:00
int r ;
2013-01-12 00:09:22 +01:00
r = check_inhibitors ( bus , arg_action ) ;
if ( r < 0 )
return r ;
2013-01-11 04:24:05 +01:00
2010-07-08 21:31:23 +02:00
if ( geteuid ( ) ! = 0 ) {
2012-04-11 00:36:44 +02:00
/* Try logind if we are a normal user and no special
* mode applies . Maybe PolicyKit allows us to shutdown
* the machine . */
if ( arg_when < = 0 & &
! arg_dry & &
2013-01-11 04:24:05 +01:00
arg_force < = 0 & &
2012-04-11 00:36:44 +02:00
( arg_action = = ACTION_POWEROFF | |
arg_action = = ACTION_REBOOT ) ) {
2012-02-29 22:22:15 +01:00
r = reboot_with_logind ( bus , arg_action ) ;
if ( r > = 0 )
return r ;
}
2010-08-25 22:12:50 +02:00
log_error ( " Must be root. " ) ;
2010-07-08 21:31:23 +02:00
return - EPERM ;
}
2010-08-16 15:37:52 +02:00
if ( arg_when > 0 ) {
2013-04-18 09:11:22 +02:00
_cleanup_free_ char * m ;
2010-08-16 19:26:27 +02:00
m = strv_join ( arg_wall , " " ) ;
2013-11-08 13:54:46 +01:00
if ( ! m )
return log_oom ( ) ;
2010-08-16 19:26:27 +02:00
r = send_shutdownd ( arg_when ,
arg_action = = ACTION_HALT ? ' H ' :
arg_action = = ACTION_POWEROFF ? ' P ' :
2012-04-11 02:04:46 +02:00
arg_action = = ACTION_KEXEC ? ' K ' :
2010-08-16 19:26:27 +02:00
' r ' ,
2011-07-02 23:09:59 +02:00
arg_dry ,
2010-08-16 19:26:27 +02:00
! arg_no_wall ,
m ) ;
if ( r < 0 )
2010-08-16 15:37:52 +02:00
log_warning ( " Failed to talk to shutdownd, proceeding with immediate shutdown: %s " , strerror ( - r ) ) ;
2010-08-16 22:40:11 +02:00
else {
2012-04-11 00:36:44 +02:00
char date [ FORMAT_TIMESTAMP_MAX ] ;
2010-08-16 22:40:11 +02:00
log_info ( " Shutdown scheduled for %s, use 'shutdown -c' to cancel. " ,
format_timestamp ( date , sizeof ( date ) , arg_when ) ) ;
2010-08-16 15:37:52 +02:00
return 0 ;
2010-08-16 22:40:11 +02:00
}
2010-08-16 15:37:52 +02:00
}
2012-05-03 16:17:39 +02:00
if ( ! arg_dry & & ! arg_force )
2010-06-17 22:57:28 +02:00
return start_with_fallback ( bus ) ;
2010-08-14 19:14:52 +02:00
if ( ! arg_no_wtmp ) {
if ( sd_booted ( ) > 0 )
log_debug ( " Not writing utmp record, assuming that systemd-update-utmp is used. " ) ;
2012-04-11 00:36:44 +02:00
else {
r = utmp_put_shutdown ( ) ;
if ( r < 0 )
log_warning ( " Failed to write utmp record: %s " , strerror ( - r ) ) ;
}
2010-08-14 19:14:52 +02:00
}
2010-06-17 22:57:28 +02:00
if ( arg_dry )
return 0 ;
2012-02-15 20:05:49 +01:00
halt_now ( arg_action ) ;
2010-06-17 22:57:28 +02:00
/* We should never reach this. */
return - ENOSYS ;
}
static int runlevel_main ( void ) {
int r , runlevel , previous ;
2011-07-25 04:58:02 +02:00
r = utmp_get_runlevel ( & runlevel , & previous ) ;
if ( r < 0 ) {
puts ( " unknown " ) ;
2010-06-17 22:57:28 +02:00
return r ;
}
printf ( " %c %c \n " ,
previous < = 0 ? ' N ' : previous ,
runlevel < = 0 ? ' N ' : runlevel ) ;
return 0 ;
}
int main ( int argc , char * argv [ ] ) {
2013-11-07 05:49:04 +01:00
_cleanup_bus_unref_ sd_bus * bus = NULL ;
int r ;
2010-06-17 22:57:28 +02:00
2012-11-12 20:16:07 +01:00
setlocale ( LC_ALL , " " ) ;
2010-06-17 22:57:28 +02:00
log_parse_environment ( ) ;
2010-08-16 22:39:02 +02:00
log_open ( ) ;
2010-06-17 22:57:28 +02:00
2013-09-19 23:12:00 +02:00
/* Explicitly not on_tty() to avoid setting cached value.
* This becomes relevant for piping output which might be
* ellipsized . */
original_stdout_is_tty = isatty ( STDOUT_FILENO ) ;
2012-04-11 02:04:46 +02:00
r = parse_argv ( argc , argv ) ;
2013-11-07 05:49:04 +01:00
if ( r < = 0 )
2010-06-17 22:57:28 +02:00
goto finish ;
2010-06-15 02:51:55 +02:00
2010-06-17 22:57:28 +02:00
/* /sbin/runlevel doesn't need to communicate via D-Bus, so
* let ' s shortcut this */
if ( arg_action = = ACTION_RUNLEVEL ) {
2010-08-31 21:05:54 +02:00
r = runlevel_main ( ) ;
2010-06-17 22:57:28 +02:00
goto finish ;
}
2011-04-06 01:35:56 +02:00
if ( running_in_chroot ( ) > 0 & & arg_action ! = ACTION_SYSTEMCTL ) {
log_info ( " Running in chroot, ignoring request. " ) ;
2013-11-07 05:49:04 +01:00
r = 0 ;
2011-04-06 01:35:56 +02:00
goto finish ;
}
2013-11-08 17:07:07 +01:00
if ( ! avoid_bus ( ) )
r = bus_open_transport_systemd ( arg_transport , arg_host , arg_scope ! = UNIT_FILE_SYSTEM , & bus ) ;
/* systemctl_main() will print an error message for the bus
* connection , but only if it needs to */
2010-06-17 22:57:28 +02:00
switch ( arg_action ) {
2010-08-31 21:05:54 +02:00
case ACTION_SYSTEMCTL :
2013-11-07 05:49:04 +01:00
r = systemctl_main ( bus , argc , argv , r ) ;
2010-06-17 22:57:28 +02:00
break ;
case ACTION_HALT :
case ACTION_POWEROFF :
case ACTION_REBOOT :
2011-02-20 21:09:07 +01:00
case ACTION_KEXEC :
2010-08-31 21:05:54 +02:00
r = halt_main ( bus ) ;
2010-06-17 22:57:28 +02:00
break ;
case ACTION_RUNLEVEL2 :
case ACTION_RUNLEVEL3 :
case ACTION_RUNLEVEL4 :
case ACTION_RUNLEVEL5 :
case ACTION_RESCUE :
2010-06-18 04:22:59 +02:00
case ACTION_EMERGENCY :
2010-06-18 04:44:53 +02:00
case ACTION_DEFAULT :
2010-08-31 21:05:54 +02:00
r = start_with_fallback ( bus ) ;
2010-06-17 22:57:28 +02:00
break ;
2010-06-15 02:51:55 +02:00
2010-06-17 22:57:28 +02:00
case ACTION_RELOAD :
case ACTION_REEXEC :
2010-08-31 21:05:54 +02:00
r = reload_with_fallback ( bus ) ;
2010-06-17 22:57:28 +02:00
break ;
2012-07-30 17:25:39 +02:00
case ACTION_CANCEL_SHUTDOWN : {
2013-11-07 05:49:04 +01:00
_cleanup_free_ char * m = NULL ;
2012-07-30 17:25:39 +02:00
if ( arg_wall ) {
m = strv_join ( arg_wall , " " ) ;
if ( ! m ) {
2013-11-07 05:49:04 +01:00
r = log_oom ( ) ;
2012-07-30 17:25:39 +02:00
goto finish ;
}
}
2013-11-07 05:49:04 +01:00
2012-07-30 17:25:39 +02:00
r = send_shutdownd ( arg_when , SD_SHUTDOWN_NONE , false , ! arg_no_wall , m ) ;
if ( r < 0 )
log_warning ( " Failed to talk to shutdownd, shutdown hasn't been cancelled: %s " , strerror ( - r ) ) ;
2010-08-16 15:37:52 +02:00
break ;
2012-07-30 17:25:39 +02:00
}
2010-08-16 15:37:52 +02:00
2010-06-18 04:44:53 +02:00
case ACTION_RUNLEVEL :
2013-11-07 05:49:04 +01:00
case _ACTION_INVALID :
2010-06-17 22:57:28 +02:00
default :
assert_not_reached ( " Unknown action " ) ;
}
2010-06-15 02:51:55 +02:00
finish :
2013-11-07 05:49:04 +01:00
pager_close ( ) ;
ask_password_agent_close ( ) ;
polkit_agent_close ( ) ;
2010-06-15 02:51:55 +02:00
2013-04-11 04:40:58 +02:00
strv_free ( arg_types ) ;
2013-07-18 13:24:12 +02:00
strv_free ( arg_states ) ;
2013-04-11 04:40:58 +02:00
strv_free ( arg_properties ) ;
2010-07-23 05:24:05 +02:00
2013-11-07 05:49:04 +01:00
return r < 0 ? EXIT_FAILURE : r ;
2010-06-15 02:51:55 +02:00
}