2011-05-24 01:55:06 +04:00
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd .
Copyright 2011 Lennart Poettering
systemd is free software ; you can redistribute it and / or modify it
2012-04-12 02:20:58 +04: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
2011-05-24 01:55:06 +04: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 02:20:58 +04:00
Lesser General Public License for more details .
2011-05-24 01:55:06 +04:00
2012-04-12 02:20:58 +04:00
You should have received a copy of the GNU Lesser General Public License
2011-05-24 01:55:06 +04:00
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
# include <errno.h>
# include <pwd.h>
# include <libudev.h>
# include <fcntl.h>
# include <string.h>
# include <unistd.h>
# include <sys/epoll.h>
2011-05-24 06:20:35 +04:00
# include <sys/ioctl.h>
# include <linux/vt.h>
2012-12-24 01:32:48 +04:00
# include <sys/timerfd.h>
2011-05-24 01:55:06 +04:00
2012-01-05 19:01:58 +04:00
# include <systemd/sd-daemon.h>
2011-05-24 01:55:06 +04:00
# include "logind.h"
# include "dbus-common.h"
# include "dbus-loop.h"
2011-06-29 03:47:55 +04:00
# include "strv.h"
# include "conf-parser.h"
2013-03-15 19:46:35 +04:00
# include "mkdir.h"
2011-05-24 01:55:06 +04:00
Manager * manager_new ( void ) {
Manager * m ;
m = new0 ( Manager , 1 ) ;
if ( ! m )
return NULL ;
m - > console_active_fd = - 1 ;
m - > bus_fd = - 1 ;
2011-06-28 05:21:14 +04:00
m - > udev_seat_fd = - 1 ;
m - > udev_vcsa_fd = - 1 ;
2012-05-30 17:01:51 +04:00
m - > udev_button_fd = - 1 ;
2011-05-24 01:55:06 +04:00
m - > epoll_fd = - 1 ;
2012-09-17 14:39:16 +04:00
m - > reserve_vt_fd = - 1 ;
2012-05-30 17:01:51 +04:00
2011-05-24 01:55:06 +04:00
m - > n_autovts = 6 ;
2012-09-17 14:39:16 +04:00
m - > reserve_vt = 6 ;
2012-05-05 02:34:48 +04:00
m - > inhibit_delay_max = 5 * USEC_PER_SEC ;
2012-09-19 15:10:10 +04:00
m - > handle_power_key = HANDLE_POWEROFF ;
2012-09-21 17:44:14 +04:00
m - > handle_suspend_key = HANDLE_SUSPEND ;
m - > handle_hibernate_key = HANDLE_HIBERNATE ;
2012-09-19 15:10:10 +04:00
m - > handle_lid_switch = HANDLE_SUSPEND ;
m - > lid_switch_ignore_inhibited = true ;
2011-05-24 01:55:06 +04:00
2012-12-24 01:32:48 +04:00
m - > idle_action_fd = - 1 ;
m - > idle_action_usec = 30 * USEC_PER_MINUTE ;
m - > idle_action = HANDLE_IGNORE ;
m - > idle_action_not_before_usec = now ( CLOCK_MONOTONIC ) ;
2011-05-24 01:55:06 +04:00
m - > devices = hashmap_new ( string_hash_func , string_compare_func ) ;
m - > seats = hashmap_new ( string_hash_func , string_compare_func ) ;
m - > sessions = hashmap_new ( string_hash_func , string_compare_func ) ;
m - > users = hashmap_new ( trivial_hash_func , trivial_compare_func ) ;
2012-04-16 18:47:33 +04:00
m - > inhibitors = hashmap_new ( string_hash_func , string_compare_func ) ;
2012-05-30 17:01:51 +04:00
m - > buttons = hashmap_new ( string_hash_func , string_compare_func ) ;
2012-04-16 18:47:33 +04:00
2013-07-02 03:46:30 +04:00
m - > user_units = hashmap_new ( string_hash_func , string_compare_func ) ;
m - > session_units = hashmap_new ( string_hash_func , string_compare_func ) ;
2012-05-31 21:46:42 +04:00
2012-04-16 18:47:33 +04:00
m - > session_fds = hashmap_new ( trivial_hash_func , trivial_compare_func ) ;
m - > inhibitor_fds = hashmap_new ( trivial_hash_func , trivial_compare_func ) ;
2012-05-30 17:01:51 +04:00
m - > button_fds = hashmap_new ( trivial_hash_func , trivial_compare_func ) ;
2011-05-24 01:55:06 +04:00
2013-07-02 05:47:23 +04:00
if ( ! m - > devices | | ! m - > seats | | ! m - > sessions | | ! m - > users | | ! m - > inhibitors | | ! m - > buttons | |
! m - > user_units | | ! m - > session_units | |
2012-05-31 21:46:42 +04:00
! m - > session_fds | | ! m - > inhibitor_fds | | ! m - > button_fds ) {
2011-06-29 04:27:16 +04:00
manager_free ( m ) ;
return NULL ;
}
m - > kill_exclude_users = strv_new ( " root " , NULL ) ;
2013-07-02 03:46:30 +04:00
if ( ! m - > kill_exclude_users ) {
2011-05-24 01:55:06 +04:00
manager_free ( m ) ;
return NULL ;
}
m - > udev = udev_new ( ) ;
if ( ! m - > udev ) {
manager_free ( m ) ;
return NULL ;
}
return m ;
}
void manager_free ( Manager * m ) {
Session * session ;
User * u ;
Device * d ;
Seat * s ;
2012-04-16 18:47:33 +04:00
Inhibitor * i ;
2012-05-30 17:01:51 +04:00
Button * b ;
2011-05-24 01:55:06 +04:00
assert ( m ) ;
while ( ( session = hashmap_first ( m - > sessions ) ) )
session_free ( session ) ;
while ( ( u = hashmap_first ( m - > users ) ) )
user_free ( u ) ;
while ( ( d = hashmap_first ( m - > devices ) ) )
device_free ( d ) ;
while ( ( s = hashmap_first ( m - > seats ) ) )
seat_free ( s ) ;
2012-04-16 18:47:33 +04:00
while ( ( i = hashmap_first ( m - > inhibitors ) ) )
inhibitor_free ( i ) ;
2012-05-30 17:01:51 +04:00
while ( ( b = hashmap_first ( m - > buttons ) ) )
button_free ( b ) ;
2011-05-24 01:55:06 +04:00
hashmap_free ( m - > devices ) ;
hashmap_free ( m - > seats ) ;
2012-04-16 18:47:33 +04:00
hashmap_free ( m - > sessions ) ;
hashmap_free ( m - > users ) ;
hashmap_free ( m - > inhibitors ) ;
2012-05-30 17:01:51 +04:00
hashmap_free ( m - > buttons ) ;
2012-04-16 18:47:33 +04:00
2013-07-02 03:46:30 +04:00
hashmap_free ( m - > user_units ) ;
hashmap_free ( m - > session_units ) ;
2012-05-31 21:46:42 +04:00
2012-04-16 18:47:33 +04:00
hashmap_free ( m - > session_fds ) ;
hashmap_free ( m - > inhibitor_fds ) ;
2012-05-30 17:01:51 +04:00
hashmap_free ( m - > button_fds ) ;
2011-05-24 01:55:06 +04:00
if ( m - > console_active_fd > = 0 )
close_nointr_nofail ( m - > console_active_fd ) ;
2011-06-28 05:21:14 +04:00
if ( m - > udev_seat_monitor )
udev_monitor_unref ( m - > udev_seat_monitor ) ;
if ( m - > udev_vcsa_monitor )
udev_monitor_unref ( m - > udev_vcsa_monitor ) ;
2012-05-30 17:01:51 +04:00
if ( m - > udev_button_monitor )
udev_monitor_unref ( m - > udev_button_monitor ) ;
2011-05-24 01:55:06 +04:00
if ( m - > udev )
udev_unref ( m - > udev ) ;
if ( m - > bus ) {
dbus_connection_flush ( m - > bus ) ;
dbus_connection_close ( m - > bus ) ;
dbus_connection_unref ( m - > bus ) ;
}
if ( m - > bus_fd > = 0 )
close_nointr_nofail ( m - > bus_fd ) ;
if ( m - > epoll_fd > = 0 )
close_nointr_nofail ( m - > epoll_fd ) ;
2012-09-17 14:39:16 +04:00
if ( m - > reserve_vt_fd > = 0 )
close_nointr_nofail ( m - > reserve_vt_fd ) ;
2012-12-24 01:32:48 +04:00
if ( m - > idle_action_fd > = 0 )
close_nointr_nofail ( m - > idle_action_fd ) ;
2011-06-29 03:47:55 +04:00
strv_free ( m - > kill_only_users ) ;
strv_free ( m - > kill_exclude_users ) ;
2013-01-24 07:56:44 +04:00
free ( m - > action_job ) ;
2011-05-24 01:55:06 +04:00
free ( m ) ;
}
int manager_add_device ( Manager * m , const char * sysfs , Device * * _device ) {
Device * d ;
assert ( m ) ;
assert ( sysfs ) ;
d = hashmap_get ( m - > devices , sysfs ) ;
if ( d ) {
if ( _device )
* _device = d ;
return 0 ;
}
d = device_new ( m , sysfs ) ;
if ( ! d )
return - ENOMEM ;
if ( _device )
* _device = d ;
return 0 ;
}
int manager_add_seat ( Manager * m , const char * id , Seat * * _seat ) {
Seat * s ;
assert ( m ) ;
assert ( id ) ;
s = hashmap_get ( m - > seats , id ) ;
if ( s ) {
if ( _seat )
* _seat = s ;
return 0 ;
}
s = seat_new ( m , id ) ;
if ( ! s )
return - ENOMEM ;
if ( _seat )
* _seat = s ;
return 0 ;
}
2013-06-20 05:45:08 +04:00
int manager_add_session ( Manager * m , const char * id , Session * * _session ) {
2011-05-24 01:55:06 +04:00
Session * s ;
assert ( m ) ;
assert ( id ) ;
s = hashmap_get ( m - > sessions , id ) ;
if ( s ) {
if ( _session )
* _session = s ;
return 0 ;
}
2013-06-20 05:45:08 +04:00
s = session_new ( m , id ) ;
2011-05-24 01:55:06 +04:00
if ( ! s )
return - ENOMEM ;
if ( _session )
* _session = s ;
return 0 ;
}
int manager_add_user ( Manager * m , uid_t uid , gid_t gid , const char * name , User * * _user ) {
User * u ;
assert ( m ) ;
assert ( name ) ;
u = hashmap_get ( m - > users , ULONG_TO_PTR ( ( unsigned long ) uid ) ) ;
if ( u ) {
if ( _user )
* _user = u ;
return 0 ;
}
u = user_new ( m , uid , gid , name ) ;
if ( ! u )
return - ENOMEM ;
2011-05-25 02:55:58 +04:00
if ( _user )
* _user = u ;
2011-05-24 01:55:06 +04:00
2011-05-25 02:55:58 +04:00
return 0 ;
2011-05-24 01:55:06 +04:00
}
int manager_add_user_by_name ( Manager * m , const char * name , User * * _user ) {
2011-07-23 03:17:59 +04:00
uid_t uid ;
gid_t gid ;
int r ;
2011-05-24 01:55:06 +04:00
assert ( m ) ;
assert ( name ) ;
2012-07-16 14:34:54 +04:00
r = get_user_creds ( & name , & uid , & gid , NULL , NULL ) ;
2011-07-23 03:17:59 +04:00
if ( r < 0 )
return r ;
2011-05-24 01:55:06 +04:00
2011-07-23 03:17:59 +04:00
return manager_add_user ( m , uid , gid , name , _user ) ;
2011-05-24 01:55:06 +04:00
}
int manager_add_user_by_uid ( Manager * m , uid_t uid , User * * _user ) {
struct passwd * p ;
assert ( m ) ;
errno = 0 ;
p = getpwuid ( uid ) ;
if ( ! p )
return errno ? - errno : - ENOENT ;
return manager_add_user ( m , uid , p - > pw_gid , p - > pw_name , _user ) ;
}
2012-04-16 18:47:33 +04:00
int manager_add_inhibitor ( Manager * m , const char * id , Inhibitor * * _inhibitor ) {
Inhibitor * i ;
assert ( m ) ;
assert ( id ) ;
i = hashmap_get ( m - > inhibitors , id ) ;
if ( i ) {
if ( _inhibitor )
* _inhibitor = i ;
return 0 ;
}
i = inhibitor_new ( m , id ) ;
if ( ! i )
return - ENOMEM ;
if ( _inhibitor )
* _inhibitor = i ;
return 0 ;
}
2012-05-30 17:01:51 +04:00
int manager_add_button ( Manager * m , const char * name , Button * * _button ) {
Button * b ;
assert ( m ) ;
assert ( name ) ;
b = hashmap_get ( m - > buttons , name ) ;
if ( b ) {
if ( _button )
* _button = b ;
return 0 ;
}
b = button_new ( m , name ) ;
if ( ! b )
return - ENOMEM ;
if ( _button )
* _button = b ;
return 0 ;
}
2011-06-28 05:21:14 +04:00
int manager_process_seat_device ( Manager * m , struct udev_device * d ) {
2011-05-24 01:55:06 +04:00
Device * device ;
int r ;
assert ( m ) ;
2011-05-25 02:55:58 +04:00
if ( streq_ptr ( udev_device_get_action ( d ) , " remove " ) ) {
2011-05-24 01:55:06 +04:00
2011-08-31 05:16:01 +04:00
device = hashmap_get ( m - > devices , udev_device_get_syspath ( d ) ) ;
2011-05-25 02:55:58 +04:00
if ( ! device )
return 0 ;
2011-05-24 01:55:06 +04:00
2011-05-25 02:55:58 +04:00
seat_add_to_gc_queue ( device - > seat ) ;
device_free ( device ) ;
} else {
const char * sn ;
Seat * seat ;
2011-05-26 04:21:16 +04:00
sn = udev_device_get_property_value ( d , " ID_SEAT " ) ;
2011-06-29 21:41:07 +04:00
if ( isempty ( sn ) )
2011-05-25 02:55:58 +04:00
sn = " seat0 " ;
2011-05-26 04:21:16 +04:00
if ( ! seat_name_is_valid ( sn ) ) {
log_warning ( " Device with invalid seat name %s found, ignoring. " , sn ) ;
return 0 ;
}
2011-05-25 02:55:58 +04:00
2011-08-31 05:16:01 +04:00
r = manager_add_device ( m , udev_device_get_syspath ( d ) , & device ) ;
2011-05-25 02:55:58 +04:00
if ( r < 0 )
return r ;
r = manager_add_seat ( m , sn , & seat ) ;
if ( r < 0 ) {
if ( ! device - > seat )
device_free ( device ) ;
return r ;
}
device_attach ( device , seat ) ;
2011-05-26 04:21:16 +04:00
seat_start ( seat ) ;
2011-05-25 02:55:58 +04:00
}
2011-05-24 01:55:06 +04:00
return 0 ;
}
2012-05-30 17:01:51 +04:00
int manager_process_button_device ( Manager * m , struct udev_device * d ) {
Button * b ;
int r ;
assert ( m ) ;
if ( streq_ptr ( udev_device_get_action ( d ) , " remove " ) ) {
b = hashmap_get ( m - > buttons , udev_device_get_sysname ( d ) ) ;
if ( ! b )
return 0 ;
button_free ( b ) ;
} else {
const char * sn ;
r = manager_add_button ( m , udev_device_get_sysname ( d ) , & b ) ;
if ( r < 0 )
return r ;
sn = udev_device_get_property_value ( d , " ID_SEAT " ) ;
if ( isempty ( sn ) )
sn = " seat0 " ;
button_set_seat ( b , sn ) ;
button_open ( b ) ;
}
return 0 ;
}
2011-05-24 01:55:06 +04:00
int manager_enumerate_devices ( Manager * m ) {
struct udev_list_entry * item = NULL , * first = NULL ;
struct udev_enumerate * e ;
2011-05-25 02:55:58 +04:00
int r ;
2011-05-24 01:55:06 +04:00
assert ( m ) ;
/* Loads devices from udev and creates seats for them as
* necessary */
e = udev_enumerate_new ( m - > udev ) ;
2011-05-25 02:55:58 +04:00
if ( ! e ) {
r = - ENOMEM ;
2011-05-24 06:20:35 +04:00
goto finish ;
2011-05-25 02:55:58 +04:00
}
2011-05-24 01:55:06 +04:00
2013-02-09 04:25:55 +04:00
r = udev_enumerate_add_match_tag ( e , " master-of-seat " ) ;
2011-05-25 02:55:58 +04:00
if ( r < 0 )
2011-05-24 01:55:06 +04:00
goto finish ;
2011-05-25 02:55:58 +04:00
r = udev_enumerate_scan_devices ( e ) ;
if ( r < 0 )
2011-05-24 01:55:06 +04:00
goto finish ;
first = udev_enumerate_get_list_entry ( e ) ;
udev_list_entry_foreach ( item , first ) {
struct udev_device * d ;
int k ;
d = udev_device_new_from_syspath ( m - > udev , udev_list_entry_get_name ( item ) ) ;
2011-05-25 02:55:58 +04:00
if ( ! d ) {
r = - ENOMEM ;
2011-05-24 01:55:06 +04:00
goto finish ;
2011-05-25 02:55:58 +04:00
}
2011-05-24 01:55:06 +04:00
2011-06-28 05:21:14 +04:00
k = manager_process_seat_device ( m , d ) ;
2011-05-24 01:55:06 +04:00
udev_device_unref ( d ) ;
if ( k < 0 )
r = k ;
}
finish :
if ( e )
udev_enumerate_unref ( e ) ;
return r ;
}
2012-05-30 17:01:51 +04:00
int manager_enumerate_buttons ( Manager * m ) {
struct udev_list_entry * item = NULL , * first = NULL ;
struct udev_enumerate * e ;
int r ;
assert ( m ) ;
/* Loads buttons from udev */
2012-09-19 15:10:10 +04:00
if ( m - > handle_power_key = = HANDLE_IGNORE & &
2012-09-21 17:44:14 +04:00
m - > handle_suspend_key = = HANDLE_IGNORE & &
m - > handle_hibernate_key = = HANDLE_IGNORE & &
2012-09-19 15:10:10 +04:00
m - > handle_lid_switch = = HANDLE_IGNORE )
2012-05-30 23:40:32 +04:00
return 0 ;
2012-05-30 17:01:51 +04:00
e = udev_enumerate_new ( m - > udev ) ;
if ( ! e ) {
r = - ENOMEM ;
goto finish ;
}
r = udev_enumerate_add_match_subsystem ( e , " input " ) ;
if ( r < 0 )
goto finish ;
r = udev_enumerate_add_match_tag ( e , " power-switch " ) ;
if ( r < 0 )
goto finish ;
r = udev_enumerate_scan_devices ( e ) ;
if ( r < 0 )
goto finish ;
first = udev_enumerate_get_list_entry ( e ) ;
udev_list_entry_foreach ( item , first ) {
struct udev_device * d ;
int k ;
d = udev_device_new_from_syspath ( m - > udev , udev_list_entry_get_name ( item ) ) ;
if ( ! d ) {
r = - ENOMEM ;
goto finish ;
}
k = manager_process_button_device ( m , d ) ;
udev_device_unref ( d ) ;
if ( k < 0 )
r = k ;
}
finish :
if ( e )
udev_enumerate_unref ( e ) ;
return r ;
}
2011-05-24 01:55:06 +04:00
int manager_enumerate_seats ( Manager * m ) {
2013-06-20 05:45:08 +04:00
_cleanup_closedir_ DIR * d = NULL ;
2011-05-24 01:55:06 +04:00
struct dirent * de ;
int r = 0 ;
assert ( m ) ;
/* This loads data about seats stored on disk, but does not
* actually create any seats . Removes data of seats that no
* longer exist . */
d = opendir ( " /run/systemd/seats " ) ;
if ( ! d ) {
if ( errno = = ENOENT )
return 0 ;
log_error ( " Failed to open /run/systemd/seats: %m " ) ;
return - errno ;
}
2013-06-20 05:45:08 +04:00
FOREACH_DIRENT ( de , d , return - errno ) {
2011-05-24 01:55:06 +04:00
Seat * s ;
int k ;
if ( ! dirent_is_file ( de ) )
continue ;
s = hashmap_get ( m - > seats , de - > d_name ) ;
if ( ! s ) {
unlinkat ( dirfd ( d ) , de - > d_name , 0 ) ;
continue ;
}
k = seat_load ( s ) ;
if ( k < 0 )
r = k ;
}
2011-05-25 02:55:58 +04:00
return r ;
}
2011-05-24 01:55:06 +04:00
2011-05-25 02:55:58 +04:00
static int manager_enumerate_linger_users ( Manager * m ) {
2013-06-20 05:45:08 +04:00
_cleanup_closedir_ DIR * d = NULL ;
2011-05-25 02:55:58 +04:00
struct dirent * de ;
int r = 0 ;
2013-06-20 05:45:08 +04:00
assert ( m ) ;
2011-05-25 02:55:58 +04:00
d = opendir ( " /var/lib/systemd/linger " ) ;
if ( ! d ) {
if ( errno = = ENOENT )
return 0 ;
log_error ( " Failed to open /var/lib/systemd/linger/: %m " ) ;
return - errno ;
}
2013-06-20 05:45:08 +04:00
FOREACH_DIRENT ( de , d , return - errno ) {
2011-05-25 02:55:58 +04:00
int k ;
if ( ! dirent_is_file ( de ) )
2011-05-24 01:55:06 +04:00
continue ;
2011-05-25 02:55:58 +04:00
k = manager_add_user_by_name ( m , de - > d_name , NULL ) ;
if ( k < 0 ) {
log_notice ( " Couldn't add lingering user %s: %s " , de - > d_name , strerror ( - k ) ) ;
r = k ;
2011-05-24 01:55:06 +04:00
}
}
return r ;
}
int manager_enumerate_users ( Manager * m ) {
2013-06-20 05:45:08 +04:00
_cleanup_closedir_ DIR * d = NULL ;
2011-05-24 01:55:06 +04:00
struct dirent * de ;
2011-05-25 02:55:58 +04:00
int r , k ;
2011-05-24 01:55:06 +04:00
assert ( m ) ;
2013-06-20 05:45:08 +04:00
/* Add lingering users */
2013-06-20 08:51:10 +04:00
r = manager_enumerate_linger_users ( m ) ;
2011-05-25 02:55:58 +04:00
2013-06-20 05:45:08 +04:00
/* Read in user data stored on disk */
2011-05-24 01:55:06 +04:00
d = opendir ( " /run/systemd/users " ) ;
if ( ! d ) {
if ( errno = = ENOENT )
return 0 ;
log_error ( " Failed to open /run/systemd/users: %m " ) ;
return - errno ;
}
2013-06-20 05:45:08 +04:00
FOREACH_DIRENT ( de , d , return - errno ) {
2011-05-24 01:55:06 +04:00
User * u ;
if ( ! dirent_is_file ( de ) )
continue ;
2013-06-20 05:45:08 +04:00
k = manager_add_user_by_name ( m , de - > d_name , & u ) ;
2011-05-24 01:55:06 +04:00
if ( k < 0 ) {
2013-06-20 05:45:08 +04:00
log_error ( " Failed to add user by file name %s: %s " , de - > d_name , strerror ( - k ) ) ;
2011-05-24 01:55:06 +04:00
2013-06-20 05:45:08 +04:00
r = k ;
2011-05-24 01:55:06 +04:00
continue ;
}
2013-06-20 05:45:08 +04:00
user_add_to_gc_queue ( u ) ;
2011-05-24 01:55:06 +04:00
k = user_load ( u ) ;
if ( k < 0 )
r = k ;
}
return r ;
}
2013-06-20 05:45:08 +04:00
int manager_enumerate_sessions ( Manager * m ) {
_cleanup_closedir_ DIR * d = NULL ;
struct dirent * de ;
2011-05-24 01:55:06 +04:00
int r = 0 ;
2013-06-20 05:45:08 +04:00
assert ( m ) ;
/* Read in session data stored on disk */
d = opendir ( " /run/systemd/sessions " ) ;
if ( ! d ) {
if ( errno = = ENOENT )
return 0 ;
log_error ( " Failed to open /run/systemd/sessions: %m " ) ;
return - errno ;
}
FOREACH_DIRENT ( de , d , return - errno ) {
struct Session * s ;
2011-05-24 01:55:06 +04:00
int k ;
2013-06-20 05:45:08 +04:00
if ( ! dirent_is_file ( de ) )
2011-05-25 02:55:58 +04:00
continue ;
2013-09-16 06:26:56 +04:00
if ( ! session_id_valid ( de - > d_name ) ) {
log_warning ( " Invalid session file name '%s', ignoring. " , de - > d_name ) ;
r = - EINVAL ;
continue ;
}
2013-06-20 05:45:08 +04:00
k = manager_add_session ( m , de - > d_name , & s ) ;
2011-05-24 01:55:06 +04:00
if ( k < 0 ) {
2013-06-20 05:45:08 +04:00
log_error ( " Failed to add session by file name %s: %s " , de - > d_name , strerror ( - k ) ) ;
2011-05-24 01:55:06 +04:00
r = k ;
continue ;
}
2013-06-20 05:45:08 +04:00
session_add_to_gc_queue ( s ) ;
2011-05-24 01:55:06 +04:00
2013-06-20 05:45:08 +04:00
k = session_load ( s ) ;
2011-05-24 01:55:06 +04:00
if ( k < 0 )
r = k ;
}
return r ;
}
2013-06-20 05:45:08 +04:00
int manager_enumerate_inhibitors ( Manager * m ) {
_cleanup_closedir_ DIR * d = NULL ;
2011-05-24 01:55:06 +04:00
struct dirent * de ;
int r = 0 ;
assert ( m ) ;
2013-06-20 05:45:08 +04:00
d = opendir ( " /run/systemd/inhibit " ) ;
2011-05-24 01:55:06 +04:00
if ( ! d ) {
if ( errno = = ENOENT )
return 0 ;
2013-06-20 05:45:08 +04:00
log_error ( " Failed to open /run/systemd/inhibit: %m " ) ;
2011-05-24 01:55:06 +04:00
return - errno ;
}
2013-06-20 05:45:08 +04:00
FOREACH_DIRENT ( de , d , return - errno ) {
2011-05-24 01:55:06 +04:00
int k ;
2013-06-20 05:45:08 +04:00
Inhibitor * i ;
2011-05-24 01:55:06 +04:00
if ( ! dirent_is_file ( de ) )
continue ;
2013-06-20 05:45:08 +04:00
k = manager_add_inhibitor ( m , de - > d_name , & i ) ;
if ( k < 0 ) {
log_notice ( " Couldn't add inhibitor %s: %s " , de - > d_name , strerror ( - k ) ) ;
r = k ;
2011-05-24 01:55:06 +04:00
continue ;
}
2013-06-20 05:45:08 +04:00
k = inhibitor_load ( i ) ;
2011-05-24 01:55:06 +04:00
if ( k < 0 )
r = k ;
}
return r ;
}
2011-06-28 05:21:14 +04:00
int manager_dispatch_seat_udev ( Manager * m ) {
2011-05-24 01:55:06 +04:00
struct udev_device * d ;
int r ;
assert ( m ) ;
2011-06-28 05:21:14 +04:00
d = udev_monitor_receive_device ( m - > udev_seat_monitor ) ;
2011-05-24 01:55:06 +04:00
if ( ! d )
return - ENOMEM ;
2011-06-28 05:21:14 +04:00
r = manager_process_seat_device ( m , d ) ;
udev_device_unref ( d ) ;
return r ;
}
int manager_dispatch_vcsa_udev ( Manager * m ) {
struct udev_device * d ;
int r = 0 ;
const char * name ;
assert ( m ) ;
d = udev_monitor_receive_device ( m - > udev_vcsa_monitor ) ;
if ( ! d )
return - ENOMEM ;
name = udev_device_get_sysname ( d ) ;
/* Whenever a VCSA device is removed try to reallocate our
* VTs , to make sure our auto VTs never go away . */
if ( name & & startswith ( name , " vcsa " ) & & streq_ptr ( udev_device_get_action ( d ) , " remove " ) )
r = seat_preallocate_vts ( m - > vtconsole ) ;
2011-05-24 01:55:06 +04:00
udev_device_unref ( d ) ;
return r ;
}
2012-05-30 17:01:51 +04:00
int manager_dispatch_button_udev ( Manager * m ) {
struct udev_device * d ;
int r ;
assert ( m ) ;
d = udev_monitor_receive_device ( m - > udev_button_monitor ) ;
if ( ! d )
return - ENOMEM ;
r = manager_process_button_device ( m , d ) ;
udev_device_unref ( d ) ;
return r ;
}
2011-05-24 01:55:06 +04:00
int manager_dispatch_console ( Manager * m ) {
assert ( m ) ;
if ( m - > vtconsole )
2011-05-25 02:55:58 +04:00
seat_read_active_vt ( m - > vtconsole ) ;
2011-05-24 01:55:06 +04:00
return 0 ;
}
2011-05-24 06:20:35 +04:00
static int vt_is_busy ( int vtnr ) {
struct vt_stat vt_stat ;
int r = 0 , fd ;
assert ( vtnr > = 1 ) ;
2011-06-28 02:26:10 +04:00
/* We explicitly open /dev/tty1 here instead of /dev/tty0. If
* we ' d open the latter we ' d open the foreground tty which
* hence would be unconditionally busy . By opening / dev / tty1
* we avoid this . Since tty1 is special and needs to be an
* explicitly loaded getty or DM this is safe . */
fd = open_terminal ( " /dev/tty1 " , O_RDWR | O_NOCTTY | O_CLOEXEC ) ;
2011-05-24 06:20:35 +04:00
if ( fd < 0 )
return - errno ;
if ( ioctl ( fd , VT_GETSTATE , & vt_stat ) < 0 )
r = - errno ;
else
r = ! ! ( vt_stat . v_state & ( 1 < < vtnr ) ) ;
close_nointr_nofail ( fd ) ;
return r ;
}
2011-05-24 01:55:06 +04:00
int manager_spawn_autovt ( Manager * m , int vtnr ) {
2011-05-24 06:20:35 +04:00
int r ;
2011-06-28 02:26:10 +04:00
char * name = NULL ;
const char * mode = " fail " ;
2011-05-24 06:20:35 +04:00
2011-05-24 01:55:06 +04:00
assert ( m ) ;
2011-06-28 05:21:14 +04:00
assert ( vtnr > = 1 ) ;
2011-05-24 01:55:06 +04:00
2012-09-17 14:39:16 +04:00
if ( ( unsigned ) vtnr > m - > n_autovts & &
( unsigned ) vtnr ! = m - > reserve_vt )
2011-06-28 05:05:33 +04:00
return 0 ;
2012-09-17 14:39:16 +04:00
if ( ( unsigned ) vtnr ! = m - > reserve_vt ) {
/* If this is the reserved TTY, we'll start the getty
* on it in any case , but otherwise only if it is not
* busy . */
r = vt_is_busy ( vtnr ) ;
if ( r < 0 )
return r ;
else if ( r > 0 )
return - EBUSY ;
}
2011-05-24 06:20:35 +04:00
2011-06-28 20:16:00 +04:00
if ( asprintf ( & name , " autovt@tty%i.service " , vtnr ) < 0 ) {
2011-06-28 02:26:10 +04:00
log_error ( " Could not allocate service name. " ) ;
r = - ENOMEM ;
goto finish ;
}
2012-09-17 14:39:16 +04:00
2012-08-08 19:20:04 +04:00
r = bus_method_call_with_reply (
m - > bus ,
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
" StartUnit " ,
NULL ,
NULL ,
DBUS_TYPE_STRING , & name ,
DBUS_TYPE_STRING , & mode ,
DBUS_TYPE_INVALID ) ;
2011-06-28 02:26:10 +04:00
finish :
free ( name ) ;
return r ;
2011-05-24 01:55:06 +04:00
}
2012-09-17 14:39:16 +04:00
static int manager_reserve_vt ( Manager * m ) {
_cleanup_free_ char * p = NULL ;
assert ( m ) ;
if ( m - > reserve_vt < = 0 )
return 0 ;
if ( asprintf ( & p , " /dev/tty%u " , m - > reserve_vt ) < 0 )
return log_oom ( ) ;
m - > reserve_vt_fd = open ( p , O_RDWR | O_NOCTTY | O_CLOEXEC | O_NONBLOCK ) ;
if ( m - > reserve_vt_fd < 0 ) {
2012-09-17 21:11:48 +04:00
/* Don't complain on VT-less systems */
if ( errno ! = ENOENT )
log_warning ( " Failed to pin reserved VT: %m " ) ;
2012-09-17 14:39:16 +04:00
return - errno ;
}
return 0 ;
}
2012-02-01 02:51:16 +04:00
int manager_get_session_by_pid ( Manager * m , pid_t pid , Session * * session ) {
2013-07-02 03:46:30 +04:00
_cleanup_free_ char * unit = NULL ;
Session * s ;
2012-02-01 02:51:16 +04:00
int r ;
assert ( m ) ;
assert ( pid > = 1 ) ;
assert ( session ) ;
2011-06-24 22:41:56 +04:00
2013-07-02 03:46:30 +04:00
r = cg_pid_get_unit ( pid , & unit ) ;
2012-02-01 02:51:16 +04:00
if ( r < 0 )
return r ;
2013-07-02 03:46:30 +04:00
s = hashmap_get ( m - > session_units , unit ) ;
if ( ! s )
return 0 ;
* session = s ;
return 1 ;
2012-02-01 02:51:16 +04:00
}
2013-06-20 05:45:08 +04:00
int manager_get_user_by_pid ( Manager * m , pid_t pid , User * * user ) {
2013-07-02 03:46:30 +04:00
_cleanup_free_ char * unit = NULL ;
User * u ;
2013-06-20 05:45:08 +04:00
int r ;
assert ( m ) ;
assert ( pid > = 1 ) ;
assert ( user ) ;
2013-07-02 03:46:30 +04:00
r = cg_pid_get_slice ( pid , & unit ) ;
2013-06-20 05:45:08 +04:00
if ( r < 0 )
return r ;
2013-07-02 03:46:30 +04:00
u = hashmap_get ( m - > user_units , unit ) ;
if ( ! u )
return 0 ;
* user = u ;
return 1 ;
2013-06-20 05:45:08 +04:00
}
2012-05-30 17:01:51 +04:00
static void manager_dispatch_other ( Manager * m , int fd ) {
2011-06-25 01:25:28 +04:00
Session * s ;
2012-04-16 18:47:33 +04:00
Inhibitor * i ;
2012-05-30 17:01:51 +04:00
Button * b ;
2011-06-25 01:25:28 +04:00
assert_se ( m ) ;
assert_se ( fd > = 0 ) ;
2012-04-16 18:47:33 +04:00
s = hashmap_get ( m - > session_fds , INT_TO_PTR ( fd + 1 ) ) ;
if ( s ) {
assert ( s - > fifo_fd = = fd ) ;
session_remove_fifo ( s ) ;
session_stop ( s ) ;
return ;
}
2011-06-25 01:25:28 +04:00
2012-04-16 18:47:33 +04:00
i = hashmap_get ( m - > inhibitor_fds , INT_TO_PTR ( fd + 1 ) ) ;
if ( i ) {
assert ( i - > fifo_fd = = fd ) ;
inhibitor_stop ( i ) ;
inhibitor_free ( i ) ;
return ;
}
2012-05-30 17:01:51 +04:00
b = hashmap_get ( m - > button_fds , INT_TO_PTR ( fd + 1 ) ) ;
if ( b ) {
assert ( b - > fd = = fd ) ;
button_process ( b ) ;
return ;
}
assert_not_reached ( " Got event for unknown fd " ) ;
2011-06-25 01:25:28 +04:00
}
2011-05-24 01:55:06 +04:00
static int manager_connect_bus ( Manager * m ) {
DBusError error ;
int r ;
2013-03-25 03:59:00 +04:00
struct epoll_event ev = {
. events = EPOLLIN ,
. data . u32 = FD_BUS ,
} ;
2011-05-24 01:55:06 +04:00
assert ( m ) ;
assert ( ! m - > bus ) ;
assert ( m - > bus_fd < 0 ) ;
dbus_error_init ( & error ) ;
m - > bus = dbus_bus_get_private ( DBUS_BUS_SYSTEM , & error ) ;
if ( ! m - > bus ) {
2011-06-28 01:15:30 +04:00
log_error ( " Failed to get system D-Bus connection: %s " , bus_error_message ( & error ) ) ;
2011-05-24 01:55:06 +04:00
r = - ECONNREFUSED ;
goto fail ;
}
2011-05-26 04:21:16 +04:00
if ( ! dbus_connection_register_object_path ( m - > bus , " /org/freedesktop/login1 " , & bus_manager_vtable , m ) | |
! dbus_connection_register_fallback ( m - > bus , " /org/freedesktop/login1/seat " , & bus_seat_vtable , m ) | |
! dbus_connection_register_fallback ( m - > bus , " /org/freedesktop/login1/session " , & bus_session_vtable , m ) | |
! dbus_connection_register_fallback ( m - > bus , " /org/freedesktop/login1/user " , & bus_user_vtable , m ) | |
2011-06-24 22:41:56 +04:00
! dbus_connection_add_filter ( m - > bus , bus_message_filter , m , NULL ) ) {
2012-07-26 01:55:59 +04:00
r = log_oom ( ) ;
2011-05-24 01:55:06 +04:00
goto fail ;
}
dbus_bus_add_match ( m - > bus ,
" type='signal', "
2013-07-02 03:46:30 +04:00
" sender='org.freedesktop.systemd1', "
" interface='org.freedesktop.systemd1.Manager', "
" member='JobRemoved', "
" path='/org/freedesktop/systemd1' " ,
& error ) ;
if ( dbus_error_is_set ( & error ) ) {
log_error ( " Failed to add match for JobRemoved: %s " , bus_error_message ( & error ) ) ;
dbus_error_free ( & error ) ;
2013-07-03 17:12:58 +04:00
}
dbus_bus_add_match ( m - > bus ,
" type='signal', "
" sender='org.freedesktop.systemd1', "
" interface='org.freedesktop.systemd1.Manager', "
" member='UnitRemoved', "
" path='/org/freedesktop/systemd1' " ,
& error ) ;
if ( dbus_error_is_set ( & error ) ) {
log_error ( " Failed to add match for UnitRemoved: %s " , bus_error_message ( & error ) ) ;
dbus_error_free ( & error ) ;
2013-07-02 03:46:30 +04:00
}
dbus_bus_add_match ( m - > bus ,
" type='signal', "
" sender='org.freedesktop.systemd1', "
" interface='org.freedesktop.DBus.Properties', "
" member='PropertiesChanged' " ,
2011-05-24 01:55:06 +04:00
& error ) ;
if ( dbus_error_is_set ( & error ) ) {
2013-07-02 03:46:30 +04:00
log_error ( " Failed to add match for PropertiesChanged: %s " , bus_error_message ( & error ) ) ;
dbus_error_free ( & error ) ;
}
2013-07-11 01:31:40 +04:00
dbus_bus_add_match ( m - > bus ,
" type='signal', "
" sender='org.freedesktop.systemd1', "
" interface='org.freedesktop.systemd1.Manager', "
" member='Reloading', "
" path='/org/freedesktop/systemd1' " ,
& error ) ;
if ( dbus_error_is_set ( & error ) ) {
log_error ( " Failed to add match for Reloading: %s " , bus_error_message ( & error ) ) ;
dbus_error_free ( & error ) ;
}
2013-07-02 03:46:30 +04:00
r = bus_method_call_with_reply (
m - > bus ,
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
" Subscribe " ,
NULL ,
& error ,
DBUS_TYPE_INVALID ) ;
if ( r < 0 ) {
log_error ( " Failed to enable subscription: %s " , bus_error ( & error , r ) ) ;
dbus_error_free ( & error ) ;
2011-05-24 01:55:06 +04:00
}
2011-06-28 01:07:28 +04:00
r = dbus_bus_request_name ( m - > bus , " org.freedesktop.login1 " , DBUS_NAME_FLAG_DO_NOT_QUEUE , & error ) ;
if ( dbus_error_is_set ( & error ) ) {
log_error ( " Failed to register name on bus: %s " , bus_error_message ( & error ) ) ;
r = - EIO ;
goto fail ;
}
if ( r ! = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER ) {
log_error ( " Failed to acquire name. " ) ;
2011-05-24 01:55:06 +04:00
r = - EEXIST ;
goto fail ;
}
m - > bus_fd = bus_loop_open ( m - > bus ) ;
if ( m - > bus_fd < 0 ) {
r = m - > bus_fd ;
goto fail ;
}
if ( epoll_ctl ( m - > epoll_fd , EPOLL_CTL_ADD , m - > bus_fd , & ev ) < 0 )
goto fail ;
return 0 ;
fail :
dbus_error_free ( & error ) ;
return r ;
}
static int manager_connect_console ( Manager * m ) {
2013-03-25 03:59:00 +04:00
struct epoll_event ev = {
. events = 0 ,
. data . u32 = FD_CONSOLE ,
} ;
2011-05-24 01:55:06 +04:00
assert ( m ) ;
assert ( m - > console_active_fd < 0 ) ;
2012-04-13 19:54:33 +04:00
/* On certain architectures (S390 and Xen, and containers),
/ dev / tty0 does not exist , so don ' t fail if we can ' t open
it . */
if ( access ( " /dev/tty0 " , F_OK ) < 0 ) {
m - > console_active_fd = - 1 ;
return 0 ;
}
2011-05-24 01:55:06 +04:00
m - > console_active_fd = open ( " /sys/class/tty/tty0/active " , O_RDONLY | O_NOCTTY | O_CLOEXEC ) ;
if ( m - > console_active_fd < 0 ) {
2012-06-16 00:22:24 +04:00
/* On some systems the device node /dev/tty0 may exist
* even though / sys / class / tty / tty0 does not . */
if ( errno = = ENOENT )
return 0 ;
2011-05-24 01:55:06 +04:00
log_error ( " Failed to open /sys/class/tty/tty0/active: %m " ) ;
return - errno ;
}
if ( epoll_ctl ( m - > epoll_fd , EPOLL_CTL_ADD , m - > console_active_fd , & ev ) < 0 )
return - errno ;
return 0 ;
}
static int manager_connect_udev ( Manager * m ) {
2011-05-25 02:55:58 +04:00
int r ;
2013-03-25 03:59:00 +04:00
struct epoll_event ev = {
. events = EPOLLIN ,
. data . u32 = FD_SEAT_UDEV ,
} ;
2011-05-24 01:55:06 +04:00
assert ( m ) ;
2011-06-28 05:21:14 +04:00
assert ( ! m - > udev_seat_monitor ) ;
assert ( ! m - > udev_vcsa_monitor ) ;
2012-05-30 17:01:51 +04:00
assert ( ! m - > udev_button_monitor ) ;
2011-05-24 01:55:06 +04:00
2011-06-28 05:21:14 +04:00
m - > udev_seat_monitor = udev_monitor_new_from_netlink ( m - > udev , " udev " ) ;
if ( ! m - > udev_seat_monitor )
2011-05-24 01:55:06 +04:00
return - ENOMEM ;
2013-02-09 04:25:55 +04:00
r = udev_monitor_filter_add_match_tag ( m - > udev_seat_monitor , " master-of-seat " ) ;
2011-05-25 02:55:58 +04:00
if ( r < 0 )
return r ;
2011-05-24 01:55:06 +04:00
2011-06-28 05:21:14 +04:00
r = udev_monitor_enable_receiving ( m - > udev_seat_monitor ) ;
2011-05-25 02:55:58 +04:00
if ( r < 0 )
return r ;
2011-05-24 01:55:06 +04:00
2011-06-28 05:21:14 +04:00
m - > udev_seat_fd = udev_monitor_get_fd ( m - > udev_seat_monitor ) ;
2011-05-24 01:55:06 +04:00
2012-05-30 17:01:51 +04:00
if ( epoll_ctl ( m - > epoll_fd , EPOLL_CTL_ADD , m - > udev_seat_fd , & ev ) < 0 )
return - errno ;
2012-05-30 23:40:32 +04:00
/* Don't watch keys if nobody cares */
2012-09-19 15:10:10 +04:00
if ( m - > handle_power_key ! = HANDLE_IGNORE | |
2012-09-21 17:44:14 +04:00
m - > handle_suspend_key ! = HANDLE_IGNORE | |
m - > handle_hibernate_key ! = HANDLE_IGNORE | |
2012-09-19 15:10:10 +04:00
m - > handle_lid_switch ! = HANDLE_IGNORE ) {
2012-05-30 17:01:51 +04:00
2012-05-30 23:40:32 +04:00
m - > udev_button_monitor = udev_monitor_new_from_netlink ( m - > udev , " udev " ) ;
if ( ! m - > udev_button_monitor )
return - ENOMEM ;
2012-05-30 17:01:51 +04:00
2012-05-30 23:40:32 +04:00
r = udev_monitor_filter_add_match_tag ( m - > udev_button_monitor , " power-switch " ) ;
if ( r < 0 )
return r ;
2012-05-30 17:01:51 +04:00
2012-05-30 23:40:32 +04:00
r = udev_monitor_filter_add_match_subsystem_devtype ( m - > udev_button_monitor , " input " , NULL ) ;
if ( r < 0 )
return r ;
2012-05-30 17:01:51 +04:00
2012-05-30 23:40:32 +04:00
r = udev_monitor_enable_receiving ( m - > udev_button_monitor ) ;
if ( r < 0 )
return r ;
2012-05-30 17:01:51 +04:00
2012-05-30 23:40:32 +04:00
m - > udev_button_fd = udev_monitor_get_fd ( m - > udev_button_monitor ) ;
2012-05-30 17:01:51 +04:00
2012-05-30 23:40:32 +04:00
zero ( ev ) ;
ev . events = EPOLLIN ;
ev . data . u32 = FD_BUTTON_UDEV ;
if ( epoll_ctl ( m - > epoll_fd , EPOLL_CTL_ADD , m - > udev_button_fd , & ev ) < 0 )
return - errno ;
}
2012-05-30 17:01:51 +04:00
2012-01-04 00:50:02 +04:00
/* Don't bother watching VCSA devices, if nobody cares */
2012-05-30 23:40:32 +04:00
if ( m - > n_autovts > 0 & & m - > console_active_fd > = 0 ) {
2011-06-28 05:21:14 +04:00
2012-05-30 23:40:32 +04:00
m - > udev_vcsa_monitor = udev_monitor_new_from_netlink ( m - > udev , " udev " ) ;
if ( ! m - > udev_vcsa_monitor )
return - ENOMEM ;
2011-06-28 05:21:14 +04:00
2012-05-30 23:40:32 +04:00
r = udev_monitor_filter_add_match_subsystem_devtype ( m - > udev_vcsa_monitor , " vc " , NULL ) ;
if ( r < 0 )
return r ;
2011-06-28 05:21:14 +04:00
2012-05-30 23:40:32 +04:00
r = udev_monitor_enable_receiving ( m - > udev_vcsa_monitor ) ;
if ( r < 0 )
return r ;
2011-06-28 05:21:14 +04:00
2012-05-30 23:40:32 +04:00
m - > udev_vcsa_fd = udev_monitor_get_fd ( m - > udev_vcsa_monitor ) ;
2011-06-28 05:21:14 +04:00
2012-05-30 23:40:32 +04:00
zero ( ev ) ;
ev . events = EPOLLIN ;
ev . data . u32 = FD_VCSA_UDEV ;
if ( epoll_ctl ( m - > epoll_fd , EPOLL_CTL_ADD , m - > udev_vcsa_fd , & ev ) < 0 )
return - errno ;
}
2011-05-24 01:55:06 +04:00
return 0 ;
}
2011-06-29 05:48:16 +04:00
void manager_gc ( Manager * m , bool drop_not_started ) {
2011-05-25 02:55:58 +04:00
Seat * seat ;
Session * session ;
User * user ;
assert ( m ) ;
while ( ( seat = m - > seat_gc_queue ) ) {
LIST_REMOVE ( Seat , gc_queue , m - > seat_gc_queue , seat ) ;
seat - > in_gc_queue = false ;
2011-06-29 05:48:16 +04:00
if ( seat_check_gc ( seat , drop_not_started ) = = 0 ) {
2011-05-25 02:55:58 +04:00
seat_stop ( seat ) ;
seat_free ( seat ) ;
}
}
while ( ( session = m - > session_gc_queue ) ) {
LIST_REMOVE ( Session , gc_queue , m - > session_gc_queue , session ) ;
session - > in_gc_queue = false ;
2011-06-29 05:48:16 +04:00
if ( session_check_gc ( session , drop_not_started ) = = 0 ) {
2011-05-25 02:55:58 +04:00
session_stop ( session ) ;
2013-08-13 19:59:28 +04:00
session_finalize ( session ) ;
2011-05-25 02:55:58 +04:00
session_free ( session ) ;
}
}
while ( ( user = m - > user_gc_queue ) ) {
LIST_REMOVE ( User , gc_queue , m - > user_gc_queue , user ) ;
user - > in_gc_queue = false ;
2011-06-29 05:48:16 +04:00
if ( user_check_gc ( user , drop_not_started ) = = 0 ) {
2011-05-25 02:55:58 +04:00
user_stop ( user ) ;
2013-08-13 19:59:28 +04:00
user_finalize ( user ) ;
2011-05-25 02:55:58 +04:00
user_free ( user ) ;
}
}
}
2011-06-17 17:59:18 +04:00
int manager_get_idle_hint ( Manager * m , dual_timestamp * t ) {
Session * s ;
2012-04-16 19:05:15 +04:00
bool idle_hint ;
2011-06-17 17:59:18 +04:00
dual_timestamp ts = { 0 , 0 } ;
Iterator i ;
assert ( m ) ;
2012-09-21 13:57:48 +04:00
idle_hint = ! manager_is_inhibited ( m , INHIBIT_IDLE , INHIBIT_BLOCK , t , false , false , 0 ) ;
2012-04-16 19:05:15 +04:00
2011-06-17 17:59:18 +04:00
HASHMAP_FOREACH ( s , m - > sessions , i ) {
dual_timestamp k ;
int ih ;
ih = session_get_idle_hint ( s , & k ) ;
if ( ih < 0 )
return ih ;
if ( ! ih ) {
if ( ! idle_hint ) {
if ( k . monotonic < ts . monotonic )
ts = k ;
} else {
idle_hint = false ;
ts = k ;
}
} else if ( idle_hint ) {
if ( k . monotonic > ts . monotonic )
ts = k ;
}
}
if ( t )
* t = ts ;
return idle_hint ;
}
2013-08-13 19:59:28 +04:00
bool manager_shall_kill ( Manager * m , const char * user ) {
assert ( m ) ;
assert ( user ) ;
if ( ! m - > kill_user_processes )
return false ;
if ( strv_contains ( m - > kill_exclude_users , user ) )
return false ;
if ( strv_isempty ( m - > kill_only_users ) )
return true ;
return strv_contains ( m - > kill_only_users , user ) ;
}
2012-12-24 01:32:48 +04:00
int manager_dispatch_idle_action ( Manager * m ) {
struct dual_timestamp since ;
2013-03-25 03:59:00 +04:00
struct itimerspec its = { } ;
2012-12-24 01:32:48 +04:00
int r ;
usec_t n ;
assert ( m ) ;
if ( m - > idle_action = = HANDLE_IGNORE | |
m - > idle_action_usec < = 0 ) {
r = 0 ;
goto finish ;
}
n = now ( CLOCK_MONOTONIC ) ;
r = manager_get_idle_hint ( m , & since ) ;
if ( r < = 0 )
2013-02-15 01:16:58 +04:00
/* Not idle. Let's check if after a timeout it might be idle then. */
2012-12-24 01:32:48 +04:00
timespec_store ( & its . it_value , n + m - > idle_action_usec ) ;
else {
/* Idle! Let's see if it's time to do something, or if
* we shall sleep for longer . */
if ( n > = since . monotonic + m - > idle_action_usec & &
( m - > idle_action_not_before_usec < = 0 | | n > = m - > idle_action_not_before_usec + m - > idle_action_usec ) ) {
log_info ( " System idle. Taking action. " ) ;
manager_handle_action ( m , 0 , m - > idle_action , false , false ) ;
m - > idle_action_not_before_usec = n ;
}
timespec_store ( & its . it_value , MAX ( since . monotonic , m - > idle_action_not_before_usec ) + m - > idle_action_usec ) ;
}
if ( m - > idle_action_fd < 0 ) {
2013-03-25 03:59:00 +04:00
struct epoll_event ev = {
. events = EPOLLIN ,
. data . u32 = FD_IDLE_ACTION ,
} ;
2012-12-24 01:32:48 +04:00
m - > idle_action_fd = timerfd_create ( CLOCK_MONOTONIC , TFD_NONBLOCK | TFD_CLOEXEC ) ;
if ( m - > idle_action_fd < 0 ) {
log_error ( " Failed to create idle action timer: %m " ) ;
r = - errno ;
goto finish ;
}
if ( epoll_ctl ( m - > epoll_fd , EPOLL_CTL_ADD , m - > idle_action_fd , & ev ) < 0 ) {
log_error ( " Failed to add idle action timer to epoll: %m " ) ;
r = - errno ;
goto finish ;
}
}
if ( timerfd_settime ( m - > idle_action_fd , TFD_TIMER_ABSTIME , & its , NULL ) < 0 ) {
log_error ( " Failed to reset timerfd: %m " ) ;
r = - errno ;
goto finish ;
}
return 0 ;
finish :
if ( m - > idle_action_fd > = 0 ) {
close_nointr_nofail ( m - > idle_action_fd ) ;
m - > idle_action_fd = - 1 ;
}
return r ;
}
2011-05-24 01:55:06 +04:00
int manager_startup ( Manager * m ) {
int r ;
2011-05-25 02:55:58 +04:00
Seat * seat ;
Session * session ;
User * user ;
2012-04-16 18:47:33 +04:00
Inhibitor * inhibitor ;
2011-05-25 02:55:58 +04:00
Iterator i ;
2011-05-24 01:55:06 +04:00
assert ( m ) ;
assert ( m - > epoll_fd < = 0 ) ;
m - > epoll_fd = epoll_create1 ( EPOLL_CLOEXEC ) ;
if ( m - > epoll_fd < 0 )
return - errno ;
2012-01-04 00:50:02 +04:00
/* Connect to console */
r = manager_connect_console ( m ) ;
2011-05-24 01:55:06 +04:00
if ( r < 0 )
return r ;
2012-01-04 00:50:02 +04:00
/* Connect to udev */
r = manager_connect_udev ( m ) ;
2011-05-24 01:55:06 +04:00
if ( r < 0 )
return r ;
/* Connect to the bus */
r = manager_connect_bus ( m ) ;
if ( r < 0 )
return r ;
2011-05-25 02:55:58 +04:00
/* Instantiate magic seat 0 */
r = manager_add_seat ( m , " seat0 " , & m - > vtconsole ) ;
if ( r < 0 )
return r ;
2011-05-24 01:55:06 +04:00
/* Deserialize state */
2013-08-24 18:52:23 +04:00
r = manager_enumerate_devices ( m ) ;
if ( r < 0 )
log_warning ( " Device enumeration failed: %s " , strerror ( - r ) ) ;
r = manager_enumerate_seats ( m ) ;
if ( r < 0 )
log_warning ( " Seat enumeration failed: %s " , strerror ( - r ) ) ;
r = manager_enumerate_users ( m ) ;
if ( r < 0 )
log_warning ( " User enumeration failed: %s " , strerror ( - r ) ) ;
r = manager_enumerate_sessions ( m ) ;
if ( r < 0 )
log_warning ( " Session enumeration failed: %s " , strerror ( - r ) ) ;
r = manager_enumerate_inhibitors ( m ) ;
if ( r < 0 )
log_warning ( " Inhibitor enumeration failed: %s " , strerror ( - r ) ) ;
r = manager_enumerate_buttons ( m ) ;
if ( r < 0 )
log_warning ( " Button enumeration failed: %s " , strerror ( - r ) ) ;
2011-05-24 01:55:06 +04:00
2011-06-29 05:48:16 +04:00
/* Remove stale objects before we start them */
manager_gc ( m , false ) ;
2012-09-17 14:39:16 +04:00
/* Reserve the special reserved VT */
manager_reserve_vt ( m ) ;
2011-05-25 02:55:58 +04:00
/* And start everything */
HASHMAP_FOREACH ( seat , m - > seats , i )
seat_start ( seat ) ;
HASHMAP_FOREACH ( user , m - > users , i )
user_start ( user ) ;
HASHMAP_FOREACH ( session , m - > sessions , i )
session_start ( session ) ;
2011-05-24 01:55:06 +04:00
2012-04-16 18:47:33 +04:00
HASHMAP_FOREACH ( inhibitor , m - > inhibitors , i )
inhibitor_start ( inhibitor ) ;
2012-12-24 01:32:48 +04:00
manager_dispatch_idle_action ( m ) ;
2011-05-24 01:55:06 +04:00
return 0 ;
}
2012-09-19 17:42:29 +04:00
static int manager_recheck_buttons ( Manager * m ) {
Iterator i ;
Button * b ;
int r = 0 ;
assert ( m ) ;
HASHMAP_FOREACH ( b , m - > buttons , i ) {
int q ;
q = button_recheck ( b ) ;
if ( q > 0 )
return 1 ;
if ( q < 0 )
r = q ;
}
return r ;
}
2011-05-24 01:55:06 +04:00
int manager_run ( Manager * m ) {
assert ( m ) ;
for ( ; ; ) {
struct epoll_event event ;
int n ;
2012-05-05 02:34:48 +04:00
int msec = - 1 ;
2011-05-24 01:55:06 +04:00
2011-06-29 05:48:16 +04:00
manager_gc ( m , true ) ;
2011-05-25 02:55:58 +04:00
2012-05-08 21:02:25 +04:00
if ( manager_dispatch_delayed ( m ) > 0 )
2012-05-05 02:34:48 +04:00
continue ;
2012-09-19 17:42:29 +04:00
if ( manager_recheck_buttons ( m ) > 0 )
continue ;
2011-05-24 01:55:06 +04:00
if ( dbus_connection_dispatch ( m - > bus ) ! = DBUS_DISPATCH_COMPLETE )
continue ;
2011-06-29 05:48:16 +04:00
manager_gc ( m , true ) ;
2011-06-24 22:41:56 +04:00
2013-04-24 22:23:01 +04:00
if ( m - > action_what ! = 0 & & ! m - > action_job ) {
2012-05-05 02:34:48 +04:00
usec_t x , y ;
x = now ( CLOCK_MONOTONIC ) ;
2013-01-25 09:30:23 +04:00
y = m - > action_timestamp + m - > inhibit_delay_max ;
2012-05-05 02:34:48 +04:00
msec = x > = y ? 0 : ( int ) ( ( y - x ) / USEC_PER_MSEC ) ;
}
n = epoll_wait ( m - > epoll_fd , & event , 1 , msec ) ;
2011-05-24 01:55:06 +04:00
if ( n < 0 ) {
2011-05-26 04:21:16 +04:00
if ( errno = = EINTR | | errno = = EAGAIN )
continue ;
2011-05-24 01:55:06 +04:00
log_error ( " epoll() failed: %m " ) ;
return - errno ;
}
2012-05-05 02:34:48 +04:00
if ( n = = 0 )
continue ;
2011-05-24 01:55:06 +04:00
switch ( event . data . u32 ) {
2011-06-28 05:21:14 +04:00
case FD_SEAT_UDEV :
manager_dispatch_seat_udev ( m ) ;
break ;
case FD_VCSA_UDEV :
manager_dispatch_vcsa_udev ( m ) ;
2011-05-24 01:55:06 +04:00
break ;
2012-05-30 17:01:51 +04:00
case FD_BUTTON_UDEV :
manager_dispatch_button_udev ( m ) ;
break ;
2011-05-24 01:55:06 +04:00
case FD_CONSOLE :
manager_dispatch_console ( m ) ;
break ;
2012-12-24 01:32:48 +04:00
case FD_IDLE_ACTION :
manager_dispatch_idle_action ( m ) ;
break ;
2011-05-24 01:55:06 +04:00
case FD_BUS :
bus_loop_dispatch ( m - > bus_fd ) ;
break ;
2011-06-25 01:25:28 +04:00
default :
2012-05-30 17:01:51 +04:00
if ( event . data . u32 > = FD_OTHER_BASE )
manager_dispatch_other ( m , event . data . u32 - FD_OTHER_BASE ) ;
2011-05-24 01:55:06 +04:00
}
}
return 0 ;
}
2011-06-29 03:47:55 +04:00
static int manager_parse_config_file ( Manager * m ) {
2013-04-25 02:53:16 +04:00
static const char fn [ ] = " /etc/systemd/logind.conf " ;
_cleanup_fclose_ FILE * f = NULL ;
2011-06-29 03:47:55 +04:00
int r ;
assert ( m ) ;
f = fopen ( fn , " re " ) ;
if ( ! f ) {
if ( errno = = ENOENT )
return 0 ;
log_warning ( " Failed to open configuration file %s: %m " , fn ) ;
return - errno ;
}
2013-04-25 02:53:16 +04:00
r = config_parse ( NULL , fn , f , " Login \0 " , config_item_perf_lookup ,
( void * ) logind_gperf_lookup , false , false , m ) ;
2011-06-29 03:47:55 +04:00
if ( r < 0 )
log_warning ( " Failed to parse configuration file: %s " , strerror ( - r ) ) ;
return r ;
}
2011-05-24 01:55:06 +04:00
int main ( int argc , char * argv [ ] ) {
Manager * m = NULL ;
2011-05-24 06:20:35 +04:00
int r ;
2011-05-24 01:55:06 +04:00
log_set_target ( LOG_TARGET_AUTO ) ;
2012-04-03 21:25:29 +04:00
log_set_facility ( LOG_AUTH ) ;
2011-05-24 01:55:06 +04:00
log_parse_environment ( ) ;
log_open ( ) ;
2011-08-01 22:52:18 +04:00
umask ( 0022 ) ;
2011-05-24 01:55:06 +04:00
if ( argc ! = 1 ) {
log_error ( " This program takes no arguments. " ) ;
r = - EINVAL ;
goto finish ;
}
2013-03-15 19:46:35 +04:00
/* Always create the directories people can create inotify
* watches in . Note that some applications might check for the
2013-04-15 06:37:54 +04:00
* existence of / run / systemd / seats / to determine whether
2013-03-15 19:46:35 +04:00
* logind is available , so please always make sure this check
* stays in . */
mkdir_label ( " /run/systemd/seats " , 0755 ) ;
mkdir_label ( " /run/systemd/users " , 0755 ) ;
mkdir_label ( " /run/systemd/sessions " , 0755 ) ;
2011-05-24 01:55:06 +04:00
m = manager_new ( ) ;
if ( ! m ) {
2012-07-26 01:55:59 +04:00
r = log_oom ( ) ;
2011-05-24 01:55:06 +04:00
goto finish ;
}
2011-06-29 03:47:55 +04:00
manager_parse_config_file ( m ) ;
2011-05-24 01:55:06 +04:00
r = manager_startup ( m ) ;
if ( r < 0 ) {
log_error ( " Failed to fully start up daemon: %s " , strerror ( - r ) ) ;
goto finish ;
}
2012-01-04 23:40:04 +04:00
log_debug ( " systemd-logind running as pid %lu " , ( unsigned long ) getpid ( ) ) ;
sd_notify ( false ,
" READY=1 \n "
" STATUS=Processing requests... " ) ;
2011-05-24 01:55:06 +04:00
r = manager_run ( m ) ;
2012-01-04 23:40:04 +04:00
log_debug ( " systemd-logind stopped as pid %lu " , ( unsigned long ) getpid ( ) ) ;
2011-05-24 01:55:06 +04:00
finish :
2012-01-04 23:40:04 +04:00
sd_notify ( false ,
" STATUS=Shutting down... " ) ;
2011-05-24 01:55:06 +04:00
if ( m )
manager_free ( m ) ;
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS ;
}