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
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>
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>
2010-06-15 02:51:55 +02:00
# include <dbus/dbus.h>
2012-01-05 16:01:58 +01:00
# include <systemd/sd-daemon.h>
2012-04-11 02:04:46 +02:00
# include <systemd/sd-shutdown.h>
2013-01-15 03:00:43 +01:00
# include <systemd/sd-login.h>
2012-01-05 16:01:58 +01:00
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-06 05:06:40 +02:00
# include "dbus-common.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"
2010-06-15 02:51:55 +02:00
static const char * arg_type = NULL ;
2012-07-10 18:03:03 +02:00
static const char * arg_load_state = NULL ;
2010-07-23 05:24:05 +02:00
static char * * arg_property = NULL ;
2010-06-15 02:51:55 +02:00
static bool arg_all = false ;
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-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-02-16 20:34:59 +01:00
static bool arg_failed = false ;
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 {
2010-06-17 22:57:28 +02:00
ACTION_INVALID ,
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 ;
2011-03-12 01:03:13 +01:00
static enum transport {
TRANSPORT_NORMAL ,
TRANSPORT_SSH ,
TRANSPORT_POLKIT
} arg_transport = TRANSPORT_NORMAL ;
static const char * arg_host = NULL ;
2012-01-04 18:33:36 +01:00
static unsigned arg_lines = 10 ;
static OutputMode arg_output = OUTPUT_SHORT ;
2010-06-17 22:57:28 +02:00
2010-07-07 03:43:39 +02:00
static bool private_bus = false ;
2011-07-25 04:58:02 +02:00
static int daemon_reload ( DBusConnection * 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 ;
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 ;
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
2012-10-04 13:12:23 +02:00
static const char * ansi_highlight ( bool b ) {
if ( ! on_tty ( ) )
return " " ;
return b ? ANSI_HIGHLIGHT_ON : ANSI_HIGHLIGHT_OFF ;
}
2012-01-13 21:56:09 +01:00
static const char * ansi_highlight_red ( bool b ) {
2010-08-11 15:19:31 +02:00
if ( ! on_tty ( ) )
2010-07-20 21:04:32 +02:00
return " " ;
2012-01-13 21:56:09 +01:00
return b ? ANSI_HIGHLIGHT_RED_ON : ANSI_HIGHLIGHT_OFF ;
2010-07-20 21:04:32 +02:00
}
2010-08-11 15:19:31 +02:00
static const char * ansi_highlight_green ( bool b ) {
if ( ! on_tty ( ) )
return " " ;
return b ? ANSI_HIGHLIGHT_GREEN_ON : ANSI_HIGHLIGHT_OFF ;
}
2010-08-31 21:05:54 +02:00
static int translate_bus_error_to_exit_status ( int r , const DBusError * error ) {
assert ( error ) ;
if ( ! dbus_error_is_set ( error ) )
return r ;
if ( dbus_error_has_name ( error , DBUS_ERROR_ACCESS_DENIED ) | |
dbus_error_has_name ( error , BUS_ERROR_ONLY_BY_DEPENDENCY ) | |
dbus_error_has_name ( error , BUS_ERROR_NO_ISOLATION ) | |
dbus_error_has_name ( error , BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE ) )
return EXIT_NOPERMISSION ;
if ( dbus_error_has_name ( error , BUS_ERROR_NO_SUCH_UNIT ) )
return EXIT_NOTINSTALLED ;
if ( dbus_error_has_name ( error , BUS_ERROR_JOB_TYPE_NOT_APPLICABLE ) | |
dbus_error_has_name ( error , BUS_ERROR_NOT_SUPPORTED ) )
return EXIT_NOTIMPLEMENTED ;
if ( dbus_error_has_name ( error , BUS_ERROR_LOAD_FAILED ) )
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 ) {
const char * d1 , * d2 ;
const struct unit_info * u = a , * v = b ;
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
}
2011-02-16 20:34:59 +01:00
static bool output_show_unit ( const struct unit_info * u ) {
2010-09-07 10:30:52 +02:00
const char * dot ;
2010-09-15 03:12:04 +02:00
2011-02-16 20:34:59 +01:00
if ( arg_failed )
return streq ( u - > active_state , " failed " ) ;
2010-09-07 10:30:52 +02:00
return ( ! arg_type | | ( ( dot = strrchr ( u - > id , ' . ' ) ) & &
streq ( dot + 1 , arg_type ) ) ) & &
2012-07-10 18:03:03 +02:00
( ! arg_load_state | | streq ( u - > load_state , arg_load_state ) ) & &
( arg_all | | ! ( streq ( u - > active_state , " inactive " )
| | u - > following [ 0 ] ) | | u - > job_id > 0 ) ;
2010-09-07 10:30:52 +02:00
}
2010-09-07 10:30:51 +02:00
static void output_units_list ( const struct unit_info * unit_infos , unsigned c ) {
2011-09-27 11:20:20 +02:00
unsigned id_len , max_id_len , active_len , sub_len , job_len , desc_len , n_shown = 0 ;
2010-09-15 03:12:04 +02:00
const struct unit_info * u ;
2012-10-28 13:22:37 +01:00
int job_count = 0 ;
2010-09-07 10:30:52 +02:00
2011-09-27 11:20:20 +02:00
max_id_len = sizeof ( " UNIT " ) - 1 ;
2010-09-15 03:12:04 +02:00
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 ) ) ;
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 ) ) ;
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
}
2011-09-27 11:20:20 +02:00
if ( ! arg_full ) {
unsigned basic_len ;
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 ;
if ( job_count )
basic_len + = job_len + 1 ;
2011-09-27 11:20:20 +02:00
if ( basic_len < ( unsigned ) columns ( ) ) {
unsigned extra_len , incr ;
extra_len = columns ( ) - basic_len ;
/* 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 ;
/* 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-02-14 19:32:19 +01:00
char _cleanup_free_ * e = NULL ;
2010-09-15 03:12:04 +02:00
const char * on_loaded , * off_loaded ;
const char * on_active , * off_active ;
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 ) {
2012-10-28 13:22:37 +01:00
printf ( " %-*s %-6s %-*s %-*s " , id_len , " UNIT " , " LOAD " ,
active_len , " ACTIVE " , sub_len , " SUB " ) ;
if ( job_count )
printf ( " %-*s " , job_len , " JOB " ) ;
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 + + ;
2011-12-06 01:14:36 +01:00
if ( streq ( u - > load_state , " error " ) ) {
2012-01-13 21:56:09 +01:00
on_loaded = ansi_highlight_red ( true ) ;
off_loaded = ansi_highlight_red ( false ) ;
2010-09-15 03:12:04 +02:00
} else
on_loaded = off_loaded = " " ;
if ( streq ( u - > active_state , " failed " ) ) {
2012-01-13 21:56:09 +01:00
on_active = ansi_highlight_red ( true ) ;
off_active = ansi_highlight_red ( false ) ;
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
2012-10-28 13:22:37 +01:00
printf ( " %-*s %s%-6s%s %s%-*s %-*s%s %-*s " ,
2011-09-27 11:20:20 +02:00
id_len , e ? e : u - > id ,
2010-09-15 03:12:04 +02:00
on_loaded , u - > load_state , off_loaded ,
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 : " " ) ;
2011-09-29 21:18:17 +02:00
if ( ! arg_full & & arg_no_pager )
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 ( " " ) ;
2012-10-04 13:12:23 +02:00
on = ansi_highlight ( true ) ;
off = ansi_highlight ( false ) ;
} else {
on = ansi_highlight_red ( true ) ;
off = ansi_highlight_red ( false ) ;
}
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-02-14 22:55:24 +01:00
static int get_unit_list ( DBusConnection * bus , DBusMessage * * reply ,
struct unit_info * * unit_infos , unsigned * c ) {
2013-01-31 09:57:25 +01:00
DBusMessageIter iter , sub ;
2013-02-14 22:55:24 +01:00
unsigned n_units = 0 ;
2013-01-14 02:11:22 +01:00
int r ;
2010-06-15 02:51:55 +02:00
2013-02-14 22:55:24 +01:00
assert ( bus ) ;
assert ( unit_infos ) ;
assert ( c ) ;
2011-01-04 01:04:20 +01:00
2013-01-14 02:11:22 +01:00
r = bus_method_call_with_reply (
2012-08-08 01:32:30 +02:00
bus ,
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
" ListUnits " ,
2013-02-14 22:55:24 +01:00
reply ,
2012-08-08 01:32:30 +02:00
NULL ,
DBUS_TYPE_INVALID ) ;
2013-01-14 02:11:22 +01:00
if ( r < 0 )
return r ;
2010-06-15 02:51:55 +02:00
2013-02-14 22:55:24 +01:00
if ( ! dbus_message_iter_init ( * reply , & iter ) | |
2010-06-15 02:51:55 +02:00
dbus_message_iter_get_arg_type ( & iter ) ! = DBUS_TYPE_ARRAY | |
dbus_message_iter_get_element_type ( & iter ) ! = DBUS_TYPE_STRUCT ) {
log_error ( " Failed to parse reply. " ) ;
2013-01-14 02:11:22 +01:00
return - EIO ;
2010-06-15 02:51:55 +02:00
}
dbus_message_iter_recurse ( & iter , & sub ) ;
while ( dbus_message_iter_get_arg_type ( & sub ) ! = DBUS_TYPE_INVALID ) {
2010-08-14 03:40:10 +02:00
struct unit_info * u ;
2010-06-15 02:51:55 +02:00
2013-02-14 22:55:24 +01:00
if ( * c > = n_units ) {
2010-08-14 03:40:10 +02:00
struct unit_info * w ;
2013-04-01 08:08:05 +02:00
n_units = MAX ( 2 * * c , 16u ) ;
2013-02-14 22:55:24 +01:00
w = realloc ( * unit_infos , sizeof ( struct unit_info ) * n_units ) ;
2013-01-14 02:11:22 +01:00
if ( ! w )
return log_oom ( ) ;
2010-08-14 03:40:10 +02:00
2013-02-14 22:55:24 +01:00
* unit_infos = w ;
2010-08-14 03:40:10 +02:00
}
2013-02-14 22:55:24 +01:00
u = * unit_infos + * c ;
2010-08-14 03:40:10 +02:00
2013-01-31 09:57:25 +01:00
bus_parse_unit_info ( & sub , u ) ;
2010-06-15 02:51:55 +02:00
2010-08-14 03:40:10 +02:00
dbus_message_iter_next ( & sub ) ;
2013-02-14 22:55:24 +01:00
( * c ) + + ;
2010-08-14 03:40:10 +02:00
}
2013-02-14 22:55:24 +01:00
if ( * c > 0 )
qsort ( * unit_infos , * c , sizeof ( struct unit_info ) , compare_unit_info ) ;
return 0 ;
}
static int list_units ( DBusConnection * bus , char * * args ) {
_cleanup_dbus_message_unref_ DBusMessage * reply = NULL ;
_cleanup_free_ struct unit_info * unit_infos = NULL ;
unsigned c = 0 ;
int r ;
pager_open_if_enabled ( ) ;
r = get_unit_list ( bus , & reply , & unit_infos , & c ) ;
if ( r < 0 )
return r ;
if ( c > 0 )
2011-01-22 02:18:59 +01:00
output_units_list ( unit_infos , c ) ;
2010-07-16 02:56:00 +02:00
2013-01-14 02:11:22 +01:00
return 0 ;
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 ;
return ! arg_type | | ( ( dot = strrchr ( u - > path , ' . ' ) ) & & streq ( dot + 1 , arg_type ) ) ;
}
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 ;
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-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 )
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-02-14 19:32:19 +01:00
char _cleanup_free_ * 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 ) {
2012-01-13 21:56:09 +01:00
on = ansi_highlight_red ( true ) ;
off = ansi_highlight_red ( false ) ;
2011-07-25 04:58:02 +02:00
} else if ( u - > state = = UNIT_FILE_ENABLED ) {
on = ansi_highlight_green ( true ) ;
off = ansi_highlight_green ( false ) ;
} 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 ) ;
}
static int list_unit_files ( DBusConnection * bus , char * * args ) {
2013-01-14 02:11:22 +01:00
_cleanup_dbus_message_unref_ DBusMessage * reply = NULL ;
_cleanup_free_ UnitFileList * units = NULL ;
2011-07-25 04:58:02 +02:00
DBusMessageIter iter , sub , sub2 ;
unsigned c = 0 , n_units = 0 ;
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 ;
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 ) ;
}
hashmap_free ( h ) ;
} else {
2013-01-14 02:11:22 +01:00
r = bus_method_call_with_reply (
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 " ,
& reply ,
NULL ,
DBUS_TYPE_INVALID ) ;
2013-01-14 02:11:22 +01:00
if ( r < 0 )
return r ;
2011-07-25 04:58:02 +02:00
if ( ! dbus_message_iter_init ( reply , & iter ) | |
dbus_message_iter_get_arg_type ( & iter ) ! = DBUS_TYPE_ARRAY | |
dbus_message_iter_get_element_type ( & iter ) ! = DBUS_TYPE_STRUCT ) {
log_error ( " Failed to parse reply. " ) ;
2013-01-14 02:11:22 +01:00
return - EIO ;
2011-07-25 04:58:02 +02:00
}
dbus_message_iter_recurse ( & iter , & sub ) ;
while ( dbus_message_iter_get_arg_type ( & sub ) ! = DBUS_TYPE_INVALID ) {
UnitFileList * u ;
const char * state ;
2013-01-16 00:49:31 +01:00
assert ( dbus_message_iter_get_arg_type ( & sub ) = = DBUS_TYPE_STRUCT ) ;
2011-07-25 04:58:02 +02:00
if ( c > = n_units ) {
UnitFileList * w ;
2013-04-01 08:08:05 +02:00
n_units = MAX ( 2 * c , 16u ) ;
2011-07-25 04:58:02 +02:00
w = realloc ( units , sizeof ( struct UnitFileList ) * n_units ) ;
2013-01-14 02:11:22 +01:00
if ( ! w )
return log_oom ( ) ;
2011-07-25 04:58:02 +02:00
units = w ;
}
2013-01-14 02:11:22 +01:00
u = units + c ;
2011-07-25 04:58:02 +02:00
dbus_message_iter_recurse ( & sub , & sub2 ) ;
if ( bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_STRING , & u - > path , true ) < 0 | |
bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_STRING , & state , false ) < 0 ) {
log_error ( " Failed to parse reply. " ) ;
2013-01-14 02:11:22 +01:00
return - EIO ;
2011-07-25 04:58:02 +02:00
}
u - > state = unit_file_state_from_string ( state ) ;
dbus_message_iter_next ( & sub ) ;
c + + ;
}
}
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 ) {
int i ;
_cleanup_free_ char * n = NULL ;
size_t len = 0 ;
2013-04-01 08:08:05 +02:00
size_t max_len = MAX ( columns ( ) , 20u ) ;
2013-01-17 21:34:11 +01: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 ) ) ;
}
len + = 2 ;
if ( len > max_len - 3 & & ! arg_full ) {
printf ( " %s... \n " , max_len % 2 ? " " : " " ) ;
return 0 ;
}
printf ( " %s " , draw_special_char ( last ? DRAW_TREE_RIGHT : DRAW_TREE_BRANCH ) ) ;
if ( arg_full ) {
printf ( " %s \n " , name ) ;
return 0 ;
}
n = ellipsize ( name , max_len - len , 100 ) ;
if ( ! n )
return log_oom ( ) ;
printf ( " %s \n " , n ) ;
return 0 ;
}
static int list_dependencies_get_dependencies ( DBusConnection * bus , const char * name , char * * * deps ) {
2013-01-18 00:29:47 +01:00
static const char dependencies [ ] =
" Requires \0 "
" RequiresOverridable \0 "
" Requisite \0 "
" RequisiteOverridable \0 "
" Wants \0 " ;
2013-01-17 21:34:11 +01:00
_cleanup_free_ char * path ;
const char * interface = " org.freedesktop.systemd1.Unit " ;
_cleanup_dbus_message_unref_ DBusMessage * reply = NULL ;
DBusMessageIter iter , sub , sub2 , sub3 ;
int r = 0 ;
char * * ret = NULL ;
assert ( bus ) ;
assert ( name ) ;
assert ( deps ) ;
path = unit_dbus_path_from_name ( name ) ;
if ( path = = NULL ) {
r = - EINVAL ;
goto finish ;
}
r = bus_method_call_with_reply (
bus ,
" org.freedesktop.systemd1 " ,
path ,
" org.freedesktop.DBus.Properties " ,
" GetAll " ,
& reply ,
NULL ,
DBUS_TYPE_STRING , & interface ,
DBUS_TYPE_INVALID ) ;
if ( r < 0 )
goto finish ;
if ( ! dbus_message_iter_init ( reply , & iter ) | |
dbus_message_iter_get_arg_type ( & iter ) ! = DBUS_TYPE_ARRAY | |
dbus_message_iter_get_element_type ( & iter ) ! = DBUS_TYPE_DICT_ENTRY ) {
log_error ( " Failed to parse reply. " ) ;
r = - EIO ;
goto finish ;
}
dbus_message_iter_recurse ( & iter , & sub ) ;
while ( dbus_message_iter_get_arg_type ( & sub ) ! = DBUS_TYPE_INVALID ) {
const char * prop ;
2013-01-18 00:52:45 +01:00
assert ( dbus_message_iter_get_arg_type ( & sub ) = = DBUS_TYPE_DICT_ENTRY ) ;
2013-01-17 21:34:11 +01:00
dbus_message_iter_recurse ( & sub , & sub2 ) ;
if ( bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_STRING , & prop , true ) < 0 ) {
log_error ( " Failed to parse reply. " ) ;
r = - EIO ;
goto finish ;
}
if ( dbus_message_iter_get_arg_type ( & sub2 ) ! = DBUS_TYPE_VARIANT ) {
log_error ( " Failed to parse reply. " ) ;
r = - EIO ;
goto finish ;
}
dbus_message_iter_recurse ( & sub2 , & sub3 ) ;
dbus_message_iter_next ( & sub ) ;
2013-01-18 00:29:47 +01:00
if ( ! nulstr_contains ( dependencies , prop ) )
2013-01-17 21:34:11 +01:00
continue ;
if ( dbus_message_iter_get_arg_type ( & sub3 ) = = DBUS_TYPE_ARRAY ) {
if ( dbus_message_iter_get_element_type ( & sub3 ) = = DBUS_TYPE_STRING ) {
DBusMessageIter sub4 ;
dbus_message_iter_recurse ( & sub3 , & sub4 ) ;
while ( dbus_message_iter_get_arg_type ( & sub4 ) ! = DBUS_TYPE_INVALID ) {
const char * s ;
assert ( dbus_message_iter_get_arg_type ( & sub4 ) = = DBUS_TYPE_STRING ) ;
dbus_message_iter_get_basic ( & sub4 , & s ) ;
2013-01-18 00:51:46 +01:00
r = strv_extend ( & ret , s ) ;
if ( r < 0 ) {
log_oom ( ) ;
2013-01-17 21:34:11 +01:00
goto finish ;
}
2013-01-18 00:51:46 +01:00
2013-01-17 21:34:11 +01:00
dbus_message_iter_next ( & sub4 ) ;
}
}
}
}
finish :
if ( r < 0 )
2013-01-18 00:53:06 +01:00
strv_free ( ret ) ;
else
* deps = ret ;
2013-01-17 21:34:11 +01:00
return r ;
}
static int list_dependencies_compare ( const void * _a , const void * _b ) {
const char * * a = ( const char * * ) _a , * * b = ( const char * * ) _b ;
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 ;
return strcasecmp ( * a , * b ) ;
}
static int list_dependencies_one ( DBusConnection * bus , const char * name , int level , char * * units , unsigned int branches ) {
2013-02-14 19:32:19 +01:00
char _cleanup_strv_free_ * * deps = NULL , * * u ;
2013-01-17 21:34:11 +01:00
char * * c ;
int r = 0 ;
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
qsort ( deps , strv_length ( deps ) , sizeof ( char * ) , list_dependencies_compare ) ;
STRV_FOREACH ( c , deps ) {
if ( strv_contains ( u , * c ) ) {
r = list_dependencies_print ( " ... " , level + 1 , ( branches < < 1 ) | ( c [ 1 ] = = NULL ? 0 : 1 ) , 1 ) ;
2013-02-14 19:32:19 +01:00
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 ) {
r = list_dependencies_one ( bus , * c , level + 1 , u , ( branches < < 1 ) | ( c [ 1 ] = = NULL ? 0 : 1 ) ) ;
if ( r < 0 )
2013-02-14 19:32:19 +01:00
return r ;
2013-01-17 21:34:11 +01:00
}
}
2013-02-14 19:32:19 +01:00
return 0 ;
2013-01-17 21:34:11 +01:00
}
static int list_dependencies ( DBusConnection * bus , char * * args ) {
_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 ) ;
return list_dependencies_one ( bus , u , 0 , NULL , 0 ) ;
2013-01-17 21:34:11 +01:00
}
2011-07-25 04:58:02 +02:00
static int list_jobs ( DBusConnection * bus , char * * args ) {
2013-01-14 02:11:22 +01:00
_cleanup_dbus_message_unref_ DBusMessage * reply = NULL ;
2010-06-15 02:51:55 +02:00
DBusMessageIter iter , sub , sub2 ;
unsigned k = 0 ;
2013-01-14 02:11:22 +01:00
int r ;
2010-06-15 02:51:55 +02:00
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
r = bus_method_call_with_reply (
2012-08-08 01:32:30 +02:00
bus ,
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
" ListJobs " ,
& reply ,
NULL ,
DBUS_TYPE_INVALID ) ;
2013-01-14 02:11:22 +01:00
if ( r < 0 )
return r ;
2010-06-15 02:51:55 +02:00
if ( ! dbus_message_iter_init ( reply , & iter ) | |
dbus_message_iter_get_arg_type ( & iter ) ! = DBUS_TYPE_ARRAY | |
dbus_message_iter_get_element_type ( & iter ) ! = DBUS_TYPE_STRUCT ) {
log_error ( " Failed to parse reply. " ) ;
2013-01-14 02:11:22 +01:00
return - EIO ;
2010-06-15 02:51:55 +02:00
}
dbus_message_iter_recurse ( & iter , & sub ) ;
2011-07-07 03:30:47 +02:00
if ( on_tty ( ) )
2010-08-31 16:56:08 +02:00
printf ( " %4s %-25s %-15s %-7s \n " , " JOB " , " UNIT " , " TYPE " , " STATE " ) ;
2010-06-15 02:51:55 +02:00
while ( dbus_message_iter_get_arg_type ( & sub ) ! = DBUS_TYPE_INVALID ) {
const char * name , * type , * state , * job_path , * unit_path ;
uint32_t id ;
2013-02-14 19:32:19 +01:00
char _cleanup_free_ * e = NULL ;
2010-06-15 02:51:55 +02:00
if ( dbus_message_iter_get_arg_type ( & sub ) ! = DBUS_TYPE_STRUCT ) {
log_error ( " Failed to parse reply. " ) ;
2013-01-14 02:11:22 +01:00
return - EIO ;
2010-06-15 02:51:55 +02:00
}
dbus_message_iter_recurse ( & sub , & sub2 ) ;
if ( bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_UINT32 , & id , true ) < 0 | |
bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_STRING , & name , true ) < 0 | |
bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_STRING , & type , true ) < 0 | |
bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_STRING , & state , true ) < 0 | |
bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_OBJECT_PATH , & job_path , true ) < 0 | |
bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_OBJECT_PATH , & unit_path , false ) < 0 ) {
log_error ( " Failed to parse reply. " ) ;
2013-01-14 02:11:22 +01:00
return - EIO ;
2010-06-15 02:51:55 +02:00
}
2010-08-31 16:56:08 +02:00
e = arg_full ? NULL : ellipsize ( name , 25 , 33 ) ;
printf ( " %4u %-25s %-15s %-7s \n " , id , e ? e : name , type , state ) ;
2010-07-20 20:33:19 +02:00
2010-06-15 02:51:55 +02:00
k + + ;
dbus_message_iter_next ( & sub ) ;
}
2011-07-07 03:30:47 +02:00
if ( on_tty ( ) )
2010-08-31 16:56:08 +02:00
printf ( " \n %u jobs listed. \n " , k ) ;
2013-01-14 02:11:22 +01:00
return 0 ;
2010-06-15 02:51:55 +02:00
}
2011-07-25 04:58:02 +02:00
static int load_unit ( DBusConnection * bus , char * * args ) {
2013-01-10 22:45:45 +01: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
STRV_FOREACH ( name , args + 1 ) {
2013-01-10 22:45:45 +01:00
_cleanup_free_ char * n = NULL ;
int r ;
2012-06-22 13:08:48 +02:00
n = unit_name_mangle ( * name ) ;
2013-01-14 02:11:22 +01:00
if ( ! n )
return log_oom ( ) ;
r = bus_method_call_with_reply (
2012-08-08 01:32:30 +02:00
bus ,
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
" LoadUnit " ,
NULL ,
NULL ,
2013-01-14 02:11:22 +01:00
DBUS_TYPE_STRING , & n ,
2012-08-08 01:32:30 +02:00
DBUS_TYPE_INVALID ) ;
2013-01-10 22:45:45 +01:00
if ( r < 0 )
return r ;
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
}
2011-07-25 04:58:02 +02:00
static int cancel_job ( DBusConnection * bus , char * * args ) {
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 ) {
2010-06-15 02:51:55 +02:00
log_error ( " Failed to parse job id: %s " , strerror ( - r ) ) ;
2013-01-10 22:45:45 +01:00
return r ;
2010-06-15 02:51:55 +02:00
}
2013-01-10 22:45:45 +01:00
r = bus_method_call_with_reply (
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 " ,
2012-08-08 01:32:30 +02:00
NULL ,
NULL ,
2013-01-10 22:45:45 +01:00
DBUS_TYPE_UINT32 , & id ,
2012-08-08 01:32:30 +02:00
DBUS_TYPE_INVALID ) ;
2013-01-10 22:45:45 +01:00
if ( r < 0 )
return r ;
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
}
2010-07-24 00:53:33 +02:00
static bool need_daemon_reload ( DBusConnection * bus , const char * unit ) {
2013-01-14 02:11:22 +01:00
_cleanup_dbus_message_unref_ DBusMessage * reply = NULL ;
2010-07-17 00:57:51 +02:00
dbus_bool_t b = FALSE ;
DBusMessageIter iter , sub ;
const char
* interface = " org.freedesktop.systemd1.Unit " ,
* property = " NeedDaemonReload " ,
* path ;
2013-01-14 02:11:22 +01:00
_cleanup_free_ char * n = NULL ;
2012-08-08 01:32:30 +02:00
int r ;
2010-07-17 00:57:51 +02:00
/* We ignore all errors here, since this is used to show a warning only */
2012-06-22 13:08:48 +02:00
n = unit_name_mangle ( unit ) ;
2013-01-15 11:58:42 +01:00
if ( ! n )
2013-01-14 02:11:22 +01:00
return log_oom ( ) ;
2013-02-27 15:01:06 +01:00
r = bus_method_call_with_reply (
2012-08-08 01:32:30 +02:00
bus ,
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
" GetUnit " ,
& reply ,
NULL ,
2013-01-14 02:11:22 +01:00
DBUS_TYPE_STRING , & n ,
2012-08-08 01:32:30 +02:00
DBUS_TYPE_INVALID ) ;
2013-01-14 02:11:22 +01:00
if ( r < 0 )
return r ;
2010-07-17 00:57:51 +02:00
if ( ! dbus_message_get_args ( reply , NULL ,
DBUS_TYPE_OBJECT_PATH , & path ,
DBUS_TYPE_INVALID ) )
2013-01-14 02:11:22 +01:00
return - EIO ;
2010-07-17 00:57:51 +02:00
2012-08-08 01:32:30 +02:00
dbus_message_unref ( reply ) ;
2013-01-14 02:11:22 +01:00
reply = NULL ;
r = bus_method_call_with_reply (
2012-08-08 01:32:30 +02:00
bus ,
2012-06-22 13:08:48 +02:00
" org.freedesktop.systemd1 " ,
path ,
" org.freedesktop.DBus.Properties " ,
2012-08-08 01:32:30 +02:00
" Get " ,
& reply ,
NULL ,
DBUS_TYPE_STRING , & interface ,
DBUS_TYPE_STRING , & property ,
DBUS_TYPE_INVALID ) ;
2013-01-14 02:11:22 +01:00
if ( r < 0 )
return r ;
2010-07-17 00:57:51 +02:00
if ( ! dbus_message_iter_init ( reply , & iter ) | |
dbus_message_iter_get_arg_type ( & iter ) ! = DBUS_TYPE_VARIANT )
2013-01-14 02:11:22 +01:00
return - EIO ;
2010-07-17 00:57:51 +02:00
dbus_message_iter_recurse ( & iter , & sub ) ;
if ( dbus_message_iter_get_arg_type ( & sub ) ! = DBUS_TYPE_BOOLEAN )
2013-01-14 02:11:22 +01:00
return - EIO ;
2010-07-17 00:57:51 +02:00
dbus_message_iter_get_basic ( & sub , & b ) ;
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 ;
2010-06-15 02:51:55 +02:00
static DBusHandlerResult wait_filter ( DBusConnection * connection , DBusMessage * message , void * data ) {
2013-02-14 19:32:19 +01:00
DBusError _cleanup_dbus_error_free_ error ;
2010-07-01 03:44:09 +02:00
WaitData * d = data ;
2010-06-15 02:51:55 +02:00
2013-02-14 19:32:19 +01:00
dbus_error_init ( & error ) ;
2010-06-15 02:51:55 +02:00
assert ( connection ) ;
assert ( message ) ;
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 " ,
dbus_message_get_interface ( message ) ,
dbus_message_get_member ( message ) ,
dbus_message_get_path ( message ) ) ;
2010-06-15 02:51:55 +02:00
if ( dbus_message_is_signal ( message , DBUS_INTERFACE_LOCAL , " Disconnected " ) ) {
log_error ( " Warning! D-Bus connection terminated. " ) ;
dbus_connection_close ( connection ) ;
} else if ( dbus_message_is_signal ( message , " org.freedesktop.systemd1.Manager " , " JobRemoved " ) ) {
uint32_t id ;
2012-05-03 22:53:25 +02:00
const char * path , * result , * unit ;
2010-06-15 02:51:55 +02:00
2011-02-24 02:36:34 +01:00
if ( dbus_message_get_args ( message , & error ,
DBUS_TYPE_UINT32 , & id ,
DBUS_TYPE_OBJECT_PATH , & path ,
2012-05-03 22:53:25 +02:00
DBUS_TYPE_STRING , & unit ,
2011-02-24 02:36:34 +01:00
DBUS_TYPE_STRING , & result ,
DBUS_TYPE_INVALID ) ) {
2010-06-15 02:51:55 +02:00
2013-01-14 02:13:26 +01:00
free ( set_remove ( d - > set , ( char * ) path ) ) ;
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-02-14 19:32:19 +01:00
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED ;
2011-02-24 02:36:34 +01:00
}
# ifndef LEGACY
dbus_error_free ( & error ) ;
2012-05-03 22:53:25 +02:00
if ( dbus_message_get_args ( message , & error ,
DBUS_TYPE_UINT32 , & id ,
DBUS_TYPE_OBJECT_PATH , & path ,
DBUS_TYPE_STRING , & result ,
DBUS_TYPE_INVALID ) ) {
/* Compatibility with older systemd versions <
* 183 during upgrades . This should be dropped
* one day . */
2013-01-14 02:13:26 +01:00
free ( set_remove ( d - > set , ( char * ) path ) ) ;
2011-02-24 02:36:34 +01:00
2012-05-03 22:53:25 +02:00
if ( * result )
d - > result = strdup ( result ) ;
2013-02-14 19:32:19 +01:00
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED ;
2012-05-03 22:53:25 +02:00
}
2011-02-24 02:36:34 +01:00
# endif
log_error ( " Failed to parse message: %s " , bus_error_message ( & error ) ) ;
2010-06-15 02:51:55 +02:00
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED ;
}
2010-06-15 04:24:30 +02:00
static int enable_wait_for_jobs ( DBusConnection * bus ) {
2010-06-15 02:51:55 +02:00
DBusError error ;
assert ( bus ) ;
2010-07-07 03:43:39 +02:00
if ( private_bus )
return 0 ;
2010-06-15 02:51:55 +02:00
dbus_error_init ( & error ) ;
dbus_bus_add_match ( bus ,
" type='signal', "
" sender='org.freedesktop.systemd1', "
" interface='org.freedesktop.systemd1.Manager', "
" member='JobRemoved', "
" path='/org/freedesktop/systemd1' " ,
& error ) ;
if ( dbus_error_is_set ( & error ) ) {
2010-08-25 19:49:23 +02:00
log_error ( " Failed to add match: %s " , bus_error_message ( & error ) ) ;
2010-07-05 00:58:07 +02:00
dbus_error_free ( & error ) ;
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
}
2010-06-15 04:24:30 +02:00
static int wait_for_jobs ( DBusConnection * bus , Set * s ) {
2012-09-14 15:11:07 +02:00
int r = 0 ;
2010-07-01 03:44:09 +02:00
WaitData d ;
2010-06-15 04:24:30 +02:00
assert ( bus ) ;
assert ( s ) ;
2010-07-01 03:44:09 +02:00
zero ( d ) ;
d . set = s ;
2012-09-14 15:11:07 +02:00
if ( ! dbus_connection_add_filter ( bus , wait_filter , & d , NULL ) )
return log_oom ( ) ;
2010-06-15 04:24:30 +02:00
2012-09-14 15:11:07 +02:00
while ( ! set_isempty ( s ) ) {
2010-07-01 03:44:09 +02:00
2012-09-14 15:11:07 +02:00
if ( ! dbus_connection_read_write_dispatch ( bus , - 1 ) ) {
log_error ( " Disconnected from bus. " ) ;
return - ECONNREFUSED ;
}
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
2012-09-19 08:15:07 +02:00
dbus_connection_remove_filter ( bus , wait_filter , & d ) ;
2010-06-15 04:24:30 +02:00
return r ;
}
2013-01-11 23:59:41 +01:00
static int check_one_unit ( DBusConnection * bus , const char * name , char * * check_states , bool quiet ) {
_cleanup_dbus_message_unref_ DBusMessage * reply = NULL ;
2013-01-14 02:11:22 +01:00
_cleanup_free_ char * n = NULL ;
2012-06-13 14:14:13 +02:00
DBusMessageIter iter , sub ;
2012-06-13 17:29:11 +02:00
const char
* interface = " org.freedesktop.systemd1.Unit " ,
* property = " ActiveState " ;
2013-01-11 23:59:41 +01:00
const char * state , * path ;
DBusError error ;
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
2013-01-11 23:59:41 +01:00
dbus_error_init ( & error ) ;
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 ( ) ;
2012-08-08 01:32:30 +02:00
r = bus_method_call_with_reply (
bus ,
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
" GetUnit " ,
& reply ,
2013-01-11 23:59:41 +01:00
& error ,
DBUS_TYPE_STRING , & n ,
2012-08-08 01:32:30 +02:00
DBUS_TYPE_INVALID ) ;
2013-01-11 23:59:41 +01:00
if ( r < 0 ) {
dbus_error_free ( & error ) ;
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
2012-08-08 01:32:30 +02:00
if ( ! dbus_message_get_args ( reply , NULL ,
2012-06-13 17:29:11 +02:00
DBUS_TYPE_OBJECT_PATH , & path ,
DBUS_TYPE_INVALID ) ) {
2012-08-08 01:32:30 +02:00
log_error ( " Failed to parse reply. " ) ;
2013-01-11 23:59:41 +01:00
return - EIO ;
2012-06-13 17:29:11 +02:00
}
dbus_message_unref ( reply ) ;
2013-01-11 23:59:41 +01:00
reply = NULL ;
r = bus_method_call_with_reply (
2012-08-08 01:32:30 +02:00
bus ,
" org.freedesktop.systemd1 " ,
path ,
" org.freedesktop.DBus.Properties " ,
" Get " ,
& reply ,
NULL ,
DBUS_TYPE_STRING , & interface ,
DBUS_TYPE_STRING , & property ,
DBUS_TYPE_INVALID ) ;
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 ( ! dbus_message_iter_init ( reply , & iter ) | |
dbus_message_iter_get_arg_type ( & iter ) ! = DBUS_TYPE_VARIANT ) {
log_error ( " Failed to parse reply. " ) ;
2013-01-11 23:59:41 +01:00
return r ;
2012-06-13 17:29:11 +02:00
}
2012-06-13 14:14:13 +02:00
dbus_message_iter_recurse ( & iter , & sub ) ;
2012-06-13 17:29:11 +02:00
if ( dbus_message_iter_get_arg_type ( & sub ) ! = DBUS_TYPE_STRING ) {
log_error ( " Failed to parse reply. " ) ;
2013-01-11 23:59:41 +01:00
return r ;
2012-06-13 14:14:13 +02:00
}
2012-06-13 17:29:11 +02:00
dbus_message_iter_get_basic ( & sub , & state ) ;
if ( ! quiet )
puts ( state ) ;
2013-01-11 23:59:41 +01:00
return strv_find ( check_states , state ) ? 1 : 0 ;
2012-06-13 14:14:13 +02:00
}
2012-06-13 18:27:41 +02:00
static void check_triggering_units (
2012-06-13 14:14:13 +02:00
DBusConnection * bus ,
const char * unit_name ) {
2012-10-02 23:07:00 +02:00
_cleanup_dbus_message_unref_ DBusMessage * reply = NULL ;
2012-06-13 14:14:13 +02:00
DBusMessageIter iter , sub ;
2012-06-13 17:29:11 +02:00
const char * interface = " org.freedesktop.systemd1.Unit " ,
2013-02-15 16:10:36 +01:00
* load_state_property = " LoadState " ,
* triggered_by_property = " TriggeredBy " ,
* state ;
2012-09-18 20:22:57 +02:00
char _cleanup_free_ * unit_path = NULL , * n = NULL ;
2012-06-13 15:52:27 +02:00
bool print_warning_label = true ;
2012-08-08 01:32:30 +02:00
int r ;
2012-06-13 14:14:13 +02:00
2012-06-22 13:08:48 +02:00
n = unit_name_mangle ( unit_name ) ;
2012-09-18 20:37:15 +02:00
if ( ! n ) {
log_oom ( ) ;
return ;
}
2012-09-18 20:22:57 +02:00
2012-09-18 20:37:15 +02:00
unit_path = unit_dbus_path_from_name ( n ) ;
2012-06-13 18:22:08 +02:00
if ( ! unit_path ) {
2012-09-18 20:37:15 +02:00
log_oom ( ) ;
2012-09-18 20:22:57 +02:00
return ;
2012-06-13 18:22:08 +02:00
}
2012-06-13 14:14:13 +02:00
2013-02-15 16:10:36 +01:00
r = bus_method_call_with_reply (
bus ,
" org.freedesktop.systemd1 " ,
unit_path ,
" org.freedesktop.DBus.Properties " ,
" Get " ,
& reply ,
NULL ,
DBUS_TYPE_STRING , & interface ,
DBUS_TYPE_STRING , & load_state_property ,
DBUS_TYPE_INVALID ) ;
if ( r < 0 )
return ;
if ( ! dbus_message_iter_init ( reply , & iter ) | |
dbus_message_iter_get_arg_type ( & iter ) ! = DBUS_TYPE_VARIANT ) {
log_error ( " Failed to parse reply. " ) ;
return ;
}
dbus_message_iter_recurse ( & iter , & sub ) ;
if ( dbus_message_iter_get_arg_type ( & sub ) ! = DBUS_TYPE_STRING ) {
log_error ( " Failed to parse reply. " ) ;
return ;
}
dbus_message_iter_get_basic ( & sub , & state ) ;
if ( streq ( state , " masked " ) )
return ;
dbus_message_unref ( reply ) ;
reply = NULL ;
2013-01-11 23:59:41 +01:00
r = bus_method_call_with_reply (
2012-08-08 01:32:30 +02:00
bus ,
" org.freedesktop.systemd1 " ,
unit_path ,
" org.freedesktop.DBus.Properties " ,
" Get " ,
& reply ,
NULL ,
DBUS_TYPE_STRING , & interface ,
DBUS_TYPE_STRING , & triggered_by_property ,
DBUS_TYPE_INVALID ) ;
2013-01-11 23:59:41 +01:00
if ( r < 0 )
2012-09-18 20:22:57 +02:00
return ;
2012-06-13 14:14:13 +02:00
if ( ! dbus_message_iter_init ( reply , & iter ) | |
2012-06-13 15:52:27 +02:00
dbus_message_iter_get_arg_type ( & iter ) ! = DBUS_TYPE_VARIANT ) {
2012-08-08 01:32:30 +02:00
log_error ( " Failed to parse reply. " ) ;
2012-09-18 20:22:57 +02:00
return ;
2012-06-13 14:14:13 +02:00
}
dbus_message_iter_recurse ( & iter , & sub ) ;
dbus_message_iter_recurse ( & sub , & iter ) ;
sub = iter ;
while ( dbus_message_iter_get_arg_type ( & sub ) ! = DBUS_TYPE_INVALID ) {
2013-01-11 23:59:41 +01:00
const char * const check_states [ ] = {
" active " ,
" reloading " ,
NULL
} ;
const char * service_trigger ;
2012-06-13 14:14:13 +02:00
if ( dbus_message_iter_get_arg_type ( & sub ) ! = DBUS_TYPE_STRING ) {
2012-08-08 01:32:30 +02:00
log_error ( " Failed to parse reply. " ) ;
2012-09-18 20:22:57 +02:00
return ;
2012-06-13 14:14:13 +02:00
}
dbus_message_iter_get_basic ( & sub , & service_trigger ) ;
2013-01-11 23:59:41 +01:00
r = check_one_unit ( bus , service_trigger , ( char * * ) check_states , true ) ;
2012-06-13 15:52:27 +02:00
if ( r < 0 )
2012-09-18 20:22:57 +02:00
return ;
2013-01-11 23:59:41 +01:00
if ( r > 0 ) {
2012-06-13 14:14:13 +02:00
if ( print_warning_label ) {
2012-06-13 18:27:41 +02:00
log_warning ( " Warning: Stopping %s, but it can still be activated by: " , unit_name ) ;
2012-06-13 15:52:27 +02:00
print_warning_label = false ;
2012-06-13 14:14:13 +02:00
}
2013-01-11 23:59:41 +01:00
2012-06-13 18:27:41 +02:00
log_warning ( " %s " , service_trigger ) ;
2012-06-13 14:14:13 +02:00
}
2012-06-13 18:27:41 +02:00
2012-06-13 17:47:51 +02:00
dbus_message_iter_next ( & sub ) ;
2012-06-13 14:14:13 +02:00
}
}
2010-06-17 22:57:28 +02:00
static int start_unit_one (
DBusConnection * bus ,
const char * method ,
const char * name ,
const char * mode ,
2010-08-31 21:05:54 +02:00
DBusError * error ,
2010-06-17 22:57:28 +02:00
Set * s ) {
2010-06-15 02:51:55 +02:00
2012-10-02 23:07:00 +02:00
_cleanup_dbus_message_unref_ DBusMessage * 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 ( ) ;
r = bus_method_call_with_reply (
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 ,
& reply ,
error ,
2012-09-14 15:11:07 +02:00
DBUS_TYPE_STRING , & n ,
2012-08-08 01:32:30 +02:00
DBUS_TYPE_STRING , & mode ,
DBUS_TYPE_INVALID ) ;
if ( r ) {
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 . */
2010-09-01 02:03:41 +02:00
r = - EADDRNOTAVAIL ;
2012-08-10 17:32:19 +02:00
else
log_error ( " Failed to issue method call: %s " , bus_error_message ( error ) ) ;
2012-09-14 15:11:07 +02:00
2012-09-18 20:37:15 +02:00
return r ;
2010-06-15 02:51:55 +02:00
}
2010-08-31 21:05:54 +02:00
if ( ! dbus_message_get_args ( reply , error ,
2010-07-17 00:57:51 +02:00
DBUS_TYPE_OBJECT_PATH , & path ,
DBUS_TYPE_INVALID ) ) {
2010-08-31 21:05:54 +02:00
log_error ( " Failed to parse reply: %s " , bus_error_message ( error ) ) ;
2012-09-18 20:37:15 +02:00
return - EIO ;
2010-07-17 00:57:51 +02:00
}
2012-09-14 15:11:07 +02:00
if ( need_daemon_reload ( bus , n ) )
log_warning ( " Warning: Unit file of %s changed on disk, 'systemctl %s daemon-reload' recommended. " ,
n , arg_scope = = UNIT_FILE_SYSTEM ? " --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
2012-09-14 15:11:07 +02:00
r = set_put ( s , p ) ;
if ( r < 0 ) {
2013-01-14 02:11:22 +01:00
free ( p ) ;
2010-06-15 02:51:55 +02:00
log_error ( " Failed to add path to set. " ) ;
2012-09-18 20:37:15 +02:00
return r ;
2010-06-15 02:51:55 +02:00
}
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 ;
for ( i = ACTION_INVALID ; i < _ACTION_MAX ; i + + )
if ( action_table [ i ] . verb & & streq ( verb , action_table [ i ] . verb ) )
return i ;
return ACTION_INVALID ;
2010-06-18 04:22:59 +02:00
}
2011-07-25 04:58:02 +02:00
static int start_unit ( DBusConnection * bus , char * * args ) {
2010-06-17 22:57:28 +02:00
2010-08-31 21:05:54 +02:00
int r , ret = 0 ;
2010-06-18 04:22:59 +02:00
const char * method , * mode , * one_name ;
2013-02-14 19:32:19 +01:00
Set _cleanup_set_free_free_ * s = NULL ;
DBusError _cleanup_dbus_error_free_ error ;
2011-07-25 04:58:02 +02:00
char * * name ;
2010-08-31 21:05:54 +02:00
dbus_error_init ( & error ) ;
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 " ) | |
2011-03-01 22:19:08 +01:00
streq ( args [ 0 ] , " condreload " ) | |
2011-03-08 01:44:19 +01:00
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 ) {
2012-09-14 15:11:07 +02:00
ret = enable_wait_for_jobs ( bus ) ;
if ( ret < 0 ) {
2010-08-31 21:05:54 +02:00
log_error ( " Could not watch jobs: %s " , strerror ( - ret ) ) ;
2013-02-14 19:32:19 +01:00
return ret ;
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 ) {
2012-09-14 15:11:07 +02:00
ret = start_unit_one ( bus , method , one_name , mode , & error , s ) ;
if ( ret < 0 )
ret = translate_bus_error_to_exit_status ( ret , & error ) ;
2010-06-18 04:22:59 +02:00
} else {
2012-09-14 15:11:07 +02:00
STRV_FOREACH ( name , args + 1 ) {
r = start_unit_one ( bus , method , * name , mode , & error , s ) ;
if ( r < 0 ) {
2010-09-01 02:03:41 +02:00
ret = translate_bus_error_to_exit_status ( r , & error ) ;
2010-08-31 21:05:54 +02:00
dbus_error_free ( & error ) ;
}
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 ) {
r = wait_for_jobs ( bus , s ) ;
2013-02-14 19:32:19 +01:00
if ( r < 0 )
return r ;
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
2010-08-31 21:05:54 +02:00
return ret ;
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 */
2012-02-29 22:22:15 +01:00
static int reboot_with_logind ( DBusConnection * bus , enum action a ) {
# ifdef HAVE_LOGIND
const char * method ;
dbus_bool_t interactive = true ;
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-01-14 02:11:22 +01:00
return bus_method_call_with_reply (
2012-08-08 01:32:30 +02:00
bus ,
" org.freedesktop.login1 " ,
" /org/freedesktop/login1 " ,
" org.freedesktop.login1.Manager " ,
method ,
NULL ,
NULL ,
DBUS_TYPE_BOOLEAN , & interactive ,
DBUS_TYPE_INVALID ) ;
2012-02-29 22:22:15 +01:00
# else
return - ENOSYS ;
# endif
}
2013-01-11 04:24:05 +01:00
static int check_inhibitors ( DBusConnection * bus , enum action a ) {
# ifdef HAVE_LOGIND
_cleanup_dbus_message_unref_ DBusMessage * reply = NULL ;
DBusMessageIter iter , sub , sub2 ;
int r ;
unsigned c = 0 ;
2013-01-15 03:00:43 +01:00
_cleanup_strv_free_ char * * sessions = NULL ;
char * * s ;
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 ;
r = bus_method_call_with_reply (
bus ,
" org.freedesktop.login1 " ,
" /org/freedesktop/login1 " ,
" org.freedesktop.login1.Manager " ,
" ListInhibitors " ,
& reply ,
NULL ,
DBUS_TYPE_INVALID ) ;
if ( r < 0 )
/* If logind is not around, then there are no inhibitors... */
return 0 ;
if ( ! dbus_message_iter_init ( reply , & iter ) | |
dbus_message_iter_get_arg_type ( & iter ) ! = DBUS_TYPE_ARRAY | |
dbus_message_iter_get_element_type ( & iter ) ! = DBUS_TYPE_STRUCT ) {
log_error ( " Failed to parse reply. " ) ;
return - EIO ;
}
dbus_message_iter_recurse ( & iter , & sub ) ;
while ( dbus_message_iter_get_arg_type ( & sub ) ! = DBUS_TYPE_INVALID ) {
const char * what , * who , * why , * mode ;
uint32_t uid , pid ;
_cleanup_strv_free_ char * * sv = NULL ;
2013-01-15 03:00:43 +01:00
_cleanup_free_ char * comm = NULL , * user = NULL ;
2013-01-11 04:24:05 +01:00
if ( dbus_message_iter_get_arg_type ( & sub ) ! = DBUS_TYPE_STRUCT ) {
log_error ( " Failed to parse reply. " ) ;
return - EIO ;
}
dbus_message_iter_recurse ( & sub , & sub2 ) ;
if ( bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_STRING , & what , true ) < 0 | |
bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_STRING , & who , true ) < 0 | |
bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_STRING , & why , true ) < 0 | |
bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_STRING , & mode , true ) < 0 | |
bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_UINT32 , & uid , true ) < 0 | |
bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_UINT32 , & pid , false ) < 0 ) {
log_error ( " Failed to parse reply. " ) ;
return - EIO ;
}
if ( ! streq ( mode , " block " ) )
goto next ;
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 " ) )
goto next ;
get_process_comm ( pid , & comm ) ;
2013-01-15 03:00:43 +01:00
user = uid_to_name ( uid ) ;
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
c + + ;
next :
dbus_message_iter_next ( & sub ) ;
}
dbus_message_iter_recurse ( & iter , & sub ) ;
2013-01-15 03:00:43 +01:00
/* Check for current sessions */
sd_get_sessions ( & sessions ) ;
STRV_FOREACH ( s , sessions ) {
uid_t uid ;
_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
}
2011-07-25 04:58:02 +02:00
static int start_special ( DBusConnection * 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
}
2012-12-27 17:39:48 +01:00
static int check_unit_active ( DBusConnection * bus , char * * args ) {
2013-01-11 23:59:41 +01:00
const char * const check_states [ ] = {
" active " ,
" reloading " ,
NULL
} ;
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 ;
state = check_one_unit ( bus , * name , ( char * * ) check_states , 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 ;
}
static int check_unit_failed ( DBusConnection * bus , char * * args ) {
2013-01-11 23:59:41 +01:00
const char * const check_states [ ] = {
" failed " ,
NULL
} ;
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 ;
state = check_one_unit ( bus , * name , ( char * * ) check_states , 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
}
2011-07-25 04:58:02 +02:00
static int kill_unit ( DBusConnection * bus , char * * args ) {
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
r = bus_method_call_with_reply (
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 " ,
NULL ,
NULL ,
2013-01-14 02:11:22 +01:00
DBUS_TYPE_STRING , & n ,
2012-08-08 01:32:30 +02:00
DBUS_TYPE_STRING , & arg_kill_who ,
DBUS_TYPE_INT32 , & arg_signal ,
DBUS_TYPE_INVALID ) ;
2013-01-11 23:59:41 +01:00
if ( r < 0 )
2012-08-08 01:32:30 +02:00
return r ;
2010-10-22 16:11:50 +02:00
}
2012-08-08 01:32:30 +02:00
return 0 ;
2010-10-22 16:11:50 +02:00
}
2013-01-12 04:24:12 +01:00
static int set_cgroup ( DBusConnection * bus , char * * args ) {
_cleanup_free_ char * n = NULL ;
2013-02-27 18:50:41 +01:00
const char * method , * runtime ;
char * * argument ;
int r ;
2013-01-12 04:24:12 +01:00
assert ( bus ) ;
assert ( args ) ;
method =
2013-02-27 18:50:41 +01:00
streq ( args [ 0 ] , " set-cgroup " ) ? " SetUnitControlGroup " :
streq ( args [ 0 ] , " unset-cgroup " ) ? " UnsetUnitControlGroup "
: " UnsetUnitControlGroupAttribute " ;
runtime = arg_runtime ? " runtime " : " persistent " ;
2013-01-12 04:24:12 +01:00
n = unit_name_mangle ( args [ 1 ] ) ;
if ( ! n )
return log_oom ( ) ;
2013-02-27 18:50:41 +01:00
STRV_FOREACH ( argument , args + 2 ) {
2013-01-19 01:01:41 +01:00
2013-02-27 18:50:41 +01:00
r = bus_method_call_with_reply (
bus ,
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
method ,
NULL ,
NULL ,
DBUS_TYPE_STRING , & n ,
DBUS_TYPE_STRING , argument ,
DBUS_TYPE_STRING , & runtime ,
DBUS_TYPE_INVALID ) ;
if ( r < 0 )
return r ;
2013-01-12 04:24:12 +01:00
}
return 0 ;
}
static int set_cgroup_attr ( DBusConnection * bus , char * * args ) {
_cleanup_dbus_message_unref_ DBusMessage * m = NULL , * reply = NULL ;
DBusError error ;
2013-02-27 18:50:41 +01:00
DBusMessageIter iter ;
2013-01-12 04:24:12 +01:00
_cleanup_free_ char * n = NULL ;
2013-01-19 01:01:41 +01:00
const char * runtime ;
2013-02-27 18:50:41 +01:00
int r ;
2013-01-12 04:24:12 +01:00
assert ( bus ) ;
assert ( args ) ;
dbus_error_init ( & error ) ;
2013-02-27 18:50:41 +01:00
runtime = arg_runtime ? " runtime " : " persistent " ;
2013-01-12 04:24:12 +01:00
n = unit_name_mangle ( args [ 1 ] ) ;
if ( ! n )
return log_oom ( ) ;
m = dbus_message_new_method_call (
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
2013-02-27 18:50:41 +01:00
" SetUnitControlGroupAttribute " ) ;
2013-01-12 04:24:12 +01:00
if ( ! m )
return log_oom ( ) ;
dbus_message_iter_init_append ( m , & iter ) ;
if ( ! dbus_message_iter_append_basic ( & iter , DBUS_TYPE_STRING , & n ) | |
2013-02-27 18:50:41 +01:00
! dbus_message_iter_append_basic ( & iter , DBUS_TYPE_STRING , & args [ 2 ] ) )
2013-01-12 04:24:12 +01:00
return log_oom ( ) ;
2013-02-27 18:50:41 +01:00
r = bus_append_strv_iter ( & iter , args + 3 ) ;
if ( r < 0 )
return log_oom ( ) ;
2013-01-12 04:24:12 +01:00
2013-02-27 18:50:41 +01:00
if ( ! dbus_message_iter_append_basic ( & iter , DBUS_TYPE_STRING , & runtime ) )
2013-01-19 01:01:41 +01:00
return log_oom ( ) ;
2013-01-12 04:24:12 +01:00
reply = dbus_connection_send_with_reply_and_block ( bus , m , - 1 , & error ) ;
if ( ! reply ) {
log_error ( " Failed to issue method call: %s " , bus_error_message ( & error ) ) ;
dbus_error_free ( & error ) ;
return - EIO ;
}
return 0 ;
}
2013-01-18 01:44:41 +01:00
static int get_cgroup_attr ( DBusConnection * bus , char * * args ) {
2013-03-12 18:22:57 +01:00
_cleanup_dbus_message_unref_ DBusMessage * reply = NULL ;
2013-01-18 01:44:41 +01:00
_cleanup_free_ char * n = NULL ;
2013-02-27 18:50:41 +01:00
char * * argument ;
int r ;
2013-01-18 01:44:41 +01:00
assert ( bus ) ;
assert ( args ) ;
n = unit_name_mangle ( args [ 1 ] ) ;
if ( ! n )
return log_oom ( ) ;
2013-02-27 18:50:41 +01:00
STRV_FOREACH ( argument , args + 2 ) {
_cleanup_strv_free_ char * * list = NULL ;
DBusMessageIter iter ;
char * * a ;
2013-01-18 01:44:41 +01:00
2013-02-27 18:50:41 +01:00
r = bus_method_call_with_reply (
bus ,
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
" GetUnitControlGroupAttribute " ,
& reply ,
NULL ,
DBUS_TYPE_STRING , & n ,
DBUS_TYPE_STRING , argument ,
DBUS_TYPE_INVALID ) ;
if ( r < 0 )
return r ;
2013-01-18 01:44:41 +01:00
2013-03-01 18:29:58 +01:00
if ( ! dbus_message_iter_init ( reply , & iter ) ) {
log_error ( " Failed to initialize iterator. " ) ;
return - EIO ;
}
2013-02-27 18:50:41 +01:00
r = bus_parse_strv_iter ( & iter , & list ) ;
if ( r < 0 ) {
log_error ( " Failed to parse value list. " ) ;
return r ;
}
2013-01-18 01:44:41 +01:00
2013-02-27 18:50:41 +01:00
STRV_FOREACH ( a , list ) {
if ( endswith ( * a , " \n " ) )
fputs ( * a , stdout ) ;
else
puts ( * a ) ;
}
2013-01-18 01:44:41 +01:00
}
return 0 ;
}
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 ) ;
}
static int exec_status_info_deserialize ( DBusMessageIter * sub , ExecStatusInfo * i ) {
2011-04-07 21:35:37 +02:00
uint64_t start_timestamp , exit_timestamp , start_timestamp_monotonic , exit_timestamp_monotonic ;
2010-07-10 15:42:24 +02:00
DBusMessageIter sub2 , sub3 ;
const char * path ;
unsigned n ;
uint32_t pid ;
int32_t code , status ;
2010-07-12 02:25:42 +02:00
dbus_bool_t ignore ;
2010-07-10 15:42:24 +02:00
assert ( i ) ;
assert ( i ) ;
if ( dbus_message_iter_get_arg_type ( sub ) ! = DBUS_TYPE_STRUCT )
return - EIO ;
dbus_message_iter_recurse ( sub , & sub2 ) ;
if ( bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_STRING , & path , true ) < 0 )
return - EIO ;
2013-01-14 02:11:22 +01:00
i - > path = strdup ( path ) ;
if ( ! i - > path )
2010-07-10 15:42:24 +02:00
return - ENOMEM ;
if ( dbus_message_iter_get_arg_type ( & sub2 ) ! = DBUS_TYPE_ARRAY | |
dbus_message_iter_get_element_type ( & sub2 ) ! = DBUS_TYPE_STRING )
return - EIO ;
n = 0 ;
dbus_message_iter_recurse ( & sub2 , & sub3 ) ;
while ( dbus_message_iter_get_arg_type ( & sub3 ) ! = DBUS_TYPE_INVALID ) {
assert ( dbus_message_iter_get_arg_type ( & sub3 ) = = DBUS_TYPE_STRING ) ;
dbus_message_iter_next ( & sub3 ) ;
n + + ;
}
2013-01-14 02:11:22 +01:00
i - > argv = new0 ( char * , n + 1 ) ;
if ( ! i - > argv )
2010-07-10 15:42:24 +02:00
return - ENOMEM ;
n = 0 ;
dbus_message_iter_recurse ( & sub2 , & sub3 ) ;
while ( dbus_message_iter_get_arg_type ( & sub3 ) ! = DBUS_TYPE_INVALID ) {
const char * s ;
assert ( dbus_message_iter_get_arg_type ( & sub3 ) = = DBUS_TYPE_STRING ) ;
dbus_message_iter_get_basic ( & sub3 , & s ) ;
dbus_message_iter_next ( & sub3 ) ;
2013-01-14 02:11:22 +01:00
i - > argv [ n ] = strdup ( s ) ;
if ( ! i - > argv [ n ] )
2010-07-10 15:42:24 +02:00
return - ENOMEM ;
2013-01-14 02:11:22 +01:00
n + + ;
2010-07-10 15:42:24 +02:00
}
if ( ! dbus_message_iter_next ( & sub2 ) | |
2010-07-12 02:25:42 +02:00
bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_BOOLEAN , & ignore , true ) < 0 | |
2010-07-10 15:42:24 +02:00
bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_UINT64 , & start_timestamp , true ) < 0 | |
2011-04-07 21:35:37 +02:00
bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_UINT64 , & start_timestamp_monotonic , true ) < 0 | |
2010-07-10 15:42:24 +02:00
bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_UINT64 , & exit_timestamp , true ) < 0 | |
2011-04-07 21:35:37 +02:00
bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_UINT64 , & exit_timestamp_monotonic , true ) < 0 | |
2010-07-10 15:42:24 +02:00
bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_UINT32 , & pid , true ) < 0 | |
bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_INT32 , & code , true ) < 0 | |
bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_INT32 , & status , false ) < 0 )
return - EIO ;
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 ;
return 0 ;
}
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 ;
2010-07-05 02:40:39 +02:00
const char * default_control_group ;
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 ;
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 ;
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 ;
static void print_status_info ( UnitStatusInfo * i ) {
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
int maxlen = 8 ; /* a value that'll suffice most of the time */
char * * t , * * t2 ;
2010-07-10 15:42:24 +02:00
2010-07-05 02:40:39 +02:00
assert ( i ) ;
2013-04-02 05:09:35 +02:00
STRV_FOREACH_PAIR ( t , t2 , i - > listen )
maxlen = MAX ( maxlen , ( int ) ( sizeof ( " Listen " ) - 1 + strlen ( * t ) ) ) ;
if ( i - > accept )
maxlen = MAX ( maxlen , ( int ) sizeof ( " Accept " ) - 1 ) ;
if ( i - > main_pid > 0 )
maxlen = MAX ( maxlen , ( int ) sizeof ( " Main PID " ) - 1 ) ;
else if ( i - > control_pid > 0 )
maxlen = MAX ( maxlen , ( int ) sizeof ( " Control " ) - 1 ) ;
2010-07-05 02:40:39 +02:00
/* 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-04-02 05:09:35 +02:00
printf ( " %*s: unit currently follows state of %s \n " , maxlen , " Follow " , 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 " ) ) {
2012-01-13 21:56:09 +01:00
on = ansi_highlight_red ( true ) ;
off = ansi_highlight_red ( false ) ;
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-04-02 05:09:35 +02:00
printf ( " %*s: %s%s%s (Reason: %s) \n " ,
maxlen , " Loaded " , 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-04-02 05:09:35 +02:00
printf ( " %*s: %s%s%s (%s; %s) \n " ,
maxlen , " Loaded " , on , strna ( i - > load_state ) , off , path , i - > unit_file_state ) ;
2012-05-22 23:08:24 +02:00
else if ( path )
2013-04-02 05:09:35 +02:00
printf ( " %*s: %s%s%s (%s) \n " ,
maxlen , " Loaded " , on , strna ( i - > load_state ) , off , path ) ;
2010-07-05 02:40:39 +02:00
else
2013-04-02 05:09:35 +02:00
printf ( " %*s: %s%s%s \n " ,
maxlen , " Loaded " , 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 ) ) {
char * * dropin ;
char * dir = NULL ;
bool last = false ;
STRV_FOREACH ( dropin , i - > dropin_paths ) {
if ( ! dir | | last ) {
printf ( " %*s " , maxlen , dir ? " " : " Drop-In: " ) ;
free ( dir ) ;
if ( path_get_parent ( * dropin , & dir ) < 0 ) {
log_oom ( ) ;
return ;
}
2013-04-05 20:19:54 +02:00
printf ( " %s \n %*s %s " , dir , maxlen , " " ,
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 " : " , " ) ;
}
free ( dir ) ;
}
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 " ) ) {
2012-01-13 21:56:09 +01:00
on = ansi_highlight_red ( true ) ;
off = ansi_highlight_red ( false ) ;
2010-08-11 15:19:31 +02:00
} else if ( streq_ptr ( i - > active_state , " active " ) | | streq_ptr ( i - > active_state , " reloading " ) ) {
on = ansi_highlight_green ( true ) ;
off = ansi_highlight_green ( false ) ;
} else
on = off = " " ;
if ( ss )
2013-04-02 05:09:35 +02:00
printf ( " %*s: %s%s (%s)%s " ,
maxlen , " Active " , on , strna ( i - > active_state ) , ss , off ) ;
2010-08-11 15:19:31 +02:00
else
2013-04-02 05:09:35 +02:00
printf ( " %*s: %s%s%s " ,
maxlen , " Active " , 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 ) ;
if ( s1 )
2013-04-02 05:09:35 +02:00
printf ( " %*s start condition failed at %s; %s \n " , maxlen , " " , s2 , s1 ) ;
2011-03-09 23:58:17 +01:00
else if ( s2 )
2013-04-02 05:09:35 +02:00
printf ( " %*s start condition failed at %s \n " , maxlen , " " , s2 ) ;
2011-03-09 23:58:17 +01:00
}
2010-07-05 02:40:39 +02:00
if ( i - > sysfs_path )
2013-04-02 05:09:35 +02:00
printf ( " %*s: %s \n " , maxlen , " Device " , i - > sysfs_path ) ;
2010-10-28 22:11:45 +02:00
if ( i - > where )
2013-04-02 05:09:35 +02:00
printf ( " %*s: %s \n " , maxlen , " Where " , i - > where ) ;
2010-10-28 22:11:45 +02:00
if ( i - > what )
2013-04-02 05:09:35 +02:00
printf ( " %*s: %s \n " , maxlen , " What " , i - > what ) ;
2012-05-21 15:12:18 +02:00
2013-04-02 05:09:35 +02:00
STRV_FOREACH ( t , i - > documentation )
2013-04-05 03:14:32 +02:00
printf ( " %*s %s \n " , maxlen + 1 , 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-04-05 20:12:39 +02:00
printf ( " %*s %s (%s) \n " , maxlen + 1 , 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-04-02 05:09:35 +02:00
printf ( " %*s: %u; Connected: %u \n " , maxlen , " Accepted " , 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 , " " ) ;
printf ( " %*s: %u %s=%s " , maxlen , " Process " , 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 ) {
2012-01-13 21:56:09 +01:00
on = ansi_highlight_red ( true ) ;
off = ansi_highlight_red ( false ) ;
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-04-02 05:09:35 +02:00
printf ( " %*s: %u " , maxlen , " Main PID " , ( 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-04-02 05:09:35 +02:00
printf ( " %*s: %u " , i - > main_pid ? 0 : maxlen , " 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-04-02 05:09:35 +02:00
printf ( " %*s: \" %s \" \n " , maxlen , " Status " , i - > status_text ) ;
2010-07-11 01:20:46 +02:00
2012-12-23 11:56:13 +01:00
if ( i - > default_control_group & &
( i - > main_pid > 0 | | i - > control_pid > 0 | | cg_is_empty_by_spec ( i - > default_control_group , false ) = = 0 ) ) {
2010-07-08 06:08:32 +02:00
unsigned c ;
2013-04-02 05:09:35 +02:00
printf ( " %*s: %s \n " , maxlen , " CGroup " , i - > default_control_group ) ;
2010-07-08 06:08:32 +02:00
2011-03-12 01:03:13 +01:00
if ( arg_transport ! = TRANSPORT_SSH ) {
2012-04-16 18:56:18 +02:00
unsigned k = 0 ;
pid_t extra [ 2 ] ;
2013-04-05 03:14:32 +02:00
char prefix [ maxlen + 4 ] ;
memset ( prefix , ' ' , sizeof ( prefix ) - 1 ) ;
prefix [ sizeof ( prefix ) - 1 ] = ' \0 ' ;
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-04-05 03:14:32 +02:00
show_cgroup_and_extra_by_spec ( i - > default_control_group , prefix ,
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
2012-01-04 04:00:14 +01:00
if ( i - > id & & arg_transport ! = TRANSPORT_SSH ) {
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 ,
arg_scope = = UNIT_FILE_SYSTEM ) ;
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 )
2010-07-20 21:04:32 +02:00
printf ( " \n %sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended. \n " ,
2012-01-13 21:56:09 +01:00
ansi_highlight_red ( true ) ,
ansi_highlight_red ( false ) ,
2011-07-25 04:58:02 +02:00
arg_scope = = UNIT_FILE_SYSTEM ? " --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: " ) ) {
size_t k ;
char * e = NULL ;
2013-02-14 19:32:19 +01:00
char _cleanup_free_ * page = NULL , * section = NULL ;
2012-05-31 04:11:57 +02:00
const char * args [ 4 ] = { " man " , NULL , NULL , NULL } ;
pid_t pid ;
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
}
}
2010-07-05 02:40:39 +02:00
static int status_property ( const char * name , DBusMessageIter * iter , UnitStatusInfo * i ) {
2011-07-08 21:39:10 +02:00
assert ( name ) ;
assert ( iter ) ;
assert ( i ) ;
2010-07-05 02:40:39 +02:00
switch ( dbus_message_iter_get_arg_type ( iter ) ) {
case DBUS_TYPE_STRING : {
const char * s ;
dbus_message_iter_get_basic ( iter , & s ) ;
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 ;
2010-09-21 05:23:12 +02:00
else if ( streq ( name , " DefaultControlGroup " ) )
2010-07-05 02:40:39 +02:00
i - > default_control_group = s ;
else if ( streq ( name , " StatusText " ) )
i - > status_text = s ;
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 ;
}
2010-07-10 00:55:44 +02:00
case DBUS_TYPE_BOOLEAN : {
dbus_bool_t b ;
dbus_message_iter_get_basic ( iter , & b ) ;
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 ;
}
2010-07-05 02:40:39 +02:00
case DBUS_TYPE_UINT32 : {
uint32_t u ;
dbus_message_iter_get_basic ( iter , & u ) ;
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 ;
}
case DBUS_TYPE_INT32 : {
int32_t j ;
dbus_message_iter_get_basic ( iter , & j ) ;
if ( streq ( name , " ExecMainCode " ) )
i - > exit_code = ( int ) j ;
else if ( streq ( name , " ExecMainStatus " ) )
i - > exit_status = ( int ) j ;
break ;
}
case DBUS_TYPE_UINT64 : {
uint64_t u ;
dbus_message_iter_get_basic ( iter , & u ) ;
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
case DBUS_TYPE_ARRAY : {
if ( dbus_message_iter_get_element_type ( iter ) = = DBUS_TYPE_STRUCT & &
startswith ( name , " Exec " ) ) {
DBusMessageIter sub ;
dbus_message_iter_recurse ( iter , & sub ) ;
while ( dbus_message_iter_get_arg_type ( & sub ) = = DBUS_TYPE_STRUCT ) {
ExecStatusInfo * info ;
int r ;
if ( ! ( info = new0 ( ExecStatusInfo , 1 ) ) )
return - ENOMEM ;
2011-01-20 13:24:24 +01:00
if ( ! ( info - > name = strdup ( name ) ) ) {
free ( info ) ;
return - ENOMEM ;
}
2010-07-10 15:42:24 +02:00
if ( ( r = exec_status_info_deserialize ( & sub , info ) ) < 0 ) {
free ( info ) ;
return r ;
}
LIST_PREPEND ( ExecStatusInfo , exec , i - > exec , info ) ;
2012-05-21 15:12:18 +02:00
dbus_message_iter_next ( & sub ) ;
}
2013-04-01 22:09:45 +02:00
} else if ( dbus_message_iter_get_element_type ( iter ) = = DBUS_TYPE_STRUCT & & streq ( name , " Listen " ) ) {
DBusMessageIter sub , sub2 ;
dbus_message_iter_recurse ( iter , & sub ) ;
while ( dbus_message_iter_get_arg_type ( & sub ) = = DBUS_TYPE_STRUCT ) {
const char * type , * path ;
dbus_message_iter_recurse ( & sub , & sub2 ) ;
if ( bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_STRING , & type , true ) > = 0 & &
bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_STRING , & path , false ) > = 0 ) {
2013-04-02 05:09:35 +02:00
int r ;
r = strv_extend ( & i - > listen , type ) ;
if ( r < 0 )
return r ;
r = strv_extend ( & i - > listen , path ) ;
if ( r < 0 )
return r ;
2013-04-01 22:09:45 +02:00
}
dbus_message_iter_next ( & sub ) ;
}
return 0 ;
2013-04-05 19:58:04 +02:00
} else if ( dbus_message_iter_get_element_type ( iter ) = = DBUS_TYPE_STRING & & streq ( name , " DropInPaths " ) ) {
int r = bus_parse_strv_iter ( iter , & i - > dropin_paths ) ;
if ( r < 0 )
return r ;
2012-05-21 15:12:18 +02:00
} else if ( dbus_message_iter_get_element_type ( iter ) = = DBUS_TYPE_STRING & &
streq ( name , " Documentation " ) ) {
DBusMessageIter sub ;
dbus_message_iter_recurse ( iter , & sub ) ;
while ( dbus_message_iter_get_arg_type ( & sub ) = = DBUS_TYPE_STRING ) {
const char * s ;
2013-04-02 05:09:35 +02:00
int r ;
2012-05-21 15:12:18 +02:00
dbus_message_iter_get_basic ( & sub , & s ) ;
2013-04-02 05:09:35 +02:00
r = strv_extend ( & i - > documentation , s ) ;
if ( r < 0 )
return r ;
2012-05-21 15:12:18 +02:00
2010-07-10 15:42:24 +02:00
dbus_message_iter_next ( & sub ) ;
}
}
break ;
}
2011-07-31 18:13:03 +02:00
case DBUS_TYPE_STRUCT : {
if ( streq ( name , " LoadError " ) ) {
DBusMessageIter sub ;
const char * n , * message ;
int r ;
dbus_message_iter_recurse ( iter , & sub ) ;
r = bus_iter_get_basic_and_next ( & sub , DBUS_TYPE_STRING , & n , true ) ;
if ( r < 0 )
return r ;
r = bus_iter_get_basic_and_next ( & sub , DBUS_TYPE_STRING , & message , false ) ;
if ( r < 0 )
return r ;
if ( ! isempty ( message ) )
i - > load_error = message ;
}
break ;
}
2010-07-05 02:40:39 +02:00
}
return 0 ;
}
2010-07-04 03:43:57 +02:00
static int print_property ( const char * name , DBusMessageIter * iter ) {
assert ( name ) ;
assert ( iter ) ;
2010-07-05 02:40:39 +02:00
/* This is a low-level property printer, see
* print_status_info ( ) for the nicer output */
2010-07-23 05:24:05 +02:00
if ( arg_property & & ! strv_find ( arg_property , name ) )
2010-07-04 03:43:57 +02:00
return 0 ;
switch ( dbus_message_iter_get_arg_type ( iter ) ) {
case DBUS_TYPE_STRUCT : {
DBusMessageIter sub ;
dbus_message_iter_recurse ( iter , & sub ) ;
2010-07-04 04:23:48 +02:00
if ( dbus_message_iter_get_arg_type ( & sub ) = = DBUS_TYPE_UINT32 & & streq ( name , " Job " ) ) {
2010-07-04 03:43:57 +02:00
uint32_t u ;
dbus_message_iter_get_basic ( & sub , & u ) ;
if ( u )
printf ( " %s=%u \n " , name , ( unsigned ) u ) ;
else if ( arg_all )
printf ( " %s= \n " , name ) ;
return 0 ;
2010-07-04 04:23:48 +02:00
} else if ( dbus_message_iter_get_arg_type ( & sub ) = = DBUS_TYPE_STRING & & streq ( name , " Unit " ) ) {
2010-07-04 03:43:57 +02:00
const char * s ;
dbus_message_iter_get_basic ( & sub , & s ) ;
if ( arg_all | | s [ 0 ] )
printf ( " %s=%s \n " , name , s ) ;
return 0 ;
2011-07-31 18:13:03 +02:00
} else if ( dbus_message_iter_get_arg_type ( & sub ) = = DBUS_TYPE_STRING & & streq ( name , " LoadError " ) ) {
const char * a = NULL , * b = NULL ;
2011-07-31 18:28:33 +02:00
if ( bus_iter_get_basic_and_next ( & sub , DBUS_TYPE_STRING , & a , true ) > = 0 )
2011-07-31 18:13:03 +02:00
bus_iter_get_basic_and_next ( & sub , DBUS_TYPE_STRING , & b , false ) ;
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 ;
}
case DBUS_TYPE_ARRAY :
2011-07-08 21:39:10 +02:00
if ( dbus_message_iter_get_element_type ( iter ) = = DBUS_TYPE_STRUCT & & streq ( name , " EnvironmentFiles " ) ) {
2011-03-04 03:44:43 +01:00
DBusMessageIter sub , sub2 ;
dbus_message_iter_recurse ( iter , & sub ) ;
while ( dbus_message_iter_get_arg_type ( & sub ) = = DBUS_TYPE_STRUCT ) {
const char * path ;
dbus_bool_t ignore ;
dbus_message_iter_recurse ( & sub , & sub2 ) ;
if ( bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_STRING , & path , true ) > = 0 & &
bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_BOOLEAN , & ignore , false ) > = 0 )
2011-07-30 16:42:05 +02:00
printf ( " EnvironmentFile=%s (ignore_errors=%s) \n " , path , yes_no ( ignore ) ) ;
2011-03-04 03:44:43 +01:00
dbus_message_iter_next ( & sub ) ;
}
return 0 ;
2010-07-04 04:23:48 +02:00
} else if ( dbus_message_iter_get_element_type ( iter ) = = DBUS_TYPE_STRUCT & & streq ( name , " Paths " ) ) {
DBusMessageIter sub , sub2 ;
dbus_message_iter_recurse ( iter , & sub ) ;
2013-04-01 22:09:45 +02:00
2010-07-04 04:23:48 +02:00
while ( dbus_message_iter_get_arg_type ( & sub ) = = DBUS_TYPE_STRUCT ) {
const char * type , * path ;
dbus_message_iter_recurse ( & sub , & sub2 ) ;
if ( bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_STRING , & type , true ) > = 0 & &
bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_STRING , & path , false ) > = 0 )
printf ( " %s=%s \n " , type , path ) ;
dbus_message_iter_next ( & sub ) ;
}
2010-07-04 04:37:03 +02:00
return 0 ;
2010-07-10 15:42:24 +02:00
2013-04-01 22:09:45 +02:00
} else if ( dbus_message_iter_get_element_type ( iter ) = = DBUS_TYPE_STRUCT & & streq ( name , " Listen " ) ) {
DBusMessageIter sub , sub2 ;
dbus_message_iter_recurse ( iter , & sub ) ;
while ( dbus_message_iter_get_arg_type ( & sub ) = = DBUS_TYPE_STRUCT ) {
const char * type , * path ;
dbus_message_iter_recurse ( & sub , & sub2 ) ;
if ( bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_STRING , & type , true ) > = 0 & &
bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_STRING , & path , false ) > = 0 )
printf ( " Listen%s=%s \n " , type , path ) ;
dbus_message_iter_next ( & sub ) ;
}
return 0 ;
2010-07-04 04:37:03 +02:00
} else if ( dbus_message_iter_get_element_type ( iter ) = = DBUS_TYPE_STRUCT & & streq ( name , " Timers " ) ) {
DBusMessageIter sub , sub2 ;
dbus_message_iter_recurse ( iter , & sub ) ;
while ( dbus_message_iter_get_arg_type ( & sub ) = = DBUS_TYPE_STRUCT ) {
const char * base ;
uint64_t value , next_elapse ;
dbus_message_iter_recurse ( & sub , & sub2 ) ;
if ( bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_STRING , & base , true ) > = 0 & &
bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_UINT64 , & value , true ) > = 0 & &
2010-07-04 21:18:06 +02:00
bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_UINT64 , & next_elapse , false ) > = 0 ) {
char timespan1 [ FORMAT_TIMESPAN_MAX ] , timespan2 [ FORMAT_TIMESPAN_MAX ] ;
printf ( " %s={ value=%s ; next_elapse=%s } \n " ,
2010-07-04 20:38:14 +02:00
base ,
2013-04-04 02:56:56 +02:00
format_timespan ( timespan1 , sizeof ( timespan1 ) , value , 0 ) ,
format_timespan ( timespan2 , sizeof ( timespan2 ) , next_elapse , 0 ) ) ;
2010-07-04 21:18:06 +02:00
}
2010-07-04 20:38:14 +02:00
dbus_message_iter_next ( & sub ) ;
}
return 0 ;
2011-08-20 00:42:50 +02:00
} else if ( dbus_message_iter_get_element_type ( iter ) = = DBUS_TYPE_STRUCT & & streq ( name , " ControlGroupAttributes " ) ) {
DBusMessageIter sub , sub2 ;
dbus_message_iter_recurse ( iter , & sub ) ;
while ( dbus_message_iter_get_arg_type ( & sub ) = = DBUS_TYPE_STRUCT ) {
const char * controller , * attr , * value ;
dbus_message_iter_recurse ( & sub , & sub2 ) ;
if ( bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_STRING , & controller , true ) > = 0 & &
bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_STRING , & attr , true ) > = 0 & &
bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_STRING , & value , false ) > = 0 ) {
2013-01-19 01:01:41 +01:00
printf ( " ControlGroupAttributes={ controller=%s ; attribute=%s ; value= \" %s \" } \n " ,
2011-08-20 00:42:50 +02:00
controller ,
attr ,
value ) ;
}
dbus_message_iter_next ( & sub ) ;
}
return 0 ;
2010-07-10 15:42:24 +02:00
} else if ( dbus_message_iter_get_element_type ( iter ) = = DBUS_TYPE_STRUCT & & startswith ( name , " Exec " ) ) {
DBusMessageIter sub ;
2010-07-04 20:38:14 +02:00
dbus_message_iter_recurse ( iter , & sub ) ;
while ( dbus_message_iter_get_arg_type ( & sub ) = = DBUS_TYPE_STRUCT ) {
2010-07-10 15:42:24 +02:00
ExecStatusInfo info ;
2010-07-04 20:38:14 +02:00
2010-07-10 15:42:24 +02:00
zero ( info ) ;
if ( exec_status_info_deserialize ( & sub , & info ) > = 0 ) {
2010-07-04 20:38:14 +02:00
char timestamp1 [ FORMAT_TIMESTAMP_MAX ] , timestamp2 [ FORMAT_TIMESTAMP_MAX ] ;
2013-02-14 19:32:19 +01:00
char _cleanup_free_ * t ;
2010-07-10 15:42:24 +02:00
t = strv_join ( info . argv , " " ) ;
2011-07-30 16:42:05 +02:00
printf ( " %s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s } \n " ,
2010-07-10 15:42:24 +02:00
name ,
strna ( info . path ) ,
strna ( t ) ,
2010-07-12 02:25:42 +02:00
yes_no ( info . ignore ) ,
2010-07-10 15:42:24 +02:00
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 ) ;
2010-07-04 04:37:03 +02:00
dbus_message_iter_next ( & sub ) ;
}
2010-07-04 03:43:57 +02:00
return 0 ;
}
break ;
}
2011-07-08 21:39:10 +02:00
if ( generic_print_property ( name , iter , arg_all ) > 0 )
return 0 ;
2010-07-04 03:43:57 +02:00
if ( arg_all )
printf ( " %s=[unprintable] \n " , name ) ;
return 0 ;
}
2010-11-21 22:40:03 +01:00
static int show_one ( const char * verb , DBusConnection * bus , const char * path , bool show_properties , bool * new_line ) {
2013-03-25 00:45:16 +01:00
DBusMessage _cleanup_free_ * reply = NULL ;
2010-07-04 03:43:57 +02:00
const char * interface = " " ;
int r ;
DBusMessageIter iter , sub , sub2 , sub3 ;
2010-07-05 02:40:39 +02:00
UnitStatusInfo info ;
2010-07-10 15:42:24 +02:00
ExecStatusInfo * p ;
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
2010-07-05 02:40:39 +02:00
zero ( info ) ;
2010-07-04 03:43:57 +02:00
2013-01-14 02:11:22 +01:00
r = bus_method_call_with_reply (
2012-08-08 01:32:30 +02:00
bus ,
" org.freedesktop.systemd1 " ,
path ,
" org.freedesktop.DBus.Properties " ,
" GetAll " ,
& reply ,
NULL ,
DBUS_TYPE_STRING , & interface ,
DBUS_TYPE_INVALID ) ;
2013-01-14 02:11:22 +01:00
if ( r < 0 )
return r ;
2010-07-04 03:43:57 +02:00
if ( ! dbus_message_iter_init ( reply , & iter ) | |
dbus_message_iter_get_arg_type ( & iter ) ! = DBUS_TYPE_ARRAY | |
dbus_message_iter_get_element_type ( & iter ) ! = DBUS_TYPE_DICT_ENTRY ) {
log_error ( " Failed to parse reply. " ) ;
2013-01-14 02:11:22 +01:00
return - EIO ;
2010-07-04 03:43:57 +02:00
}
dbus_message_iter_recurse ( & iter , & sub ) ;
2010-07-05 02:40:39 +02:00
if ( * new_line )
printf ( " \n " ) ;
* new_line = true ;
2010-07-04 03:43:57 +02:00
while ( dbus_message_iter_get_arg_type ( & sub ) ! = DBUS_TYPE_INVALID ) {
const char * name ;
2013-01-14 02:11:22 +01:00
assert ( dbus_message_iter_get_arg_type ( & sub ) = = DBUS_TYPE_DICT_ENTRY ) ;
2010-07-04 03:43:57 +02:00
dbus_message_iter_recurse ( & sub , & sub2 ) ;
2010-07-01 01:06:58 +02:00
2013-01-14 02:11:22 +01:00
if ( bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_STRING , & name , true ) < 0 | |
dbus_message_iter_get_arg_type ( & sub2 ) ! = DBUS_TYPE_VARIANT ) {
2010-07-04 03:43:57 +02:00
log_error ( " Failed to parse reply. " ) ;
2013-01-14 02:11:22 +01:00
return - EIO ;
2010-07-04 03:43:57 +02:00
}
dbus_message_iter_recurse ( & sub2 , & sub3 ) ;
2010-07-05 02:40:39 +02:00
if ( show_properties )
r = print_property ( name , & sub3 ) ;
else
r = status_property ( name , & sub3 , & info ) ;
if ( r < 0 ) {
2010-07-04 03:43:57 +02:00
log_error ( " Failed to parse reply. " ) ;
2013-01-14 02:11:22 +01:00
return - EIO ;
2010-07-04 03:43:57 +02:00
}
dbus_message_iter_next ( & sub ) ;
}
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
print_status_info ( & info ) ;
}
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 " ) & &
streq ( verb , " status " ) )
2010-08-31 21:05:54 +02:00
/* According to LSB: "program not running" */
r = 3 ;
2010-07-05 02:40:39 +02:00
2010-07-10 15:42:24 +02:00
while ( ( p = info . exec ) ) {
LIST_REMOVE ( ExecStatusInfo , exec , info . exec , p ) ;
exec_status_info_free ( p ) ;
}
2010-07-04 03:43:57 +02:00
return r ;
}
2012-05-21 12:54:43 +02:00
static int show_one_by_pid ( const char * verb , DBusConnection * bus , uint32_t pid , bool * new_line ) {
2013-01-14 02:11:22 +01:00
_cleanup_dbus_message_unref_ DBusMessage * reply = NULL ;
2012-05-21 12:54:43 +02:00
const char * path = NULL ;
2013-02-14 19:32:19 +01:00
DBusError _cleanup_dbus_error_free_ error ;
2012-05-21 12:54:43 +02:00
int r ;
dbus_error_init ( & error ) ;
2013-01-14 02:11:22 +01:00
r = bus_method_call_with_reply (
2012-08-08 01:32:30 +02:00
bus ,
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
" GetUnitByPID " ,
& reply ,
NULL ,
DBUS_TYPE_UINT32 , & pid ,
DBUS_TYPE_INVALID ) ;
2013-01-14 02:11:22 +01:00
if ( r < 0 )
2013-02-14 19:32:19 +01:00
return r ;
2012-05-21 12:54:43 +02:00
if ( ! dbus_message_get_args ( reply , & error ,
DBUS_TYPE_OBJECT_PATH , & path ,
DBUS_TYPE_INVALID ) ) {
log_error ( " Failed to parse reply: %s " , bus_error_message ( & error ) ) ;
2013-02-14 19:32:19 +01:00
return - EIO ;
2012-05-21 12:54:43 +02:00
}
r = show_one ( verb , bus , path , false , new_line ) ;
return r ;
}
2013-02-14 22:55:24 +01:00
static int show_all ( const char * verb , DBusConnection * bus , bool show_properties , bool * new_line ) {
_cleanup_dbus_message_unref_ DBusMessage * reply = NULL ;
_cleanup_free_ struct unit_info * unit_infos = NULL ;
unsigned c = 0 ;
const struct unit_info * u ;
int r ;
r = get_unit_list ( bus , & reply , & unit_infos , & c ) ;
if ( r < 0 )
return r ;
for ( u = unit_infos ; u < unit_infos + c ; u + + ) {
char _cleanup_free_ * p = NULL ;
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 ) ;
r = show_one ( verb , bus , p , show_properties , new_line ) ;
if ( r ! = 0 )
return r ;
}
return 0 ;
}
2012-05-21 12:54:43 +02:00
static int show ( DBusConnection * bus , char * * args ) {
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 ;
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 )
2012-05-21 12:54:43 +02:00
return show_one ( args [ 0 ] , bus , " /org/freedesktop/systemd1 " , show_properties , & new_line ) ;
2010-07-04 03:43:57 +02:00
2013-02-14 22:55:24 +01:00
if ( show_status & & strv_length ( args ) < = 1 )
return show_all ( args [ 0 ] , bus , false , & new_line ) ;
2011-07-25 04:58:02 +02:00
STRV_FOREACH ( name , args + 1 ) {
2010-07-04 03:43:57 +02:00
uint32_t id ;
2011-07-25 04:58:02 +02:00
if ( safe_atou32 ( * name , & id ) < 0 ) {
2013-01-14 02:11:22 +01:00
_cleanup_free_ char * p = NULL , * n = NULL ;
2010-08-13 02:07:22 +02:00
/* Interpret as unit name */
2010-07-04 03:43:57 +02:00
2012-06-22 13:08:48 +02:00
n = unit_name_mangle ( * name ) ;
2013-01-14 02:11:22 +01:00
if ( ! n )
return log_oom ( ) ;
p = unit_dbus_path_from_name ( n ) ;
2012-07-25 23:55:59 +02:00
if ( ! p )
return log_oom ( ) ;
2010-07-04 03:43:57 +02:00
2012-05-21 12:54:43 +02:00
r = show_one ( args [ 0 ] , bus , p , show_properties , & new_line ) ;
if ( r ! = 0 )
ret = r ;
2010-07-06 20:14:51 +02:00
2010-08-13 02:07:22 +02:00
} else if ( show_properties ) {
2013-01-14 02:11:22 +01:00
_cleanup_free_ char * p = NULL ;
2010-08-13 02:07:22 +02:00
/* Interpret as job id */
2012-07-25 23:55:59 +02:00
if ( asprintf ( & p , " /org/freedesktop/systemd1/job/%u " , id ) < 0 )
return log_oom ( ) ;
2010-07-04 03:43:57 +02:00
2012-05-21 12:54:43 +02:00
r = show_one ( args [ 0 ] , bus , p , show_properties , & new_line ) ;
if ( r ! = 0 )
ret = r ;
2010-07-04 03:43:57 +02:00
2010-08-13 02:07:22 +02:00
} else {
/* Interpret as PID */
2012-05-21 12:54:43 +02:00
r = show_one_by_pid ( args [ 0 ] , bus , id , & new_line ) ;
if ( r ! = 0 )
ret = r ;
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
}
2011-07-25 04:58:02 +02:00
static int dump ( DBusConnection * bus , char * * args ) {
2013-01-14 02:11:22 +01:00
_cleanup_free_ DBusMessage * reply = NULL ;
2010-06-15 02:51:55 +02:00
DBusError error ;
int r ;
const char * text ;
dbus_error_init ( & error ) ;
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
r = bus_method_call_with_reply (
2012-08-08 01:32:30 +02:00
bus ,
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
" Dump " ,
& reply ,
NULL ,
DBUS_TYPE_INVALID ) ;
2013-01-14 02:11:22 +01:00
if ( r < 0 )
return r ;
2010-06-15 02:51:55 +02:00
if ( ! dbus_message_get_args ( reply , & error ,
DBUS_TYPE_STRING , & text ,
DBUS_TYPE_INVALID ) ) {
2010-08-25 19:49:23 +02:00
log_error ( " Failed to parse reply: %s " , bus_error_message ( & error ) ) ;
2013-01-14 02:11:22 +01:00
dbus_error_free ( & error ) ;
return - EIO ;
2010-06-15 02:51:55 +02:00
}
fputs ( text , stdout ) ;
2013-01-14 02:11:22 +01:00
return 0 ;
2010-06-15 02:51:55 +02:00
}
2011-07-25 04:58:02 +02:00
static int snapshot ( DBusConnection * bus , char * * args ) {
2013-01-10 22:45:45 +01:00
_cleanup_dbus_message_unref_ DBusMessage * reply = NULL ;
2010-06-15 02:51:55 +02:00
DBusError error ;
int r ;
dbus_bool_t cleanup = FALSE ;
DBusMessageIter iter , sub ;
const char
2013-01-14 02:11:57 +01:00
* path , * id ,
2010-06-15 02:51:55 +02:00
* interface = " org.freedesktop.systemd1.Unit " ,
* property = " Id " ;
2013-01-10 22:45:45 +01:00
_cleanup_free_ char * n = NULL ;
2010-06-15 02:51:55 +02:00
dbus_error_init ( & error ) ;
2013-01-14 02:11:57 +01:00
if ( strv_length ( args ) > 1 )
n = snapshot_name_mangle ( args [ 1 ] ) ;
else
n = strdup ( " " ) ;
if ( ! n )
return log_oom ( ) ;
2010-06-15 02:51:55 +02:00
2012-08-08 01:32:30 +02:00
r = bus_method_call_with_reply (
bus ,
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
" CreateSnapshot " ,
& reply ,
NULL ,
2013-01-14 02:11:57 +01:00
DBUS_TYPE_STRING , & n ,
2012-08-08 01:32:30 +02:00
DBUS_TYPE_BOOLEAN , & cleanup ,
DBUS_TYPE_INVALID ) ;
2013-01-10 22:45:45 +01:00
if ( r < 0 )
2013-01-14 02:11:57 +01:00
return r ;
2010-06-15 02:51:55 +02:00
if ( ! dbus_message_get_args ( reply , & error ,
DBUS_TYPE_OBJECT_PATH , & path ,
DBUS_TYPE_INVALID ) ) {
2010-08-25 19:49:23 +02:00
log_error ( " Failed to parse reply: %s " , bus_error_message ( & error ) ) ;
2013-01-14 02:11:57 +01:00
dbus_error_free ( & error ) ;
return - EIO ;
2010-06-15 02:51:55 +02:00
}
dbus_message_unref ( reply ) ;
2013-01-10 22:45:45 +01:00
reply = NULL ;
2012-08-08 01:32:30 +02:00
r = bus_method_call_with_reply (
bus ,
" org.freedesktop.systemd1 " ,
path ,
" org.freedesktop.DBus.Properties " ,
" Get " ,
& reply ,
NULL ,
DBUS_TYPE_STRING , & interface ,
DBUS_TYPE_STRING , & property ,
DBUS_TYPE_INVALID ) ;
2013-01-10 22:45:45 +01:00
if ( r < 0 )
2013-01-14 02:11:57 +01:00
return r ;
2010-06-15 02:51:55 +02:00
if ( ! dbus_message_iter_init ( reply , & iter ) | |
dbus_message_iter_get_arg_type ( & iter ) ! = DBUS_TYPE_VARIANT ) {
log_error ( " Failed to parse reply. " ) ;
2013-01-14 02:11:57 +01:00
return - EIO ;
2010-06-15 02:51:55 +02:00
}
dbus_message_iter_recurse ( & iter , & sub ) ;
if ( dbus_message_iter_get_arg_type ( & sub ) ! = DBUS_TYPE_STRING ) {
log_error ( " Failed to parse reply. " ) ;
2013-01-14 02:11:57 +01:00
return - EIO ;
2010-06-15 02:51:55 +02:00
}
dbus_message_iter_get_basic ( & sub , & id ) ;
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
}
2011-07-25 04:58:02 +02:00
static int delete_snapshot ( DBusConnection * bus , char * * args ) {
char * * name ;
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 ;
int r ;
2010-07-02 03:51:05 +02:00
2013-01-14 02:11:57 +01:00
n = snapshot_name_mangle ( * name ) ;
if ( ! n )
return log_oom ( ) ;
2013-01-10 22:45:45 +01:00
r = bus_method_call_with_reply (
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 " ,
2012-08-08 01:32:30 +02:00
NULL ,
NULL ,
2013-01-14 02:11:57 +01:00
DBUS_TYPE_STRING , & n ,
2012-08-08 01:32:30 +02:00
DBUS_TYPE_INVALID ) ;
2013-01-10 22:45:45 +01:00
if ( r < 0 )
return r ;
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
}
2011-07-25 04:58:02 +02:00
static int daemon_reload ( DBusConnection * bus , char * * args ) {
2010-06-15 02:51:55 +02:00
int r ;
const char * method ;
2012-08-10 17:32:19 +02:00
DBusError error ;
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-01-14 02:11:57 +01:00
r = bus_method_call_with_reply (
2012-08-08 01:32:30 +02:00
bus ,
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
method ,
NULL ,
2012-08-10 17:32:19 +02:00
& error ,
2012-08-08 01:32:30 +02:00
DBUS_TYPE_INVALID ) ;
if ( r = = - ENOENT & & arg_action ! = ACTION_SYSTEMCTL )
/* There's always a fallback possible for
* legacy actions . */
r = - EADDRNOTAVAIL ;
else if ( r = = - ETIMEDOUT & & streq ( method , " Reexecute " ) )
/* On reexecution, we expect a disconnect, not
* a reply */
r = 0 ;
2013-01-14 02:11:57 +01:00
else if ( r < 0 )
2012-08-10 17:32:19 +02:00
log_error ( " Failed to issue method call: %s " , bus_error_message ( & error ) ) ;
2010-06-15 02:51:55 +02:00
2013-01-14 02:11:57 +01:00
dbus_error_free ( & error ) ;
2010-06-15 02:51:55 +02:00
return r ;
}
2011-07-25 04:58:02 +02:00
static int reset_failed ( DBusConnection * bus , char * * args ) {
2012-08-08 01:32:30 +02:00
int r = 0 ;
2013-01-14 02:11:22 +01:00
char * * name ;
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 ( ) ;
r = bus_method_call_with_reply (
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 " ,
NULL ,
NULL ,
2013-01-14 02:11:22 +01:00
DBUS_TYPE_STRING , & n ,
2012-08-08 01:32:30 +02:00
DBUS_TYPE_INVALID ) ;
2013-01-14 02:11:22 +01:00
if ( r < 0 )
return r ;
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
}
2011-07-25 04:58:02 +02:00
static int show_enviroment ( DBusConnection * bus , char * * args ) {
2013-01-14 02:11:22 +01:00
_cleanup_dbus_message_unref_ DBusMessage * reply = NULL ;
2010-06-15 02:51:55 +02:00
DBusMessageIter iter , sub , sub2 ;
int r ;
const char
* interface = " org.freedesktop.systemd1.Manager " ,
* property = " Environment " ;
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
r = bus_method_call_with_reply (
2012-08-08 01:32:30 +02:00
bus ,
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.DBus.Properties " ,
" Get " ,
& reply ,
NULL ,
DBUS_TYPE_STRING , & interface ,
DBUS_TYPE_STRING , & property ,
DBUS_TYPE_INVALID ) ;
2013-01-14 02:11:22 +01:00
if ( r < 0 )
return r ;
2010-06-15 02:51:55 +02:00
if ( ! dbus_message_iter_init ( reply , & iter ) | |
dbus_message_iter_get_arg_type ( & iter ) ! = DBUS_TYPE_VARIANT ) {
log_error ( " Failed to parse reply. " ) ;
2013-01-14 02:11:22 +01:00
return - EIO ;
2010-06-15 02:51:55 +02:00
}
dbus_message_iter_recurse ( & iter , & sub ) ;
if ( dbus_message_iter_get_arg_type ( & sub ) ! = DBUS_TYPE_ARRAY | |
dbus_message_iter_get_element_type ( & sub ) ! = DBUS_TYPE_STRING ) {
log_error ( " Failed to parse reply. " ) ;
2013-01-14 02:11:22 +01:00
return - EIO ;
2010-06-15 02:51:55 +02:00
}
dbus_message_iter_recurse ( & sub , & sub2 ) ;
while ( dbus_message_iter_get_arg_type ( & sub2 ) ! = DBUS_TYPE_INVALID ) {
const char * text ;
if ( dbus_message_iter_get_arg_type ( & sub2 ) ! = DBUS_TYPE_STRING ) {
log_error ( " Failed to parse reply. " ) ;
2013-01-14 02:11:22 +01:00
return - EIO ;
2010-06-15 02:51:55 +02:00
}
dbus_message_iter_get_basic ( & sub2 , & text ) ;
2013-01-14 02:11:22 +01:00
puts ( text ) ;
2010-06-15 02:51:55 +02:00
dbus_message_iter_next ( & sub2 ) ;
}
2013-01-14 02:11:22 +01:00
return 0 ;
2010-06-15 02:51:55 +02:00
}
2012-05-11 17:35:46 +02:00
static int switch_root ( DBusConnection * bus , char * * args ) {
unsigned l ;
2012-11-21 23:22:03 +01:00
const char * root ;
_cleanup_free_ char * init = NULL ;
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-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-01-14 02:11:22 +01:00
return bus_method_call_with_reply (
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 " ,
NULL ,
NULL ,
DBUS_TYPE_STRING , & root ,
DBUS_TYPE_STRING , & init ,
DBUS_TYPE_INVALID ) ;
2012-05-11 17:35:46 +02:00
}
2011-07-25 04:58:02 +02:00
static int set_environment ( DBusConnection * bus , char * * args ) {
2012-10-19 04:53:12 +02:00
_cleanup_dbus_message_unref_ DBusMessage * m = NULL , * reply = NULL ;
2010-06-15 02:51:55 +02:00
DBusError error ;
const char * method ;
2012-10-19 04:53:12 +02:00
DBusMessageIter iter ;
int r ;
assert ( bus ) ;
2013-01-11 23:59:41 +01:00
assert ( args ) ;
2010-06-15 02:51:55 +02:00
dbus_error_init ( & error ) ;
method = streq ( args [ 0 ] , " set-environment " )
? " SetEnvironment "
: " UnsetEnvironment " ;
2012-10-19 04:53:12 +02:00
m = dbus_message_new_method_call (
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
method ) ;
if ( ! m )
return log_oom ( ) ;
2010-06-15 02:51:55 +02:00
dbus_message_iter_init_append ( m , & iter ) ;
2012-10-19 04:53:12 +02:00
r = bus_append_strv_iter ( & iter , args + 1 ) ;
if ( r < 0 )
return log_oom ( ) ;
2010-06-15 02:51:55 +02:00
2012-10-19 04:53:12 +02:00
reply = dbus_connection_send_with_reply_and_block ( bus , m , - 1 , & error ) ;
if ( ! reply ) {
2010-08-25 19:49:23 +02:00
log_error ( " Failed to issue method call: %s " , bus_error_message ( & error ) ) ;
2013-01-14 02:11:22 +01:00
dbus_error_free ( & error ) ;
return - EIO ;
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
}
2011-07-25 04:58:02 +02:00
static int enable_sysv_units ( char * * args ) {
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
const char * verb = args [ 0 ] ;
unsigned f = 1 , t = 1 ;
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
2011-07-25 04:58:02 +02:00
zero ( paths ) ;
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 ;
for ( f = 1 ; args [ f ] ; f + + ) {
const char * name ;
char * p ;
bool found_native = false , found_sysv ;
unsigned c = 1 ;
const char * argv [ 6 ] = { " /sbin/chkconfig " , NULL , NULL , NULL , NULL } ;
char * * k , * l , * q = NULL ;
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 ) {
p = NULL ;
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
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 ) ;
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
p = NULL ;
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
2011-07-25 04:58:02 +02:00
if ( ! found_sysv ) {
free ( p ) ;
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 ) {
free ( q ) ;
free ( 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
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 " ) ;
free ( p ) ;
free ( q ) ;
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
free ( p ) ;
free ( q ) ;
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 :
lookup_paths_free ( & paths ) ;
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
/* Drop all SysV units */
for ( f = 1 , t = 1 ; 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 ;
}
2011-07-25 04:58:02 +02:00
static int enable_unit ( DBusConnection * bus , char * * args ) {
const char * verb = args [ 0 ] ;
UnitFileChange * changes = NULL ;
unsigned n_changes = 0 , i ;
int carries_install_info = - 1 ;
2013-02-14 19:32:19 +01:00
DBusMessage _cleanup_dbus_message_unref_ * m = NULL , * reply = NULL ;
2011-07-25 04:58:02 +02:00
int r ;
2013-02-14 19:32:19 +01:00
DBusError _cleanup_dbus_error_free_ error ;
char _cleanup_strv_free_ * * mangled_names = NULL ;
dbus_error_init ( & error ) ;
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
r = enable_sysv_units ( args ) ;
if ( r < 0 )
return r ;
2010-07-24 00:53:33 +02:00
2012-02-09 10:05:15 +01:00
if ( ! args [ 1 ] )
return 0 ;
2011-07-25 04:58:02 +02:00
if ( ! bus | | avoid_bus ( ) ) {
if ( streq ( verb , " enable " ) ) {
r = unit_file_enable ( arg_scope , arg_runtime , arg_root , args + 1 , arg_force , & changes , & n_changes ) ;
carries_install_info = r ;
} else if ( streq ( verb , " disable " ) )
r = unit_file_disable ( arg_scope , arg_runtime , arg_root , args + 1 , & changes , & n_changes ) ;
else if ( streq ( verb , " reenable " ) ) {
r = unit_file_reenable ( arg_scope , arg_runtime , arg_root , args + 1 , arg_force , & changes , & n_changes ) ;
carries_install_info = r ;
} else if ( streq ( verb , " link " ) )
r = unit_file_link ( arg_scope , arg_runtime , arg_root , args + 1 , arg_force , & changes , & n_changes ) ;
else if ( streq ( verb , " preset " ) ) {
r = unit_file_preset ( arg_scope , arg_runtime , arg_root , args + 1 , arg_force , & changes , & n_changes ) ;
carries_install_info = r ;
} else if ( streq ( verb , " mask " ) )
r = unit_file_mask ( arg_scope , arg_runtime , arg_root , args + 1 , arg_force , & changes , & n_changes ) ;
else if ( streq ( verb , " unmask " ) )
r = unit_file_unmask ( arg_scope , arg_runtime , arg_root , args + 1 , & changes , & n_changes ) ;
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 {
const char * method ;
bool send_force = true , expect_carries_install_info = false ;
dbus_bool_t a , b ;
DBusMessageIter iter , sub , sub2 ;
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 ;
} else
assert_not_reached ( " Unknown verb " ) ;
m = dbus_message_new_method_call (
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
method ) ;
if ( ! m ) {
2012-07-25 23:55:59 +02:00
r = log_oom ( ) ;
2010-07-24 00:53:33 +02:00
goto finish ;
}
2011-07-25 04:58:02 +02:00
dbus_message_iter_init_append ( m , & iter ) ;
2010-07-24 00:53:33 +02:00
2012-09-13 22:35:18 +02:00
r = mangle_names ( args + 1 , & mangled_names ) ;
if ( r < 0 )
goto finish ;
r = bus_append_strv_iter ( & iter , mangled_names ) ;
2011-07-25 04:58:02 +02:00
if ( r < 0 ) {
log_error ( " Failed to append unit files. " ) ;
2010-07-24 00:53:33 +02:00
goto finish ;
}
2011-07-25 04:58:02 +02:00
a = arg_runtime ;
if ( ! dbus_message_iter_append_basic ( & iter , DBUS_TYPE_BOOLEAN , & a ) ) {
log_error ( " Failed to append runtime boolean. " ) ;
2010-07-24 00:53:33 +02:00
r = - ENOMEM ;
goto finish ;
}
2011-07-25 04:58:02 +02:00
if ( send_force ) {
b = arg_force ;
2011-06-24 15:02:57 +02:00
2011-07-25 04:58:02 +02:00
if ( ! dbus_message_iter_append_basic ( & iter , DBUS_TYPE_BOOLEAN , & b ) ) {
log_error ( " Failed to append force boolean. " ) ;
r = - ENOMEM ;
goto finish ;
}
2011-07-22 04:20:02 +02:00
}
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
reply = dbus_connection_send_with_reply_and_block ( bus , m , - 1 , & error ) ;
if ( ! reply ) {
log_error ( " Failed to issue method call: %s " , bus_error_message ( & error ) ) ;
r = - EIO ;
goto finish ;
2010-07-24 00:53:33 +02:00
}
2011-07-25 04:58:02 +02:00
if ( ! dbus_message_iter_init ( reply , & iter ) ) {
log_error ( " Failed to initialize iterator. " ) ;
goto finish ;
}
2011-06-24 15:02:57 +02:00
2011-07-25 04:58:02 +02:00
if ( expect_carries_install_info ) {
r = bus_iter_get_basic_and_next ( & iter , DBUS_TYPE_BOOLEAN , & b , true ) ;
if ( r < 0 ) {
log_error ( " Failed to parse reply. " ) ;
goto finish ;
}
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
carries_install_info = b ;
2010-07-24 00:53:33 +02:00
}
2011-07-25 04:58:02 +02:00
if ( dbus_message_iter_get_arg_type ( & iter ) ! = DBUS_TYPE_ARRAY | |
dbus_message_iter_get_element_type ( & iter ) ! = DBUS_TYPE_STRUCT ) {
log_error ( " Failed to parse reply. " ) ;
r = - EIO ;
goto finish ;
2010-07-24 00:53:33 +02:00
}
2011-07-25 04:58:02 +02:00
dbus_message_iter_recurse ( & iter , & sub ) ;
while ( dbus_message_iter_get_arg_type ( & sub ) ! = DBUS_TYPE_INVALID ) {
const char * type , * path , * source ;
2010-11-21 22:17:04 +01:00
2011-07-25 04:58:02 +02:00
if ( dbus_message_iter_get_arg_type ( & sub ) ! = DBUS_TYPE_STRUCT ) {
log_error ( " Failed to parse reply. " ) ;
r = - EIO ;
goto finish ;
2010-11-21 22:17:04 +01:00
}
2011-07-25 04:58:02 +02:00
dbus_message_iter_recurse ( & sub , & sub2 ) ;
2010-11-21 22:17:04 +01:00
2011-07-25 04:58:02 +02:00
if ( bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_STRING , & type , true ) < 0 | |
bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_STRING , & path , true ) < 0 | |
bus_iter_get_basic_and_next ( & sub2 , DBUS_TYPE_STRING , & source , false ) < 0 ) {
log_error ( " Failed to parse reply. " ) ;
r = - EIO ;
goto finish ;
2010-11-21 22:17:04 +01:00
}
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-06-13 14:19:47 +02:00
2011-07-25 04:58:02 +02:00
dbus_message_iter_next ( & sub ) ;
}
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 ) ;
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
}
2011-07-25 04:58:02 +02:00
static int unit_is_enabled ( DBusConnection * bus , char * * args ) {
2013-02-14 19:32:19 +01:00
DBusError _cleanup_dbus_error_free_ error ;
2010-07-24 00:53:33 +02:00
int r ;
2013-02-14 19:32:19 +01:00
DBusMessage _cleanup_dbus_message_unref_ * reply = NULL ;
2011-07-25 04:58:02 +02:00
bool enabled ;
char * * name ;
2013-03-07 16:09:20 +01:00
char * n ;
2010-07-24 00:53:33 +02:00
dbus_error_init ( & error ) ;
2011-07-25 04:58:02 +02:00
r = enable_sysv_units ( args ) ;
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
2011-07-25 04:58:02 +02:00
STRV_FOREACH ( name , args + 1 ) {
UnitFileState state ;
2010-07-24 00:53:33 +02:00
2013-03-07 16:09:20 +01:00
n = unit_name_mangle ( * name ) ;
if ( ! n )
return log_oom ( ) ;
state = unit_file_get_state ( arg_scope , arg_root , n ) ;
free ( n ) ;
2013-02-14 19:32:19 +01:00
if ( state < 0 )
return state ;
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 {
STRV_FOREACH ( name , args + 1 ) {
const char * s ;
2011-03-04 19:48:38 +01:00
2013-03-07 16:09:20 +01:00
n = unit_name_mangle ( * name ) ;
if ( ! n )
return log_oom ( ) ;
2012-08-08 01:32:30 +02:00
r = bus_method_call_with_reply (
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 " ,
& reply ,
NULL ,
2013-03-07 16:09:20 +01:00
DBUS_TYPE_STRING , & n ,
2012-08-08 01:32:30 +02:00
DBUS_TYPE_INVALID ) ;
2013-03-07 16:09:20 +01:00
free ( n ) ;
2012-08-08 01:32:30 +02:00
if ( r )
2013-02-14 19:32:19 +01:00
return r ;
2010-07-24 00:53:33 +02:00
2011-07-25 04:58:02 +02:00
if ( ! dbus_message_get_args ( reply , & error ,
DBUS_TYPE_STRING , & s ,
DBUS_TYPE_INVALID ) ) {
log_error ( " Failed to parse reply: %s " , bus_error_message ( & error ) ) ;
2013-02-14 19:32:19 +01:00
return - EIO ;
2010-07-24 00:53:33 +02:00
}
2011-07-25 04:58:02 +02:00
dbus_message_unref ( reply ) ;
2012-08-08 01:32:30 +02:00
reply = NULL ;
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-02-14 19:32:19 +01:00
return enabled ? 0 : 1 ;
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 "
" -t --type=TYPE List only units of a particular type \n "
" -p --property=NAME Show only properties by this name \n "
" -a --all Show all units/properties, including dead/empty ones \n "
2011-02-16 20:34:59 +01:00
" --failed Show only failed units \n "
2010-10-22 16:11:50 +02:00
" --full Don't ellipsize unit names on output \n "
" --fail When queueing a new job, fail if conflicting jobs are \n "
" pending \n "
2011-02-16 21:59:31 +01:00
" --ignore-dependencies \n "
" When queueing a new job, ignore all its dependencies \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 "
2011-07-08 21:45:59 +02:00
" -H --host=[USER@]HOST \n "
2011-03-12 01:03:13 +01:00
" Show information for remote host \n "
" -P --privileged Acquire privileges before execution \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
" --system Connect to system manager \n "
" --user Connect to user service manager \n "
" --global Enable/disable unit files globally \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 "
2012-01-04 18:33:36 +01:00
" --runtime Enable unit files only temporarily until next reboot \n "
" -n --lines=INTEGER 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 "
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-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-18 01:44:41 +01:00
" get-cgroup-attr [NAME] [ATTR] ... \n "
" Get control group attrubute \n "
2013-01-12 04:24:12 +01:00
" set-cgroup-attr [NAME] [ATTR] [VALUE] ... \n "
" Set control group attribute \n "
" unset-cgroup-attr [NAME] [ATTR...] \n "
" Unset control group attribute \n "
2013-01-18 01:44:41 +01:00
" set-cgroup [NAME] [CGROUP...] Add unit to a control group \n "
" unset-cgroup [NAME] [CGROUP...] Remove unit from a control group \n "
2013-01-17 21:34:11 +01:00
" load [NAME...] Load one or more units \n "
" list-dependencies [NAME] Recursively show units which are required \n "
" or wanted by this unit \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 "
" 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 "
2011-07-23 04:20:22 +02:00
" is-enabled [NAME...] Check whether unit files are enabled \n \n "
" 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 "
" Status Commands: \n "
2010-06-15 02:51:55 +02:00
" dump Dump server status \n "
2011-07-23 04:20:22 +02:00
" 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 "
2011-07-23 04:20:22 +02:00
" unset-environment [NAME...] Unset one or more environment variables \n \n "
" 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 "
2010-06-18 04:22:59 +02:00
" reboot 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 ) {
2010-06-24 00:08:42 +02:00
printf ( " %s [OPTIONS...] \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 ,
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
puts ( " \n Available unit load states: " ) ;
2013-03-29 22:59:35 +01:00
for ( i = 0 ; i < _UNIT_LOAD_STATE_MAX ; i + + ) {
t = unit_load_state_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-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_FULL ,
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 ,
2012-04-03 14:43:48 +02:00
ARG_FORCE
2010-06-15 02:51:55 +02:00
} ;
static const struct option options [ ] = {
2010-07-24 00:53:33 +02:00
{ " help " , no_argument , NULL , ' h ' } ,
2010-09-06 02:42:49 +02:00
{ " version " , no_argument , NULL , ARG_VERSION } ,
2010-07-24 00:53:33 +02:00
{ " type " , required_argument , NULL , ' t ' } ,
{ " property " , required_argument , NULL , ' p ' } ,
{ " all " , no_argument , NULL , ' a ' } ,
2011-02-16 20:34:59 +01:00
{ " failed " , no_argument , NULL , ARG_FAILED } ,
2010-07-24 00:53:33 +02:00
{ " full " , no_argument , NULL , ARG_FULL } ,
{ " fail " , no_argument , NULL , ARG_FAIL } ,
2013-02-22 11:21:37 +01:00
{ " irreversible " , no_argument , NULL , ARG_IRREVERSIBLE } ,
2011-02-16 21:59:31 +01:00
{ " ignore-dependencies " , no_argument , NULL , ARG_IGNORE_DEPENDENCIES } ,
2013-01-11 04:24:05 +01:00
{ " ignore-inhibitors " , no_argument , NULL , ' i ' } ,
2010-11-15 22:12:41 +01:00
{ " user " , no_argument , NULL , ARG_USER } ,
2010-07-24 00:53:33 +02:00
{ " system " , no_argument , NULL , ARG_SYSTEM } ,
{ " global " , no_argument , NULL , ARG_GLOBAL } ,
{ " no-block " , no_argument , NULL , ARG_NO_BLOCK } ,
2011-09-27 00:48:40 +02:00
{ " no-legend " , no_argument , NULL , ARG_NO_LEGEND } ,
2011-01-02 00:25:57 +01:00
{ " no-pager " , no_argument , NULL , ARG_NO_PAGER } ,
2010-07-24 00:53:33 +02:00
{ " no-wall " , no_argument , NULL , ARG_NO_WALL } ,
{ " quiet " , no_argument , NULL , ' q ' } ,
2011-06-24 15:02:57 +02:00
{ " root " , required_argument , NULL , ARG_ROOT } ,
2012-04-03 14:43:48 +02:00
{ " force " , no_argument , NULL , ARG_FORCE } ,
2010-07-24 00:53:33 +02:00
{ " no-reload " , no_argument , NULL , ARG_NO_RELOAD } ,
2010-10-22 16:11:50 +02:00
{ " kill-who " , required_argument , NULL , ARG_KILL_WHO } ,
{ " signal " , required_argument , NULL , ' s ' } ,
2010-10-26 05:29:39 +02:00
{ " no-ask-password " , no_argument , NULL , ARG_NO_ASK_PASSWORD } ,
2011-03-12 01:03:13 +01:00
{ " host " , required_argument , NULL , ' H ' } ,
{ " privileged " , no_argument , NULL , ' P ' } ,
2011-07-25 04:58:02 +02:00
{ " runtime " , no_argument , NULL , ARG_RUNTIME } ,
2012-01-04 18:33:36 +01:00
{ " lines " , required_argument , NULL , ' n ' } ,
{ " output " , required_argument , NULL , ' o ' } ,
2010-07-24 00:53:33 +02:00
{ NULL , 0 , NULL , 0 }
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-01-11 04:24:05 +01:00
while ( ( c = getopt_long ( argc , argv , " ht:p:aqfs:H:Pn:o:i " , options , NULL ) ) > = 0 ) {
2010-06-15 02:51:55 +02:00
switch ( c ) {
case ' h ' :
2010-06-17 22:57:28 +02:00
systemctl_help ( ) ;
2010-06-15 02:51:55 +02:00
return 0 ;
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
case ' t ' :
2012-11-15 11:54:57 +01:00
if ( streq ( optarg , " help " ) ) {
help_types ( ) ;
return 0 ;
}
2012-07-10 18:03:03 +02:00
if ( unit_type_from_string ( optarg ) > = 0 ) {
arg_type = optarg ;
break ;
2012-06-06 16:56:19 +02:00
}
2012-07-10 18:03:03 +02:00
if ( unit_load_state_from_string ( optarg ) > = 0 ) {
arg_load_state = optarg ;
break ;
}
log_error ( " Unkown unit type or load state '%s'. " ,
optarg ) ;
2012-11-15 11:54:57 +01:00
log_info ( " Use -t help to see a list of allowed values. " ) ;
2012-07-10 18:03:03 +02:00
return - EINVAL ;
2010-07-23 05:24:05 +02:00
case ' p ' : {
2013-02-16 23:20:28 +01:00
char * word , * state ;
size_t size ;
/* Make sure that if the empty property list
was specified , we won ' t show any properties . */
const char * source = isempty ( optarg ) ? " " : optarg ;
FOREACH_WORD_SEPARATOR ( word , size , source , " , " , state ) {
char _cleanup_free_ * prop ;
char * * tmp ;
prop = strndup ( word , size ) ;
if ( ! prop )
return - ENOMEM ;
2010-07-23 05:24:05 +02:00
2013-02-16 23:20:28 +01:00
tmp = strv_append ( arg_property , prop ) ;
if ( ! tmp )
return - ENOMEM ;
2010-07-23 05:24:05 +02:00
2013-02-16 23:20:28 +01:00
strv_free ( arg_property ) ;
arg_property = tmp ;
}
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 ;
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 ;
2010-07-20 20:33:19 +02:00
case ARG_FULL :
arg_full = true ;
break ;
2011-02-16 20:34:59 +01:00
case ARG_FAILED :
arg_failed = true ;
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 ;
2011-03-12 01:03:13 +01:00
case ' P ' :
arg_transport = TRANSPORT_POLKIT ;
break ;
case ' H ' :
arg_transport = TRANSPORT_SSH ;
arg_host = optarg ;
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 ;
2010-06-15 02:51:55 +02:00
case ' ? ' :
return - EINVAL ;
default :
2012-06-22 13:08:48 +02:00
log_error ( " Unknown option code '%c'. " , c ) ;
2010-06-15 02:51:55 +02:00
return - EINVAL ;
}
}
2011-07-25 04:58:02 +02:00
if ( arg_transport ! = TRANSPORT_NORMAL & & 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 } ,
2010-06-17 22:57:28 +02:00
{ NULL , 0 , NULL , 0 }
} ;
int c , runlevel ;
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 :
halt_help ( ) ;
return 0 ;
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 :
2012-06-22 13:08:48 +02:00
log_error ( " Unknown option code '%c'. " , c ) ;
2010-06-17 22:57:28 +02:00
return - EINVAL ;
}
}
if ( optind < argc ) {
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 ;
struct tm tm ;
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 ) ;
zero ( tm ) ;
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 } ,
2010-06-17 22:57:28 +02:00
{ NULL , 0 , NULL , 0 }
} ;
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 :
shutdown_help ( ) ;
return 0 ;
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 :
2012-06-22 13:08:48 +02:00
log_error ( " Unknown option code '%c'. " , c ) ;
2010-06-17 22:57:28 +02:00
return - EINVAL ;
}
}
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 } ,
2010-06-17 22:57:28 +02:00
{ NULL , 0 , NULL , 0 }
} ;
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 :
telinit_help ( ) ;
return 0 ;
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 :
2012-06-22 13:08:48 +02:00
log_error ( " Unknown option code '%c'. " , c ) ;
2010-06-17 22:57:28 +02:00
return - EINVAL ;
}
}
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 } ,
{ NULL , 0 , NULL , 0 }
} ;
int c ;
assert ( argc > = 0 ) ;
assert ( argv ) ;
while ( ( c = getopt_long ( argc , argv , " " , options , NULL ) ) > = 0 ) {
switch ( c ) {
case ARG_HELP :
runlevel_help ( ) ;
return 0 ;
case ' ? ' :
return - EINVAL ;
default :
2012-06-22 13:08:48 +02:00
log_error ( " Unknown option code '%c'. " , c ) ;
2010-06-17 22:57:28 +02:00
return - EINVAL ;
}
}
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 ) {
arg_action = ACTION_INVALID ;
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 ) ;
}
2010-06-18 19:16:14 +02:00
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 ] ;
}
2010-06-19 16:58:59 +02:00
static int talk_upstart ( void ) {
2013-02-14 19:32:19 +01:00
DBusMessage _cleanup_dbus_message_unref_ * m = NULL , * reply = NULL ;
DBusError _cleanup_dbus_error_free_ error ;
2010-06-18 19:16:14 +02:00
int previous , rl , r ;
char
env1_buf [ ] = " RUNLEVEL=X " ,
env2_buf [ ] = " PREVLEVEL=X " ;
char * env1 = env1_buf , * env2 = env2_buf ;
const char * emit = " runlevel " ;
dbus_bool_t b_false = FALSE ;
DBusMessageIter iter , sub ;
2010-06-19 16:58:59 +02:00
DBusConnection * bus ;
2010-06-18 19:16:14 +02:00
dbus_error_init ( & error ) ;
if ( ! ( rl = action_to_runlevel ( ) ) )
return 0 ;
if ( utmp_get_runlevel ( & previous , NULL ) < 0 )
previous = ' N ' ;
2010-07-11 02:22:46 +02:00
if ( ! ( bus = dbus_connection_open_private ( " unix:abstract=/com/ubuntu/upstart " , & error ) ) ) {
2010-06-19 16:58:59 +02:00
if ( dbus_error_has_name ( & error , DBUS_ERROR_NO_SERVER ) ) {
r = 0 ;
goto finish ;
}
2010-08-25 19:49:23 +02:00
log_error ( " Failed to connect to Upstart bus: %s " , bus_error_message ( & error ) ) ;
2010-06-19 16:58:59 +02:00
r = - EIO ;
goto finish ;
}
if ( ( r = bus_check_peercred ( bus ) ) < 0 ) {
log_error ( " Failed to verify owner of bus. " ) ;
goto finish ;
}
2010-06-18 19:16:14 +02:00
if ( ! ( m = dbus_message_new_method_call (
" com.ubuntu.Upstart " ,
" /com/ubuntu/Upstart " ,
" com.ubuntu.Upstart0_6 " ,
" EmitEvent " ) ) ) {
log_error ( " Could not allocate message. " ) ;
2010-06-19 16:58:59 +02:00
r = - ENOMEM ;
goto finish ;
2010-06-18 19:16:14 +02:00
}
dbus_message_iter_init_append ( m , & iter ) ;
env1_buf [ sizeof ( env1_buf ) - 2 ] = rl ;
env2_buf [ sizeof ( env2_buf ) - 2 ] = previous ;
if ( ! dbus_message_iter_append_basic ( & iter , DBUS_TYPE_STRING , & emit ) | |
! dbus_message_iter_open_container ( & iter , DBUS_TYPE_ARRAY , " s " , & sub ) | |
! dbus_message_iter_append_basic ( & sub , DBUS_TYPE_STRING , & env1 ) | |
! dbus_message_iter_append_basic ( & sub , DBUS_TYPE_STRING , & env2 ) | |
! dbus_message_iter_close_container ( & iter , & sub ) | |
! dbus_message_iter_append_basic ( & iter , DBUS_TYPE_BOOLEAN , & b_false ) ) {
log_error ( " Could not append arguments to message. " ) ;
r = - ENOMEM ;
goto finish ;
}
if ( ! ( reply = dbus_connection_send_with_reply_and_block ( bus , m , - 1 , & error ) ) ) {
2012-08-08 02:04:40 +02:00
if ( bus_error_is_no_service ( & error ) ) {
2010-09-01 02:11:52 +02:00
r = - EADDRNOTAVAIL ;
2010-06-18 19:16:14 +02:00
goto finish ;
}
2010-08-25 19:49:23 +02:00
log_error ( " Failed to issue method call: %s " , bus_error_message ( & error ) ) ;
2010-06-18 19:16:14 +02:00
r = - EIO ;
goto finish ;
}
2011-07-14 18:05:33 +02:00
r = 1 ;
2010-06-18 19:16:14 +02:00
finish :
2010-07-11 02:22:46 +02:00
if ( bus ) {
2010-09-02 23:26:04 +02:00
dbus_connection_flush ( bus ) ;
2010-07-11 02:22:46 +02:00
dbus_connection_close ( bus ) ;
2010-06-19 16:58:59 +02:00
dbus_connection_unref ( bus ) ;
2010-07-11 02:22:46 +02:00
}
2010-06-19 16:58:59 +02:00
2010-06-18 19:16:14 +02:00
return r ;
}
static int talk_initctl ( void ) {
2013-03-14 00:40:01 +01:00
struct init_request request = { 0 } ;
int r ;
int _cleanup_close_ fd = - 1 ;
2010-06-18 19:16:14 +02:00
char rl ;
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 ;
request . magic = INIT_MAGIC ;
request . sleeptime = 0 ;
request . cmd = INIT_CMD_RUNLVL ;
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 " ) ;
2010-06-18 04:44:53 +02:00
return errno ? - 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
}
2010-07-24 00:53:33 +02:00
static int systemctl_main ( DBusConnection * bus , int argc , char * argv [ ] , DBusError * 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 ;
2011-07-25 04:58:02 +02:00
int ( * const dispatch ) ( DBusConnection * 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 } ,
2010-07-24 00:53:33 +02:00
{ " list-jobs " , EQUAL , 1 , list_jobs } ,
{ " clear-jobs " , EQUAL , 1 , daemon_reload } ,
{ " load " , MORE , 2 , load_unit } ,
{ " 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 } ,
2013-02-27 18:58:56 +01:00
{ " set-cgroup " , MORE , 3 , set_cgroup } ,
{ " unset-cgroup " , MORE , 3 , set_cgroup } ,
{ " get-cgroup-attr " , MORE , 3 , get_cgroup_attr } ,
{ " set-cgroup-attr " , MORE , 4 , set_cgroup_attr } ,
{ " unset-cgroup-attr " , MORE , 3 , set_cgroup } ,
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
{ " dump " , EQUAL , 1 , dump } ,
{ " snapshot " , LESS , 2 , snapshot } ,
{ " delete " , MORE , 2 , delete_snapshot } ,
{ " daemon-reload " , EQUAL , 1 , daemon_reload } ,
{ " daemon-reexec " , EQUAL , 1 , daemon_reload } ,
{ " show-environment " , EQUAL , 1 , show_enviroment } ,
{ " 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 } ,
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-07-24 00:53:33 +02:00
assert ( error ) ;
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 " ) & &
! streq ( verbs [ i ] . verb , " link " ) ) {
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 ) {
2011-09-29 16:00:29 +02:00
log_error ( " Failed to get D-Bus connection: %s " ,
dbus_error_is_set ( error ) ? error - > message : " No connection to service manager. " ) ;
2011-09-29 15:31:53 +02:00
return - EIO ;
}
} else {
2011-07-25 04:58:02 +02:00
if ( ! bus & & ! avoid_bus ( ) ) {
2011-09-29 16:00:29 +02:00
log_error ( " Failed to get D-Bus connection: %s " ,
dbus_error_is_set ( error ) ? error - > message : " No connection to service manager. " ) ;
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-02-14 19:32:19 +01:00
int _cleanup_close_ fd ;
2010-08-16 15:37:52 +02:00
struct msghdr msghdr ;
2012-04-11 02:04:46 +02:00
struct iovec iovec [ 2 ] ;
2010-08-16 15:37:52 +02:00
union sockaddr_union sockaddr ;
2012-04-11 02:04:46 +02:00
struct sd_shutdown_command c ;
fd = socket ( AF_UNIX , SOCK_DGRAM | SOCK_CLOEXEC , 0 ) ;
if ( fd < 0 )
return - errno ;
2010-08-16 15:37:52 +02:00
zero ( c ) ;
2012-04-11 02:04:46 +02:00
c . usec = t ;
2010-08-16 15:37:52 +02:00
c . mode = mode ;
2011-07-02 23:09:59 +02:00
c . dry_run = dry_run ;
2010-08-16 19:26:27 +02:00
c . warn_wall = warn ;
2010-08-16 15:37:52 +02:00
zero ( sockaddr ) ;
sockaddr . sa . sa_family = AF_UNIX ;
2011-03-25 05:07:20 +01:00
strncpy ( sockaddr . un . sun_path , " /run/systemd/shutdownd " , sizeof ( sockaddr . un . sun_path ) ) ;
2010-08-16 15:37:52 +02:00
zero ( msghdr ) ;
msghdr . msg_name = & sockaddr ;
2011-03-25 05:07:20 +01:00
msghdr . msg_namelen = offsetof ( struct sockaddr_un , sun_path ) + sizeof ( " /run/systemd/shutdownd " ) - 1 ;
2010-08-16 15:37:52 +02:00
2012-04-11 02:04:46 +02:00
zero ( iovec ) ;
iovec [ 0 ] . iov_base = ( char * ) & c ;
iovec [ 0 ] . iov_len = offsetof ( struct sd_shutdown_command , wall_message ) ;
if ( isempty ( message ) )
msghdr . msg_iovlen = 1 ;
else {
iovec [ 1 ] . iov_base = ( char * ) message ;
iovec [ 1 ] . iov_len = strlen ( message ) ;
msghdr . msg_iovlen = 2 ;
}
msghdr . msg_iov = iovec ;
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 ;
}
2010-06-17 22:57:28 +02:00
static int reload_with_fallback ( DBusConnection * bus ) {
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 ;
}
static int start_with_fallback ( DBusConnection * bus ) {
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
}
2010-07-24 02:23:40 +02:00
/* Hmm, talking to systemd via D-Bus didn't work. Then
* let ' s try to talk to Upstart via D - Bus . */
2010-08-11 22:04:22 +02:00
if ( talk_upstart ( ) > 0 )
2010-07-24 02:23:40 +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
/* 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 :
log_info ( " Rebooting. " ) ;
reboot ( RB_AUTOBOOT ) ;
break ;
default :
assert_not_reached ( " Unknown halt action. " ) ;
}
assert_not_reached ( " Uh? This shouldn't happen. " ) ;
}
2010-06-17 22:57:28 +02:00
static int halt_main ( DBusConnection * bus ) {
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-02-14 19:32:19 +01:00
char _cleanup_free_ * m ;
2010-08-16 19:26:27 +02:00
m = strv_join ( arg_wall , " " ) ;
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 [ ] ) {
2010-08-31 21:05:54 +02:00
int r , retval = EXIT_FAILURE ;
2010-06-17 22:57:28 +02:00
DBusConnection * bus = NULL ;
2013-02-14 19:32:19 +01:00
DBusError _cleanup_dbus_error_free_ error ;
2010-06-17 22:57:28 +02:00
dbus_error_init ( & error ) ;
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
2012-04-11 02:04:46 +02:00
r = parse_argv ( argc , argv ) ;
if ( r < 0 )
2010-06-17 22:57:28 +02:00
goto finish ;
else if ( r = = 0 ) {
2010-08-31 21:05:54 +02:00
retval = EXIT_SUCCESS ;
2010-06-15 02:51:55 +02:00
goto finish ;
}
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 ( ) ;
retval = r < 0 ? EXIT_FAILURE : r ;
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. " ) ;
retval = 0 ;
goto finish ;
}
2011-07-25 04:58:02 +02:00
if ( ! avoid_bus ( ) ) {
if ( arg_transport = = TRANSPORT_NORMAL )
bus_connect ( arg_scope = = UNIT_FILE_SYSTEM ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION , & bus , & private_bus , & error ) ;
else if ( arg_transport = = TRANSPORT_POLKIT ) {
bus_connect_system_polkit ( & bus , & error ) ;
private_bus = false ;
} else if ( arg_transport = = TRANSPORT_SSH ) {
bus_connect_system_ssh ( NULL , arg_host , & bus , & error ) ;
private_bus = false ;
} else
assert_not_reached ( " Uh, invalid transport... " ) ;
}
2010-06-17 22:57:28 +02:00
switch ( arg_action ) {
2010-08-31 21:05:54 +02:00
case ACTION_SYSTEMCTL :
r = systemctl_main ( bus , argc , argv , & error ) ;
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 : {
char * m = NULL ;
if ( arg_wall ) {
m = strv_join ( arg_wall , " " ) ;
if ( ! m ) {
retval = EXIT_FAILURE ;
goto finish ;
}
}
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 ) ) ;
free ( m ) ;
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_INVALID :
case ACTION_RUNLEVEL :
2010-06-17 22:57:28 +02:00
default :
assert_not_reached ( " Unknown action " ) ;
}
2010-06-15 02:51:55 +02:00
2010-08-31 21:05:54 +02:00
retval = r < 0 ? EXIT_FAILURE : r ;
2010-06-15 02:51:55 +02:00
finish :
2010-07-11 02:22:46 +02:00
if ( bus ) {
2010-09-02 23:26:04 +02:00
dbus_connection_flush ( bus ) ;
2010-07-11 02:22:46 +02:00
dbus_connection_close ( bus ) ;
2010-06-15 02:51:55 +02:00
dbus_connection_unref ( bus ) ;
2010-07-11 02:22:46 +02:00
}
2010-06-15 02:51:55 +02:00
dbus_shutdown ( ) ;
2010-07-23 05:24:05 +02:00
strv_free ( arg_property ) ;
2011-01-04 00:58:28 +01:00
pager_close ( ) ;
2012-04-11 18:50:16 +02:00
ask_password_agent_close ( ) ;
polkit_agent_close ( ) ;
2011-01-04 00:58:28 +01:00
2010-06-15 02:51:55 +02:00
return retval ;
}