summaryrefslogtreecommitdiff
path: root/src/udev
diff options
context:
space:
mode:
Diffstat (limited to 'src/udev')
-rw-r--r--src/udev/keyboard-keys-from-name.gperf419
-rw-r--r--src/udev/net/link-config.c12
-rw-r--r--src/udev/udev-builtin-hwdb.c2
-rw-r--r--src/udev/udev-builtin-input_id.c146
-rw-r--r--src/udev/udev-builtin-keyboard.c6
-rw-r--r--src/udev/udev-builtin-net_id.c21
-rw-r--r--src/udev/udev-builtin-path_id.c30
-rw-r--r--src/udev/udev-builtin-usb_id.c2
-rw-r--r--src/udev/udev-event.c232
-rw-r--r--src/udev/udev-rules.c16
-rw-r--r--src/udev/udev.h18
-rw-r--r--src/udev/udevadm-test.c11
-rw-r--r--src/udev/udevd.c729
13 files changed, 678 insertions, 966 deletions
diff --git a/src/udev/keyboard-keys-from-name.gperf b/src/udev/keyboard-keys-from-name.gperf
deleted file mode 100644
index ded737580e..0000000000
--- a/src/udev/keyboard-keys-from-name.gperf
+++ /dev/null
@@ -1,419 +0,0 @@
-struct key { const char* name; unsigned short id; };
-%null-strings
-%%
-hiragana, KEY_HIRAGANA
-touchpad_toggle, KEY_TOUCHPAD_TOGGLE
-deletefile, KEY_DELETEFILE
-title, KEY_TITLE
-grave, KEY_GRAVE
-reserved, KEY_RESERVED
-dvd, KEY_DVD
-fn_f10, KEY_FN_F10
-fn_f11, KEY_FN_F11
-fn_f12, KEY_FN_F12
-frameback, KEY_FRAMEBACK
-brl_dot10, KEY_BRL_DOT10
-kpslash, KEY_KPSLASH
-sleep, KEY_SLEEP
-kbdinputassist_accept, KEY_KBDINPUTASSIST_ACCEPT
-vcr2, KEY_VCR2
-zenkakuhankaku, KEY_ZENKAKUHANKAKU
-images, KEY_IMAGES
-documents, KEY_DOCUMENTS
-leftmeta, KEY_LEFTMETA
-open, KEY_OPEN
-battery, KEY_BATTERY
-macro, KEY_MACRO
-mode, KEY_MODE
-green, KEY_GREEN
-sat, KEY_SAT
-rightmeta, KEY_RIGHTMETA
-computer, KEY_COMPUTER
-select, KEY_SELECT
-pagedown, KEY_PAGEDOWN
-capslock, KEY_CAPSLOCK
-redo, KEY_REDO
-kbdillumdown, KEY_KBDILLUMDOWN
-scrolldown, KEY_SCROLLDOWN
-switchvideomode, KEY_SWITCHVIDEOMODE
-wordprocessor, KEY_WORDPROCESSOR
-camera, KEY_CAMERA
-move, KEY_MOVE
-connect, KEY_CONNECT
-prog1, KEY_PROG1
-prog2, KEY_PROG2
-prog3, KEY_PROG3
-prog4, KEY_PROG4
-wwan, KEY_WWAN
-twen, KEY_TWEN
-ins_line, KEY_INS_LINE
-screensaver, KEY_SCREENSAVER
-games, KEY_GAMES
-katakana, KEY_KATAKANA
-numeric_b, KEY_NUMERIC_B
-props, KEY_PROPS
-calendar, KEY_CALENDAR
-restart, KEY_RESTART
-kbdillumtoggle, KEY_KBDILLUMTOGGLE
-clear, KEY_CLEAR
-camera_focus, KEY_CAMERA_FOCUS
-numlock, KEY_NUMLOCK
-bluetooth, KEY_BLUETOOTH
-zoomin, KEY_ZOOMIN
-edit, KEY_EDIT
-kbdinputassist_prev, KEY_KBDINPUTASSIST_PREV
-aux, KEY_AUX
-equal, KEY_EQUAL
-directory, KEY_DIRECTORY
-camera_right, KEY_CAMERA_RIGHT
-addressbook, KEY_ADDRESSBOOK
-paste, KEY_PASTE
-channelup, KEY_CHANNELUP
-shuffle, KEY_SHUFFLE
-mail, KEY_MAIL
-leftalt, KEY_LEFTALT
-www, KEY_WWW
-kpequal, KEY_KPEQUAL
-henkan, KEY_HENKAN
-displaytoggle, KEY_DISPLAYTOGGLE
-rightalt, KEY_RIGHTALT
-sport, KEY_SPORT
-power, KEY_POWER
-apostrophe, KEY_APOSTROPHE
-screen, KEY_SCREEN
-radio, KEY_RADIO
-database, KEY_DATABASE
-volumedown, KEY_VOLUMEDOWN
-appselect, KEY_APPSELECT
-sendfile, KEY_SENDFILE
-rightshift, KEY_RIGHTSHIFT
-archive, KEY_ARCHIVE
-numeric_pound, KEY_NUMERIC_POUND
-epg, KEY_EPG
-nextsong, KEY_NEXTSONG
-first, KEY_FIRST
-spreadsheet, KEY_SPREADSHEET
-back, KEY_BACK
-kp3, KEY_KP3
-kp5, KEY_KP5
-pageup, KEY_PAGEUP
-esc, KEY_ESC
-delete, KEY_DELETE
-home, KEY_HOME
-wps_button, KEY_WPS_BUTTON
-audio, KEY_AUDIO
-new, KEY_NEW
-sat2, KEY_SAT2
-linefeed, KEY_LINEFEED
-pvr, KEY_PVR
-kpplusminus, KEY_KPPLUSMINUS
-shop, KEY_SHOP
-leftshift, KEY_LEFTSHIFT
-bassboost, KEY_BASSBOOST
-brightness_cycle, KEY_BRIGHTNESS_CYCLE
-tab, KEY_TAB
-unknown, KEY_UNKNOWN
-kpleftparen, KEY_KPLEFTPAREN
-editor, KEY_EDITOR
-email, KEY_EMAIL
-als_toggle, KEY_ALS_TOGGLE
-102nd, KEY_102ND
-menu, KEY_MENU
-voicemail, KEY_VOICEMAIL
-space, KEY_SPACE
-info, KEY_INFO
-wakeup, KEY_WAKEUP
-semicolon, KEY_SEMICOLON
-blue, KEY_BLUE
-homepage, KEY_HOMEPAGE
-digits, KEY_DIGITS
-zoomreset, KEY_ZOOMRESET
-favorites, KEY_FAVORITES
-touchpad_on, KEY_TOUCHPAD_ON
-fn_1, KEY_FN_1
-fn_2, KEY_FN_2
-iso, KEY_ISO
-fn_d, KEY_FN_D
-fn_e, KEY_FN_E
-fn_f, KEY_FN_F
-fn_s, KEY_FN_S
-hanja, KEY_HANJA
-break, KEY_BREAK
-forward, KEY_FORWARD
-tv2, KEY_TV2
-pausecd, KEY_PAUSECD
-right, KEY_RIGHT
-f21, KEY_F21
-slow, KEY_SLOW
-attendant_on, KEY_ATTENDANT_ON
-f10, KEY_F10
-f11, KEY_F11
-f12, KEY_F12
-f13, KEY_F13
-f14, KEY_F14
-f15, KEY_F15
-f16, KEY_F16
-f17, KEY_F17
-f18, KEY_F18
-f19, KEY_F19
-f20, KEY_F20
-f22, KEY_F22
-f23, KEY_F23
-f24, KEY_F24
-save, KEY_SAVE
-1, KEY_1
-2, KEY_2
-3, KEY_3
-4, KEY_4
-5, KEY_5
-6, KEY_6
-7, KEY_7
-8, KEY_8
-9, KEY_9
-b, KEY_B
-c, KEY_C
-d, KEY_D
-e, KEY_E
-f, KEY_F
-g, KEY_G
-h, KEY_H
-i, KEY_I
-k, KEY_K
-l, KEY_L
-m, KEY_M
-o, KEY_O
-p, KEY_P
-r, KEY_R
-s, KEY_S
-t, KEY_T
-u, KEY_U
-w, KEY_W
-x, KEY_X
-z, KEY_Z
-mhp, KEY_MHP
-buttonconfig, KEY_BUTTONCONFIG
-f5, KEY_F5
-record, KEY_RECORD
-f7, KEY_F7
-f8, KEY_F8
-channel, KEY_CHANNEL
-ejectcd, KEY_EJECTCD
-videophone, KEY_VIDEOPHONE
-video, KEY_VIDEO
-vendor, KEY_VENDOR
-mp3, KEY_MP3
-0, KEY_0
-again, KEY_AGAIN
-send, KEY_SEND
-screenlock, KEY_SCREENLOCK
-micmute, KEY_MICMUTE
-comma, KEY_COMMA
-graphicseditor, KEY_GRAPHICSEDITOR
-a, KEY_A
-j, KEY_J
-voicecommand, KEY_VOICECOMMAND
-yellow, KEY_YELLOW
-leftbrace, KEY_LEFTBRACE
-n, KEY_N
-question, KEY_QUESTION
-language, KEY_LANGUAGE
-xfer, KEY_XFER
-q, KEY_Q
-logoff, KEY_LOGOFF
-sound, KEY_SOUND
-v, KEY_V
-print, KEY_PRINT
-y, KEY_Y
-copy, KEY_COPY
-kpcomma, KEY_KPCOMMA
-camera_zoomout, KEY_CAMERA_ZOOMOUT
-brl_dot1, KEY_BRL_DOT1
-brl_dot2, KEY_BRL_DOT2
-brl_dot3, KEY_BRL_DOT3
-brl_dot4, KEY_BRL_DOT4
-brl_dot5, KEY_BRL_DOT5
-brl_dot6, KEY_BRL_DOT6
-brl_dot7, KEY_BRL_DOT7
-brl_dot8, KEY_BRL_DOT8
-brl_dot9, KEY_BRL_DOT9
-brightnessup, KEY_BRIGHTNESSUP
-fn_f7, KEY_FN_F7
-controlpanel, KEY_CONTROLPANEL
-yen, KEY_YEN
-play, KEY_PLAY
-rewind, KEY_REWIND
-video_next, KEY_VIDEO_NEXT
-touchpad_off, KEY_TOUCHPAD_OFF
-help, KEY_HELP
-numeric_star, KEY_NUMERIC_STAR
-backslash, KEY_BACKSLASH
-sysrq, KEY_SYSRQ
-end, KEY_END
-rfkill, KEY_RFKILL
-leftctrl, KEY_LEFTCTRL
-kprightparen, KEY_KPRIGHTPAREN
-attendant_toggle, KEY_ATTENDANT_TOGGLE
-kpasterisk, KEY_KPASTERISK
-refresh, KEY_REFRESH
-rightctrl, KEY_RIGHTCTRL
-keyboard, KEY_KEYBOARD
-search, KEY_SEARCH
-phone, KEY_PHONE
-kbdillumup, KEY_KBDILLUMUP
-stop, KEY_STOP
-chat, KEY_CHAT
-volumeup, KEY_VOLUMEUP
-brightness_auto, KEY_BRIGHTNESS_AUTO
-closecd, KEY_CLOSECD
-camera_zoomin, KEY_CAMERA_ZOOMIN
-undo, KEY_UNDO
-tuner, KEY_TUNER
-angle, KEY_ANGLE
-presentation, KEY_PRESENTATION
-camera_down, KEY_CAMERA_DOWN
-reply, KEY_REPLY
-calc, KEY_CALC
-exit, KEY_EXIT
-fn_b, KEY_FN_B
-dollar, KEY_DOLLAR
-camera_left, KEY_CAMERA_LEFT
-rotate_display, KEY_ROTATE_DISPLAY
-uwb, KEY_UWB
-previoussong, KEY_PREVIOUSSONG
-config, KEY_CONFIG
-setup, KEY_SETUP
-kbdinputassist_cancel, KEY_KBDINPUTASSIST_CANCEL
-playcd, KEY_PLAYCD
-media, KEY_MEDIA
-compose, KEY_COMPOSE
-player, KEY_PLAYER
-10channelsdown, KEY_10CHANNELSDOWN
-taskmanager, KEY_TASKMANAGER
-list, KEY_LIST
-frameforward, KEY_FRAMEFORWARD
-msdos, KEY_MSDOS
-zoom, KEY_ZOOM
-news, KEY_NEWS
-numeric_0, KEY_NUMERIC_0
-numeric_1, KEY_NUMERIC_1
-numeric_2, KEY_NUMERIC_2
-numeric_3, KEY_NUMERIC_3
-numeric_4, KEY_NUMERIC_4
-numeric_5, KEY_NUMERIC_5
-numeric_7, KEY_NUMERIC_7
-numeric_8, KEY_NUMERIC_8
-numeric_9, KEY_NUMERIC_9
-numeric_a, KEY_NUMERIC_A
-numeric_c, KEY_NUMERIC_C
-numeric_d, KEY_NUMERIC_D
-scale, KEY_SCALE
-next, KEY_NEXT
-cut, KEY_CUT
-previous, KEY_PREVIOUS
-video_prev, KEY_VIDEO_PREV
-mute, KEY_MUTE
-pause, KEY_PAUSE
-tape, KEY_TAPE
-program, KEY_PROGRAM
-option, KEY_OPTION
-zoomout, KEY_ZOOMOUT
-playpause, KEY_PLAYPAUSE
-display_off, KEY_DISPLAY_OFF
-red, KEY_RED
-kpplus, KEY_KPPLUS
-finance, KEY_FINANCE
-brightnessdown, KEY_BRIGHTNESSDOWN
-kpdot, KEY_KPDOT
-brightness_max, KEY_BRIGHTNESS_MAX
-teen, KEY_TEEN
-fn_f1, KEY_FN_F1
-fn_f2, KEY_FN_F2
-fn_f3, KEY_FN_F3
-fn_f4, KEY_FN_F4
-fn_f5, KEY_FN_F5
-fn_f6, KEY_FN_F6
-fn_f8, KEY_FN_F8
-fn_f9, KEY_FN_F9
-euro, KEY_EURO
-brightness_min, KEY_BRIGHTNESS_MIN
-ab, KEY_AB
-kbdinputassist_prevgroup, KEY_KBDINPUTASSIST_PREVGROUP
-kbdinputassist_nextgroup, KEY_KBDINPUTASSIST_NEXTGROUP
-subtitle, KEY_SUBTITLE
-cd, KEY_CD
-context_menu, KEY_CONTEXT_MENU
-messenger, KEY_MESSENGER
-f1, KEY_F1
-f2, KEY_F2
-f3, KEY_F3
-f4, KEY_F4
-f6, KEY_F6
-f9, KEY_F9
-fn, KEY_FN
-scrollup, KEY_SCROLLUP
-enter, KEY_ENTER
-cancel, KEY_CANCEL
-scrolllock, KEY_SCROLLLOCK
-rightbrace, KEY_RIGHTBRACE
-vcr, KEY_VCR
-hp, KEY_HP
-fastforward, KEY_FASTFORWARD
-text, KEY_TEXT
-fn_esc, KEY_FN_ESC
-insert, KEY_INSERT
-cyclewindows, KEY_CYCLEWINDOWS
-katakanahiragana, KEY_KATAKANAHIRAGANA
-front, KEY_FRONT
-wlan, KEY_WLAN
-dashboard, KEY_DASHBOARD
-forwardmail, KEY_FORWARDMAIL
-muhenkan, KEY_MUHENKAN
-ok, KEY_OK
-channeldown, KEY_CHANNELDOWN
-del_eol, KEY_DEL_EOL
-down, KEY_DOWN
-del_eos, KEY_DEL_EOS
-pc, KEY_PC
-kpenter, KEY_KPENTER
-last, KEY_LAST
-kp0, KEY_KP0
-kp1, KEY_KP1
-kp2, KEY_KP2
-kp4, KEY_KP4
-kp6, KEY_KP6
-kp7, KEY_KP7
-kp8, KEY_KP8
-kp9, KEY_KP9
-lights_toggle, KEY_LIGHTS_TOGGLE
-backspace, KEY_BACKSPACE
-ro, KEY_RO
-alterase, KEY_ALTERASE
-attendant_off, KEY_ATTENDANT_OFF
-power2, KEY_POWER2
-journal, KEY_JOURNAL
-minus, KEY_MINUS
-kpjpcomma, KEY_KPJPCOMMA
-10channelsup, KEY_10CHANNELSUP
-tv, KEY_TV
-up, KEY_UP
-suspend, KEY_SUSPEND
-file, KEY_FILE
-time, KEY_TIME
-find, KEY_FIND
-stopcd, KEY_STOPCD
-spellcheck, KEY_SPELLCHECK
-left, KEY_LEFT
-ejectclosecd, KEY_EJECTCLOSECD
-kpminus, KEY_KPMINUS
-goto, KEY_GOTO
-media_repeat, KEY_MEDIA_REPEAT
-memo, KEY_MEMO
-slash, KEY_SLASH
-camera_up, KEY_CAMERA_UP
-del_line, KEY_DEL_LINE
-close, KEY_CLOSE
-dot, KEY_DOT
-numeric_6, KEY_NUMERIC_6
-kbdinputassist_next, KEY_KBDINPUTASSIST_NEXT
-hangeul, KEY_HANGEUL
-bookmarks, KEY_BOOKMARKS
diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c
index ce038abee5..63e54db56e 100644
--- a/src/udev/net/link-config.c
+++ b/src/udev/net/link-config.c
@@ -28,14 +28,14 @@
#include "ethtool-util.h"
#include "libudev-private.h"
-#include "sd-rtnl.h"
+#include "sd-netlink.h"
#include "util.h"
#include "log.h"
#include "strv.h"
#include "path-util.h"
#include "conf-parser.h"
#include "conf-files.h"
-#include "rtnl-util.h"
+#include "netlink-util.h"
#include "network-internal.h"
#include "random-util.h"
@@ -46,7 +46,7 @@ struct link_config_ctx {
bool enable_name_policy;
- sd_rtnl *rtnl;
+ sd_netlink *rtnl;
usec_t link_dirs_ts_usec;
};
@@ -103,7 +103,7 @@ void link_config_ctx_free(link_config_ctx *ctx) {
safe_close(ctx->ethtool_fd);
- sd_rtnl_unref(ctx->rtnl);
+ sd_netlink_unref(ctx->rtnl);
link_configs_free(ctx);
@@ -240,6 +240,10 @@ int link_config_get(link_config_ctx *ctx, struct udev_device *device,
link_config **ret) {
link_config *link;
+ assert(ctx);
+ assert(device);
+ assert(ret);
+
LIST_FOREACH(links, link, ctx->links) {
const char* attr_value;
diff --git a/src/udev/udev-builtin-hwdb.c b/src/udev/udev-builtin-hwdb.c
index 5e0e7ebb11..7dfc74e6fa 100644
--- a/src/udev/udev-builtin-hwdb.c
+++ b/src/udev/udev-builtin-hwdb.c
@@ -85,6 +85,8 @@ static int udev_builtin_hwdb_search(struct udev_device *dev, struct udev_device
bool last = false;
int r = 0;
+ assert(dev);
+
for (d = srcdev; d && !last; d = udev_device_get_parent(d)) {
const char *dsubsys;
const char *modalias = NULL;
diff --git a/src/udev/udev-builtin-input_id.c b/src/udev/udev-builtin-input_id.c
index b14190e423..e3fa4bc162 100644
--- a/src/udev/udev-builtin-input_id.c
+++ b/src/udev/udev-builtin-input_id.c
@@ -133,79 +133,99 @@ static bool test_pointers(struct udev_device *dev,
const unsigned long* bitmask_rel,
const unsigned long* bitmask_props,
bool test) {
- int is_mouse = 0;
- int is_touchpad = 0;
- bool ret = false;
-
- if (test_bit(INPUT_PROP_ACCELEROMETER, bitmask_props)) {
+ bool has_abs_coordinates = false;
+ bool has_rel_coordinates = false;
+ bool has_mt_coordinates = false;
+ bool has_joystick_axes_or_buttons = false;
+ bool is_direct = false;
+ bool has_touch = false;
+ bool has_3d_coordinates = false;
+ bool has_keys = false;
+ bool stylus_or_pen = false;
+ bool finger_but_no_pen = false;
+ bool has_mouse_button = false;
+ bool is_mouse = false;
+ bool is_touchpad = false;
+ bool is_touchscreen = false;
+ bool is_tablet = false;
+ bool is_joystick = false;
+ bool is_accelerometer = false;
+ bool is_pointing_stick= false;
+
+ has_keys = test_bit(EV_KEY, bitmask_ev);
+ has_abs_coordinates = test_bit(ABS_X, bitmask_abs) && test_bit(ABS_Y, bitmask_abs);
+ has_3d_coordinates = has_abs_coordinates && test_bit(ABS_Z, bitmask_abs);
+ is_accelerometer = test_bit(INPUT_PROP_ACCELEROMETER, bitmask_props);
+
+ if (!has_keys && has_3d_coordinates)
+ is_accelerometer = true;
+
+ if (is_accelerometer) {
udev_builtin_add_property(dev, test, "ID_INPUT_ACCELEROMETER", "1");
return true;
}
- if (!test_bit(EV_KEY, bitmask_ev)) {
- if (test_bit(EV_ABS, bitmask_ev) &&
- test_bit(ABS_X, bitmask_abs) &&
- test_bit(ABS_Y, bitmask_abs) &&
- test_bit(ABS_Z, bitmask_abs)) {
- udev_builtin_add_property(dev, test, "ID_INPUT_ACCELEROMETER", "1");
- ret = true;
- }
- return ret;
- }
-
- if (test_bit(EV_ABS, bitmask_ev) &&
- test_bit(ABS_X, bitmask_abs) && test_bit(ABS_Y, bitmask_abs)) {
- if (test_bit(BTN_STYLUS, bitmask_key) || test_bit(BTN_TOOL_PEN, bitmask_key)) {
- udev_builtin_add_property(dev, test, "ID_INPUT_TABLET", "1");
- ret = true;
- } else if (test_bit(BTN_TOOL_FINGER, bitmask_key) && !test_bit(BTN_TOOL_PEN, bitmask_key)) {
- is_touchpad = 1;
- } else if (test_bit(BTN_MOUSE, bitmask_key)) {
+ is_pointing_stick = test_bit(INPUT_PROP_POINTING_STICK, bitmask_props);
+ stylus_or_pen = test_bit(BTN_STYLUS, bitmask_key) || test_bit(BTN_TOOL_PEN, bitmask_key);
+ finger_but_no_pen = test_bit(BTN_TOOL_FINGER, bitmask_key) && !test_bit(BTN_TOOL_PEN, bitmask_key);
+ has_mouse_button = test_bit(BTN_LEFT, bitmask_key);
+ has_rel_coordinates = test_bit(EV_REL, bitmask_ev) && test_bit(REL_X, bitmask_rel) && test_bit(REL_Y, bitmask_rel);
+ has_mt_coordinates = test_bit(ABS_MT_POSITION_X, bitmask_abs) && test_bit(ABS_MT_POSITION_Y, bitmask_abs);
+
+ /* unset has_mt_coordinates if devices claims to have all abs axis */
+ if(has_mt_coordinates && test_bit(ABS_MT_SLOT, bitmask_abs) && test_bit(ABS_MT_SLOT - 1, bitmask_abs))
+ has_mt_coordinates = false;
+ is_direct = test_bit(INPUT_PROP_DIRECT, bitmask_props);
+ has_touch = test_bit(BTN_TOUCH, bitmask_key);
+ /* joysticks don't necessarily have buttons; e. g.
+ * rudders/pedals are joystick-like, but buttonless; they have
+ * other fancy axes */
+ has_joystick_axes_or_buttons = test_bit(BTN_TRIGGER, bitmask_key) ||
+ test_bit(BTN_A, bitmask_key) ||
+ test_bit(BTN_1, bitmask_key) ||
+ test_bit(ABS_RX, bitmask_abs) ||
+ test_bit(ABS_RY, bitmask_abs) ||
+ test_bit(ABS_RZ, bitmask_abs) ||
+ test_bit(ABS_THROTTLE, bitmask_abs) ||
+ test_bit(ABS_RUDDER, bitmask_abs) ||
+ test_bit(ABS_WHEEL, bitmask_abs) ||
+ test_bit(ABS_GAS, bitmask_abs) ||
+ test_bit(ABS_BRAKE, bitmask_abs);
+
+ if (has_abs_coordinates) {
+ if (stylus_or_pen)
+ is_tablet = true;
+ else if (finger_but_no_pen && !is_direct)
+ is_touchpad = true;
+ else if (has_mouse_button)
/* This path is taken by VMware's USB mouse, which has
* absolute axes, but no touch/pressure button. */
- is_mouse = 1;
- } else if (test_bit(BTN_TOUCH, bitmask_key)) {
- udev_builtin_add_property(dev, test, "ID_INPUT_TOUCHSCREEN", "1");
- ret = true;
- /* joysticks don't necessarily have to have buttons; e. g.
- * rudders/pedals are joystick-like, but buttonless; they have
- * other fancy axes */
- } else if (test_bit(BTN_TRIGGER, bitmask_key) ||
- test_bit(BTN_A, bitmask_key) ||
- test_bit(BTN_1, bitmask_key) ||
- test_bit(ABS_RX, bitmask_abs) ||
- test_bit(ABS_RY, bitmask_abs) ||
- test_bit(ABS_RZ, bitmask_abs) ||
- test_bit(ABS_THROTTLE, bitmask_abs) ||
- test_bit(ABS_RUDDER, bitmask_abs) ||
- test_bit(ABS_WHEEL, bitmask_abs) ||
- test_bit(ABS_GAS, bitmask_abs) ||
- test_bit(ABS_BRAKE, bitmask_abs)) {
- udev_builtin_add_property(dev, test, "ID_INPUT_JOYSTICK", "1");
- ret = true;
- }
+ is_mouse = true;
+ else if (has_touch)
+ is_touchscreen = true;
+ else if (has_joystick_axes_or_buttons)
+ is_joystick = true;
}
+ if (has_mt_coordinates && is_direct)
+ is_touchscreen = true;
- if (test_bit(INPUT_PROP_POINTING_STICK, bitmask_props)) {
- udev_builtin_add_property(dev, test, "ID_INPUT_POINTINGSTICK", "1");
- ret = true;
- }
+ if (has_rel_coordinates && has_mouse_button)
+ is_mouse = true;
- if (test_bit(EV_REL, bitmask_ev) &&
- test_bit(REL_X, bitmask_rel) && test_bit(REL_Y, bitmask_rel) &&
- test_bit(BTN_MOUSE, bitmask_key))
- is_mouse = 1;
-
- if (is_mouse) {
+ if (is_pointing_stick)
+ udev_builtin_add_property(dev, test, "ID_INPUT_POINTINGSTICK", "1");
+ if (is_mouse)
udev_builtin_add_property(dev, test, "ID_INPUT_MOUSE", "1");
- ret = true;
- }
- if (is_touchpad) {
+ if (is_touchpad)
udev_builtin_add_property(dev, test, "ID_INPUT_TOUCHPAD", "1");
- ret = true;
- }
-
- return ret;
+ if (is_touchscreen)
+ udev_builtin_add_property(dev, test, "ID_INPUT_TOUCHSCREEN", "1");
+ if (is_joystick)
+ udev_builtin_add_property(dev, test, "ID_INPUT_JOYSTICK", "1");
+ if (is_tablet)
+ udev_builtin_add_property(dev, test, "ID_INPUT_TABLET", "1");
+
+ return is_tablet || is_mouse || is_touchpad || is_touchscreen || is_joystick || is_pointing_stick;
}
/* key like devices */
@@ -268,6 +288,8 @@ static int builtin_input_id(struct udev_device *dev, int argc, char *argv[], boo
bool is_pointer;
bool is_key;
+ assert(dev);
+
/* walk up the parental chain until we find the real input device; the
* argument is very likely a subdevice of this, like eventN */
pdev = dev;
diff --git a/src/udev/udev-builtin-keyboard.c b/src/udev/udev-builtin-keyboard.c
index ed990c58fb..01f3879f37 100644
--- a/src/udev/udev-builtin-keyboard.c
+++ b/src/udev/udev-builtin-keyboard.c
@@ -37,6 +37,9 @@ static int install_force_release(struct udev_device *dev, const unsigned *releas
unsigned i;
int ret;
+ assert(dev);
+ assert(release);
+
atkbd = udev_device_get_parent_with_subsystem_devtype(dev, "serio", NULL);
if (!atkbd)
return -ENODEV;
@@ -152,6 +155,9 @@ static void set_trackpoint_sensitivity(struct udev_device *dev, const char *valu
char val_s[DECIMAL_STR_MAX(int)];
int r, val_i;
+ assert(dev);
+ assert(value);
+
/* The sensitivity sysfs attr belongs to the serio parent device */
pdev = udev_device_get_parent_with_subsystem_devtype(dev, "serio", NULL);
if (!pdev) {
diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c
index 78aef206b2..6e7e1271fb 100644
--- a/src/udev/udev-builtin-net_id.c
+++ b/src/udev/udev-builtin-net_id.c
@@ -91,6 +91,7 @@
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
+#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <net/if.h>
@@ -166,15 +167,15 @@ static int dev_pci_onboard(struct udev_device *dev, struct netnames *names) {
/* read the 256 bytes PCI configuration space to check the multi-function bit */
static bool is_pci_multifunction(struct udev_device *dev) {
- _cleanup_fclose_ FILE *f = NULL;
+ _cleanup_close_ int fd = -1;
const char *filename;
uint8_t config[64];
filename = strjoina(udev_device_get_syspath(dev), "/config");
- f = fopen(filename, "re");
- if (!f)
+ fd = open(filename, O_RDONLY | O_CLOEXEC);
+ if (fd < 0)
return false;
- if (fread(&config, sizeof(config), 1, f) != 1)
+ if (read(fd, &config, sizeof(config)) != sizeof(config))
return false;
/* bit 0-6 header type, bit 7 multi/single function device */
@@ -275,6 +276,9 @@ out:
static int names_pci(struct udev_device *dev, struct netnames *names) {
struct udev_device *parent;
+ assert(dev);
+ assert(names);
+
parent = udev_device_get_parent(dev);
if (!parent)
return -ENOENT;
@@ -301,6 +305,9 @@ static int names_usb(struct udev_device *dev, struct netnames *names) {
size_t l;
char *s;
+ assert(dev);
+ assert(names);
+
usbdev = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_interface");
if (!usbdev)
return -ENOENT;
@@ -349,6 +356,9 @@ static int names_bcma(struct udev_device *dev, struct netnames *names) {
struct udev_device *bcmadev;
unsigned int core;
+ assert(dev);
+ assert(names);
+
bcmadev = udev_device_get_parent_with_subsystem_devtype(dev, "bcma", NULL);
if (!bcmadev)
return -ENOENT;
@@ -370,6 +380,9 @@ static int names_ccw(struct udev_device *dev, struct netnames *names) {
size_t bus_id_len;
int rc;
+ assert(dev);
+ assert(names);
+
/* Retrieve the associated CCW device */
cdev = udev_device_get_parent(dev);
if (!cdev)
diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c
index b6749aab76..4ca0a69d7d 100644
--- a/src/udev/udev-builtin-path_id.c
+++ b/src/udev/udev-builtin-path_id.c
@@ -77,6 +77,9 @@ static int format_lun_number(struct udev_device *dev, char **path) {
static struct udev_device *skip_subsystem(struct udev_device *dev, const char *subsys) {
struct udev_device *parent = dev;
+ assert(dev);
+ assert(subsys);
+
while (parent != NULL) {
const char *subsystem;
@@ -96,6 +99,9 @@ static struct udev_device *handle_scsi_fibre_channel(struct udev_device *parent,
const char *port;
char *lun = NULL;
+ assert(parent);
+ assert(path);
+
targetdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_target");
if (targetdev == NULL)
return NULL;
@@ -126,6 +132,9 @@ static struct udev_device *handle_scsi_sas_wide_port(struct udev_device *parent,
const char *sas_address;
char *lun = NULL;
+ assert(parent);
+ assert(path);
+
targetdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_target");
if (targetdev == NULL)
return NULL;
@@ -169,6 +178,9 @@ static struct udev_device *handle_scsi_sas(struct udev_device *parent, char **pa
const char *phy_count;
char *lun = NULL;
+ assert(parent);
+ assert(path);
+
targetdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_target");
if (targetdev == NULL)
return NULL;
@@ -259,6 +271,9 @@ static struct udev_device *handle_scsi_iscsi(struct udev_device *parent, char **
const char *port;
char *lun = NULL;
+ assert(parent);
+ assert(path);
+
/* find iscsi session */
transportdev = parent;
for (;;) {
@@ -316,6 +331,9 @@ static struct udev_device *handle_scsi_default(struct udev_device *parent, char
struct dirent *dent;
int basenum;
+ assert(parent);
+ assert(path);
+
hostdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_host");
if (hostdev == NULL)
return NULL;
@@ -398,6 +416,9 @@ static struct udev_device *handle_scsi_hyperv(struct udev_device *parent, char *
char guid[38];
size_t i, k;
+ assert(parent);
+ assert(path);
+
hostdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_host");
if (!hostdev)
return NULL;
@@ -555,6 +576,10 @@ static struct udev_device *handle_bcma(struct udev_device *parent, char **path)
static struct udev_device *handle_ccw(struct udev_device *parent, struct udev_device *dev, char **path) {
struct udev_device *scsi_dev;
+ assert(parent);
+ assert(dev);
+ assert(path);
+
scsi_dev = udev_device_get_parent_with_subsystem_devtype(dev, "scsi", "scsi_device");
if (scsi_dev != NULL) {
const char *wwpn;
@@ -582,6 +607,8 @@ static int builtin_path_id(struct udev_device *dev, int argc, char *argv[], bool
bool supported_transport = false;
bool supported_parent = false;
+ assert(dev);
+
/* S390 ccw bus */
parent = udev_device_get_parent_with_subsystem_devtype(dev, "ccw", NULL);
if (parent != NULL) {
@@ -638,7 +665,8 @@ static int builtin_path_id(struct udev_device *dev, int argc, char *argv[], bool
supported_parent = true;
}
- parent = udev_device_get_parent(parent);
+ if (parent)
+ parent = udev_device_get_parent(parent);
}
/*
diff --git a/src/udev/udev-builtin-usb_id.c b/src/udev/udev-builtin-usb_id.c
index 462efc5c86..d309dc31cb 100644
--- a/src/udev/udev-builtin-usb_id.c
+++ b/src/udev/udev-builtin-usb_id.c
@@ -252,6 +252,8 @@ static int builtin_usb_id(struct udev_device *dev, int argc, char *argv[], bool
size_t l;
char *s;
+ assert(dev);
+
/* shortcut, if we are called directly for a "usb_device" type */
if (udev_device_get_devtype(dev) != NULL && streq(udev_device_get_devtype(dev), "usb_device")) {
dev_if_packed_info(dev, packed_if_str, sizeof(packed_if_str));
diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c
index 2fa26a40be..5516a792eb 100644
--- a/src/udev/udev-event.c
+++ b/src/udev/udev-event.c
@@ -30,9 +30,20 @@
#include <sys/wait.h>
#include <sys/signalfd.h>
-#include "udev.h"
-#include "rtnl-util.h"
+#include "netlink-util.h"
+#include "event-util.h"
#include "formats-util.h"
+#include "process-util.h"
+#include "signal-util.h"
+#include "udev.h"
+
+typedef struct Spawn {
+ const char *cmd;
+ pid_t pid;
+ usec_t timeout_warn;
+ usec_t timeout;
+ bool accept_failure;
+} Spawn;
struct udev_event *udev_event_new(struct udev_device *dev) {
struct udev *udev = udev_device_get_udev(dev);
@@ -45,15 +56,14 @@ struct udev_event *udev_event_new(struct udev_device *dev) {
event->udev = udev;
udev_list_init(udev, &event->run_list, false);
udev_list_init(udev, &event->seclabel_list, false);
- event->fd_signal = -1;
- event->birth_usec = now(CLOCK_MONOTONIC);
+ event->birth_usec = clock_boottime_or_monotonic();
return event;
}
void udev_event_unref(struct udev_event *event) {
if (event == NULL)
return;
- sd_rtnl_unref(event->rtnl);
+ sd_netlink_unref(event->rtnl);
udev_list_cleanup(&event->run_list);
udev_list_cleanup(&event->seclabel_list);
free(event->program_result);
@@ -110,6 +120,8 @@ size_t udev_event_apply_format(struct udev_event *event, const char *src, char *
char *s;
size_t l;
+ assert(dev);
+
from = src;
s = dest;
l = size;
@@ -374,7 +386,7 @@ out:
}
static int spawn_exec(struct udev_event *event,
- const char *cmd, char *const argv[], char **envp, const sigset_t *sigmask,
+ const char *cmd, char *const argv[], char **envp,
int fd_stdout, int fd_stderr) {
_cleanup_close_ int fd = -1;
@@ -402,9 +414,8 @@ static int spawn_exec(struct udev_event *event,
/* terminate child in case parent goes away */
prctl(PR_SET_PDEATHSIG, SIGTERM);
- /* restore original udev sigmask before exec */
- if (sigmask)
- sigprocmask(SIG_SETMASK, sigmask, NULL);
+ /* restore sigmask before exec */
+ (void) reset_signal_mask();
execve(argv[0], argv, envp);
@@ -467,7 +478,7 @@ static void spawn_read(struct udev_event *event,
if (timeout_usec > 0) {
usec_t age_usec;
- age_usec = now(CLOCK_MONOTONIC) - event->birth_usec;
+ age_usec = clock_boottime_or_monotonic() - event->birth_usec;
if (age_usec >= timeout_usec) {
log_error("timeout '%s'", cmd);
return;
@@ -540,102 +551,119 @@ static void spawn_read(struct udev_event *event,
result[respos] = '\0';
}
+static int on_spawn_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
+ Spawn *spawn = userdata;
+ char timeout[FORMAT_TIMESTAMP_RELATIVE_MAX];
+
+ assert(spawn);
+
+ kill_and_sigcont(spawn->pid, SIGKILL);
+
+ log_error("spawned process '%s' ["PID_FMT"] timed out after %s, killing", spawn->cmd, spawn->pid,
+ format_timestamp_relative(timeout, sizeof(timeout), spawn->timeout));
+
+ return 1;
+}
+
+static int on_spawn_timeout_warning(sd_event_source *s, uint64_t usec, void *userdata) {
+ Spawn *spawn = userdata;
+ char timeout[FORMAT_TIMESTAMP_RELATIVE_MAX];
+
+ assert(spawn);
+
+ log_warning("spawned process '%s' ["PID_FMT"] is taking longer than %s to complete", spawn->cmd, spawn->pid,
+ format_timestamp_relative(timeout, sizeof(timeout), spawn->timeout));
+
+ return 1;
+}
+
+static int on_spawn_sigchld(sd_event_source *s, const siginfo_t *si, void *userdata) {
+ Spawn *spawn = userdata;
+
+ assert(spawn);
+
+ switch (si->si_code) {
+ case CLD_EXITED:
+ if (si->si_status == 0) {
+ log_debug("Process '%s' succeeded.", spawn->cmd);
+ sd_event_exit(sd_event_source_get_event(s), 0);
+
+ return 1;
+ } else if (spawn->accept_failure)
+ log_debug("Process '%s' failed with exit code %i.", spawn->cmd, si->si_status);
+ else
+ log_warning("Process '%s' failed with exit code %i.", spawn->cmd, si->si_status);
+
+ break;
+ case CLD_KILLED:
+ case CLD_DUMPED:
+ log_warning("Process '%s' terminated by signal %s.", spawn->cmd, signal_to_string(si->si_status));
+
+ break;
+ default:
+ log_error("Process '%s' failed due to unknown reason.", spawn->cmd);
+ }
+
+ sd_event_exit(sd_event_source_get_event(s), -EIO);
+
+ return 1;
+}
+
static int spawn_wait(struct udev_event *event,
usec_t timeout_usec,
usec_t timeout_warn_usec,
- const char *cmd, pid_t pid) {
- struct pollfd pfd[1];
- int err = 0;
-
- pfd[0].events = POLLIN;
- pfd[0].fd = event->fd_signal;
+ const char *cmd, pid_t pid,
+ bool accept_failure) {
+ Spawn spawn = {
+ .cmd = cmd,
+ .pid = pid,
+ .accept_failure = accept_failure,
+ };
+ _cleanup_event_unref_ sd_event *e = NULL;
+ int r, ret;
- while (pid > 0) {
- int timeout;
- int timeout_warn = 0;
- int fdcount;
+ r = sd_event_new(&e);
+ if (r < 0)
+ return r;
- if (timeout_usec > 0) {
- usec_t age_usec;
+ if (timeout_usec > 0) {
+ usec_t usec, age_usec;
- age_usec = now(CLOCK_MONOTONIC) - event->birth_usec;
- if (age_usec >= timeout_usec)
- timeout = 1000;
- else {
- if (timeout_warn_usec > 0)
- timeout_warn = ((timeout_warn_usec - age_usec) / USEC_PER_MSEC) + MSEC_PER_SEC;
+ usec = now(clock_boottime_or_monotonic());
+ age_usec = usec - event->birth_usec;
+ if (age_usec < timeout_usec) {
+ if (timeout_warn_usec > 0 && timeout_warn_usec < timeout_usec && age_usec < timeout_warn_usec) {
+ spawn.timeout_warn = timeout_warn_usec - age_usec;
- timeout = ((timeout_usec - timeout_warn_usec - age_usec) / USEC_PER_MSEC) + MSEC_PER_SEC;
+ r = sd_event_add_time(e, NULL, clock_boottime_or_monotonic(),
+ usec + spawn.timeout_warn, USEC_PER_SEC,
+ on_spawn_timeout_warning, &spawn);
+ if (r < 0)
+ return r;
}
- } else {
- timeout = -1;
- }
- fdcount = poll(pfd, 1, timeout_warn);
- if (fdcount < 0) {
- if (errno == EINTR)
- continue;
- err = -errno;
- log_error_errno(errno, "failed to poll: %m");
- goto out;
- }
- if (fdcount == 0) {
- log_warning("slow: '%s' ["PID_FMT"]", cmd, pid);
+ spawn.timeout = timeout_usec - age_usec;
- fdcount = poll(pfd, 1, timeout);
- if (fdcount < 0) {
- if (errno == EINTR)
- continue;
- err = -errno;
- log_error_errno(errno, "failed to poll: %m");
- goto out;
- }
- if (fdcount == 0) {
- log_error("timeout: killing '%s' ["PID_FMT"]", cmd, pid);
- kill(pid, SIGKILL);
- }
+ r = sd_event_add_time(e, NULL, clock_boottime_or_monotonic(),
+ usec + spawn.timeout, USEC_PER_SEC, on_spawn_timeout, &spawn);
+ if (r < 0)
+ return r;
}
+ }
- if (pfd[0].revents & POLLIN) {
- struct signalfd_siginfo fdsi;
- int status;
- ssize_t size;
+ r = sd_event_add_child(e, NULL, pid, WEXITED, on_spawn_sigchld, &spawn);
+ if (r < 0)
+ return r;
- size = read(event->fd_signal, &fdsi, sizeof(struct signalfd_siginfo));
- if (size != sizeof(struct signalfd_siginfo))
- continue;
+ r = sd_event_loop(e);
+ if (r < 0)
+ return r;
- switch (fdsi.ssi_signo) {
- case SIGTERM:
- event->sigterm = true;
- break;
- case SIGCHLD:
- if (waitpid(pid, &status, WNOHANG) < 0)
- break;
- if (WIFEXITED(status)) {
- log_debug("'%s' ["PID_FMT"] exit with return code %i", cmd, pid, WEXITSTATUS(status));
- if (WEXITSTATUS(status) != 0)
- err = -1;
- } else if (WIFSIGNALED(status)) {
- log_error("'%s' ["PID_FMT"] terminated by signal %i (%s)", cmd, pid, WTERMSIG(status), strsignal(WTERMSIG(status)));
- err = -1;
- } else if (WIFSTOPPED(status)) {
- log_error("'%s' ["PID_FMT"] stopped", cmd, pid);
- err = -1;
- } else if (WIFCONTINUED(status)) {
- log_error("'%s' ["PID_FMT"] continued", cmd, pid);
- err = -1;
- } else {
- log_error("'%s' ["PID_FMT"] exit with status 0x%04x", cmd, pid, status);
- err = -1;
- }
- pid = 0;
- break;
- }
- }
- }
-out:
- return err;
+ r = sd_event_get_exit_code(e, &ret);
+ if (r < 0)
+ return r;
+
+ return ret;
}
int udev_build_argv(struct udev *udev, char *cmd, int *argc, char *argv[]) {
@@ -674,7 +702,8 @@ out:
int udev_event_spawn(struct udev_event *event,
usec_t timeout_usec,
usec_t timeout_warn_usec,
- const char *cmd, char **envp, const sigset_t *sigmask,
+ bool accept_failure,
+ const char *cmd, char **envp,
char *result, size_t ressize) {
int outpipe[2] = {-1, -1};
int errpipe[2] = {-1, -1};
@@ -724,7 +753,7 @@ int udev_event_spawn(struct udev_event *event,
log_debug("starting '%s'", cmd);
- spawn_exec(event, cmd, argv, envp, sigmask,
+ spawn_exec(event, cmd, argv, envp,
outpipe[WRITE_END], errpipe[WRITE_END]);
_exit(2 );
@@ -749,7 +778,7 @@ int udev_event_spawn(struct udev_event *event,
outpipe[READ_END], errpipe[READ_END],
result, ressize);
- err = spawn_wait(event, timeout_usec, timeout_warn_usec, cmd, pid);
+ err = spawn_wait(event, timeout_usec, timeout_warn_usec, cmd, pid, accept_failure);
}
out:
@@ -786,8 +815,7 @@ static int rename_netif(struct udev_event *event) {
void udev_event_execute_rules(struct udev_event *event,
usec_t timeout_usec, usec_t timeout_warn_usec,
struct udev_list *properties_list,
- struct udev_rules *rules,
- const sigset_t *sigmask) {
+ struct udev_rules *rules) {
struct udev_device *dev = event->dev;
if (udev_device_get_subsystem(dev) == NULL)
@@ -803,8 +831,7 @@ void udev_event_execute_rules(struct udev_event *event,
udev_rules_apply_to_event(rules, event,
timeout_usec, timeout_warn_usec,
- properties_list,
- sigmask);
+ properties_list);
if (major(udev_device_get_devnum(dev)) != 0)
udev_node_remove(dev);
@@ -822,8 +849,7 @@ void udev_event_execute_rules(struct udev_event *event,
udev_rules_apply_to_event(rules, event,
timeout_usec, timeout_warn_usec,
- properties_list,
- sigmask);
+ properties_list);
/* rename a new network interface, if needed */
if (udev_device_get_ifindex(dev) > 0 && streq(udev_device_get_action(dev), "add") &&
@@ -886,7 +912,7 @@ void udev_event_execute_rules(struct udev_event *event,
}
}
-void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec, usec_t timeout_warn_usec, const sigset_t *sigmask) {
+void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec, usec_t timeout_warn_usec) {
struct udev_list_entry *list_entry;
udev_list_entry_foreach(list_entry, udev_list_get_entry(&event->run_list)) {
@@ -909,7 +935,7 @@ void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec, usec_
udev_event_apply_format(event, cmd, program, sizeof(program));
envp = udev_device_get_properties_envp(event->dev);
- udev_event_spawn(event, timeout_usec, timeout_warn_usec, program, envp, sigmask, NULL, 0);
+ udev_event_spawn(event, timeout_usec, timeout_warn_usec, false, program, envp, NULL, 0);
}
}
}
diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c
index 4262119886..8ebc061eb1 100644
--- a/src/udev/udev-rules.c
+++ b/src/udev/udev-rules.c
@@ -633,7 +633,7 @@ static int import_file_into_properties(struct udev_device *dev, const char *file
static int import_program_into_properties(struct udev_event *event,
usec_t timeout_usec,
usec_t timeout_warn_usec,
- const char *program, const sigset_t *sigmask) {
+ const char *program) {
struct udev_device *dev = event->dev;
char **envp;
char result[UTIL_LINE_SIZE];
@@ -641,7 +641,7 @@ static int import_program_into_properties(struct udev_event *event,
int err;
envp = udev_device_get_properties_envp(dev);
- err = udev_event_spawn(event, timeout_usec, timeout_warn_usec, program, envp, sigmask, result, sizeof(result));
+ err = udev_event_spawn(event, timeout_usec, timeout_warn_usec, true, program, envp, result, sizeof(result));
if (err < 0)
return err;
@@ -664,6 +664,9 @@ static int import_parent_into_properties(struct udev_device *dev, const char *fi
struct udev_device *dev_parent;
struct udev_list_entry *list_entry;
+ assert(dev);
+ assert(filter);
+
dev_parent = udev_device_get_parent(dev);
if (dev_parent == NULL)
return -1;
@@ -1892,8 +1895,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules,
struct udev_event *event,
usec_t timeout_usec,
usec_t timeout_warn_usec,
- struct udev_list *properties_list,
- const sigset_t *sigmask) {
+ struct udev_list *properties_list) {
struct token *cur;
struct token *rule;
enum escape_type esc = ESCAPE_UNSET;
@@ -1939,7 +1941,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules,
udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(event->dev)) {
const char *devlink;
- devlink = udev_list_entry_get_name(list_entry) + strlen("/dev/");
+ devlink = udev_list_entry_get_name(list_entry) + strlen("/dev/");
if (match_key(rules, cur, devlink) == 0) {
match = true;
break;
@@ -2129,7 +2131,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules,
rules_str(rules, rule->rule.filename_off),
rule->rule.filename_line);
- if (udev_event_spawn(event, timeout_usec, timeout_warn_usec, program, envp, sigmask, result, sizeof(result)) < 0) {
+ if (udev_event_spawn(event, timeout_usec, timeout_warn_usec, true, program, envp, result, sizeof(result)) < 0) {
if (cur->key.op != OP_NOMATCH)
goto nomatch;
} else {
@@ -2165,7 +2167,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules,
rules_str(rules, rule->rule.filename_off),
rule->rule.filename_line);
- if (import_program_into_properties(event, timeout_usec, timeout_warn_usec, import, sigmask) != 0)
+ if (import_program_into_properties(event, timeout_usec, timeout_warn_usec, import) != 0)
if (cur->key.op != OP_NOMATCH)
goto nomatch;
break;
diff --git a/src/udev/udev.h b/src/udev/udev.h
index dece6eccab..3dca72e499 100644
--- a/src/udev/udev.h
+++ b/src/udev/udev.h
@@ -20,10 +20,9 @@
#include <sys/types.h>
#include <sys/param.h>
-#include <signal.h>
#include "macro.h"
-#include "sd-rtnl.h"
+#include "sd-netlink.h"
#include "libudev.h"
#include "libudev-private.h"
#include "util.h"
@@ -44,11 +43,9 @@ struct udev_event {
struct udev_list run_list;
int exec_delay;
usec_t birth_usec;
- int fd_signal;
- sd_rtnl *rtnl;
+ sd_netlink *rtnl;
unsigned int builtin_run;
unsigned int builtin_ret;
- bool sigterm;
bool inotify_watch;
bool inotify_watch_final;
bool group_set;
@@ -75,8 +72,7 @@ struct udev_rules *udev_rules_unref(struct udev_rules *rules);
bool udev_rules_check_timestamp(struct udev_rules *rules);
int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event,
usec_t timeout_usec, usec_t timeout_warn_usec,
- struct udev_list *properties_list,
- const sigset_t *sigmask);
+ struct udev_list *properties_list);
int udev_rules_apply_static_dev_perms(struct udev_rules *rules);
/* udev-event.c */
@@ -88,14 +84,14 @@ int udev_event_apply_subsys_kernel(struct udev_event *event, const char *string,
int udev_event_spawn(struct udev_event *event,
usec_t timeout_usec,
usec_t timeout_warn_usec,
- const char *cmd, char **envp, const sigset_t *sigmask,
+ bool accept_failure,
+ const char *cmd, char **envp,
char *result, size_t ressize);
void udev_event_execute_rules(struct udev_event *event,
usec_t timeout_usec, usec_t timeout_warn_usec,
struct udev_list *properties_list,
- struct udev_rules *rules,
- const sigset_t *sigset);
-void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec, usec_t timeout_warn_usec, const sigset_t *sigset);
+ struct udev_rules *rules);
+void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec, usec_t timeout_warn_usec);
int udev_build_argv(struct udev *udev, char *cmd, int *argc, char *argv[]);
/* udev-watch.c */
diff --git a/src/udev/udevadm-test.c b/src/udev/udevadm-test.c
index fe092cfbd9..d04e618d0d 100644
--- a/src/udev/udevadm-test.c
+++ b/src/udev/udevadm-test.c
@@ -131,18 +131,11 @@ static int adm_test(struct udev *udev, int argc, char *argv[]) {
sigfillset(&mask);
sigprocmask(SIG_SETMASK, &mask, &sigmask_orig);
- event->fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
- if (event->fd_signal < 0) {
- fprintf(stderr, "error creating signalfd\n");
- rc = 5;
- goto out;
- }
udev_event_execute_rules(event,
60 * USEC_PER_SEC, 20 * USEC_PER_SEC,
NULL,
- rules,
- &sigmask_orig);
+ rules);
udev_list_entry_foreach(entry, udev_device_get_properties_list_entry(dev))
printf("%s=%s\n", udev_list_entry_get_name(entry), udev_list_entry_get_value(entry));
@@ -154,8 +147,6 @@ static int adm_test(struct udev *udev, int argc, char *argv[]) {
printf("run: '%s'\n", program);
}
out:
- if (event != NULL && event->fd_signal >= 0)
- close(event->fd_signal);
udev_builtin_exit(udev);
return rc;
}
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index afd4640ad1..c205f1d5ec 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -41,7 +41,12 @@
#include <sys/inotify.h>
#include "sd-daemon.h"
-#include "rtnl-util.h"
+#include "sd-event.h"
+
+#include "terminal-util.h"
+#include "signal-util.h"
+#include "event-util.h"
+#include "netlink-util.h"
#include "cgroup-util.h"
#include "process-util.h"
#include "dev-setup.h"
@@ -62,11 +67,11 @@ static usec_t arg_event_timeout_warn_usec = 180 * USEC_PER_SEC / 3;
typedef struct Manager {
struct udev *udev;
+ sd_event *event;
Hashmap *workers;
struct udev_list_node events;
- char *cgroup;
+ const char *cgroup;
pid_t pid; /* the process that originally allocated the manager object */
- sigset_t sigmask_orig;
struct udev_rules *rules;
struct udev_list properties;
@@ -74,17 +79,16 @@ typedef struct Manager {
struct udev_monitor *monitor;
struct udev_ctrl *ctrl;
struct udev_ctrl_connection *ctrl_conn_blocking;
-
- int fd_ep;
- int fd_ctrl;
- int fd_uevent;
- int fd_signal;
int fd_inotify;
- int fd_worker;
int worker_watch[2];
+ sd_event_source *ctrl_event;
+ sd_event_source *uevent_event;
+ sd_event_source *inotify_event;
+
+ usec_t last_usec;
+
bool stop_exec_queue:1;
- bool reload:1;
bool exit:1;
} Manager;
@@ -110,8 +114,8 @@ struct event {
dev_t devnum;
int ifindex;
bool is_block;
- usec_t start_usec;
- bool warned;
+ sd_event_source *timeout_warning;
+ sd_event_source *timeout;
};
static inline struct event *node_to_event(struct udev_list_node *node) {
@@ -151,6 +155,9 @@ static void event_free(struct event *event) {
udev_device_unref(event->dev);
udev_device_unref(event->dev_kernel);
+ sd_event_source_unref(event->timeout_warning);
+ sd_event_source_unref(event->timeout);
+
if (event->worker)
event->worker->event = NULL;
@@ -252,7 +259,12 @@ static int on_event_timeout_warning(sd_event_source *s, uint64_t usec, void *use
}
static void worker_attach_event(struct worker *worker, struct event *event) {
+ sd_event *e;
+ uint64_t usec;
+ int r;
+
assert(worker);
+ assert(worker->manager);
assert(event);
assert(!event->worker);
assert(!worker->event);
@@ -260,9 +272,19 @@ static void worker_attach_event(struct worker *worker, struct event *event) {
worker->state = WORKER_RUNNING;
worker->event = event;
event->state = EVENT_RUNNING;
- event->start_usec = now(CLOCK_MONOTONIC);
- event->warned = false;
event->worker = worker;
+
+ e = worker->manager->event;
+
+ r = sd_event_now(e, clock_boottime_or_monotonic(), &usec);
+ if (r < 0)
+ return;
+
+ (void) sd_event_add_time(e, &event->timeout_warning, clock_boottime_or_monotonic(),
+ usec + arg_event_timeout_warn_usec, USEC_PER_SEC, on_event_timeout_warning, event);
+
+ (void) sd_event_add_time(e, &event->timeout, clock_boottime_or_monotonic(),
+ usec + arg_event_timeout_usec, USEC_PER_SEC, on_event_timeout, event);
}
static void manager_free(Manager *manager) {
@@ -271,7 +293,12 @@ static void manager_free(Manager *manager) {
udev_builtin_exit(manager->udev);
+ sd_event_source_unref(manager->ctrl_event);
+ sd_event_source_unref(manager->uevent_event);
+ sd_event_source_unref(manager->inotify_event);
+
udev_unref(manager->udev);
+ sd_event_unref(manager->event);
manager_workers_free(manager);
event_queue_cleanup(manager, EVENT_UNDEF);
@@ -281,10 +308,7 @@ static void manager_free(Manager *manager) {
udev_list_cleanup(&manager->properties);
udev_rules_unref(manager->rules);
- free(manager->cgroup);
- safe_close(manager->fd_ep);
- safe_close(manager->fd_signal);
safe_close(manager->fd_inotify);
safe_close_pair(manager->worker_watch);
@@ -316,10 +340,11 @@ static void worker_spawn(Manager *manager, struct event *event) {
switch (pid) {
case 0: {
struct udev_device *dev = NULL;
+ _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
int fd_monitor;
_cleanup_close_ int fd_signal = -1, fd_ep = -1;
- _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
- struct epoll_event ep_signal, ep_monitor;
+ struct epoll_event ep_signal = { .events = EPOLLIN };
+ struct epoll_event ep_monitor = { .events = EPOLLIN };
sigset_t mask;
int r = 0;
@@ -327,13 +352,22 @@ static void worker_spawn(Manager *manager, struct event *event) {
dev = event->dev;
event->dev = NULL;
+ unsetenv("NOTIFY_SOCKET");
+
manager_workers_free(manager);
event_queue_cleanup(manager, EVENT_UNDEF);
+
manager->monitor = udev_monitor_unref(manager->monitor);
+ manager->ctrl_conn_blocking = udev_ctrl_connection_unref(manager->ctrl_conn_blocking);
manager->ctrl = udev_ctrl_unref(manager->ctrl);
- manager->fd_signal = safe_close(manager->fd_signal);
+ manager->ctrl_conn_blocking = udev_ctrl_connection_unref(manager->ctrl_conn_blocking);
manager->worker_watch[READ_END] = safe_close(manager->worker_watch[READ_END]);
- manager->fd_ep = safe_close(manager->fd_ep);
+
+ manager->ctrl_event = sd_event_source_unref(manager->ctrl_event);
+ manager->uevent_event = sd_event_source_unref(manager->uevent_event);
+ manager->inotify_event = sd_event_source_unref(manager->inotify_event);
+
+ manager->event = sd_event_unref(manager->event);
sigfillset(&mask);
fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
@@ -341,6 +375,10 @@ static void worker_spawn(Manager *manager, struct event *event) {
r = log_error_errno(errno, "error creating signalfd %m");
goto out;
}
+ ep_signal.data.fd = fd_signal;
+
+ fd_monitor = udev_monitor_get_fd(worker_monitor);
+ ep_monitor.data.fd = fd_monitor;
fd_ep = epoll_create1(EPOLL_CLOEXEC);
if (fd_ep < 0) {
@@ -348,15 +386,6 @@ static void worker_spawn(Manager *manager, struct event *event) {
goto out;
}
- memzero(&ep_signal, sizeof(struct epoll_event));
- ep_signal.events = EPOLLIN;
- ep_signal.data.fd = fd_signal;
-
- fd_monitor = udev_monitor_get_fd(worker_monitor);
- memzero(&ep_monitor, sizeof(struct epoll_event));
- ep_monitor.events = EPOLLIN;
- ep_monitor.data.fd = fd_monitor;
-
if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_signal, &ep_signal) < 0 ||
epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_monitor, &ep_monitor) < 0) {
r = log_error_errno(errno, "fail to add fds to epoll: %m");
@@ -373,6 +402,8 @@ static void worker_spawn(Manager *manager, struct event *event) {
struct udev_event *udev_event;
int fd_lock = -1;
+ assert(dev);
+
log_debug("seq %llu running", udev_device_get_seqnum(dev));
udev_event = udev_event_new(dev);
if (udev_event == NULL) {
@@ -380,9 +411,6 @@ static void worker_spawn(Manager *manager, struct event *event) {
goto out;
}
- /* needed for SIGCHLD/SIGTERM in spawn() */
- udev_event->fd_signal = fd_signal;
-
if (arg_exec_delay > 0)
udev_event->exec_delay = arg_exec_delay;
@@ -408,7 +436,6 @@ static void worker_spawn(Manager *manager, struct event *event) {
if (fd_lock >= 0 && flock(fd_lock, LOCK_SH|LOCK_NB) < 0) {
log_debug_errno(errno, "Unable to flock(%s), skipping event handling: %m", udev_device_get_devnode(d));
fd_lock = safe_close(fd_lock);
- r = -EAGAIN;
goto skip;
}
}
@@ -421,16 +448,14 @@ static void worker_spawn(Manager *manager, struct event *event) {
udev_event_execute_rules(udev_event,
arg_event_timeout_usec, arg_event_timeout_warn_usec,
&manager->properties,
- manager->rules,
- &manager->sigmask_orig);
+ manager->rules);
udev_event_execute_run(udev_event,
- arg_event_timeout_usec, arg_event_timeout_warn_usec,
- &manager->sigmask_orig);
+ arg_event_timeout_usec, arg_event_timeout_warn_usec);
if (udev_event->rtnl)
/* in case rtnl was initialized */
- rtnl = sd_rtnl_ref(udev_event->rtnl);
+ rtnl = sd_netlink_ref(udev_event->rtnl);
/* apply/restore inotify watch */
if (udev_event->inotify_watch) {
@@ -455,11 +480,6 @@ skip:
udev_device_unref(dev);
dev = NULL;
- if (udev_event->sigterm) {
- udev_event_unref(udev_event);
- goto out;
- }
-
udev_event_unref(udev_event);
/* wait for more device messages from main udevd, or term signal */
@@ -564,7 +584,10 @@ static int event_queue_insert(Manager *manager, struct udev_device *dev) {
assert(manager);
assert(dev);
- /* only the main process can add events to the queue */
+ /* only one process can add events to the queue */
+ if (manager->pid == 0)
+ manager->pid = getpid();
+
assert(manager->pid == getpid());
event = new0(struct event, 1);
@@ -687,11 +710,104 @@ static bool is_devpath_busy(Manager *manager, struct event *event) {
return false;
}
+static int on_exit_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
+ Manager *manager = userdata;
+
+ assert(manager);
+
+ log_error_errno(ETIMEDOUT, "giving up waiting for workers to finish");
+
+ sd_event_exit(manager->event, -ETIMEDOUT);
+
+ return 1;
+}
+
+static void manager_exit(Manager *manager) {
+ uint64_t usec;
+ int r;
+
+ assert(manager);
+
+ manager->exit = true;
+
+ sd_notify(false,
+ "STOPPING=1\n"
+ "STATUS=Starting shutdown...");
+
+ /* close sources of new events and discard buffered events */
+ manager->ctrl_event = sd_event_source_unref(manager->ctrl_event);
+ manager->ctrl = udev_ctrl_unref(manager->ctrl);
+
+ manager->inotify_event = sd_event_source_unref(manager->inotify_event);
+ manager->fd_inotify = safe_close(manager->fd_inotify);
+
+ manager->uevent_event = sd_event_source_unref(manager->uevent_event);
+ manager->monitor = udev_monitor_unref(manager->monitor);
+
+ /* discard queued events and kill workers */
+ event_queue_cleanup(manager, EVENT_QUEUED);
+ manager_kill_workers(manager);
+
+ r = sd_event_now(manager->event, clock_boottime_or_monotonic(), &usec);
+ if (r < 0)
+ return;
+
+ r = sd_event_add_time(manager->event, NULL, clock_boottime_or_monotonic(),
+ usec + 30 * USEC_PER_SEC, USEC_PER_SEC, on_exit_timeout, manager);
+ if (r < 0)
+ return;
+}
+
+/* reload requested, HUP signal received, rules changed, builtin changed */
+static void manager_reload(Manager *manager) {
+
+ assert(manager);
+
+ sd_notify(false,
+ "RELOADING=1\n"
+ "STATUS=Flushing configuration...");
+
+ manager_kill_workers(manager);
+ manager->rules = udev_rules_unref(manager->rules);
+ udev_builtin_exit(manager->udev);
+
+ sd_notify(false,
+ "READY=1\n"
+ "STATUS=Processing...");
+}
+
static void event_queue_start(Manager *manager) {
struct udev_list_node *loop;
+ usec_t usec;
+ int r;
assert(manager);
+ if (udev_list_node_is_empty(&manager->events) ||
+ manager->exit || manager->stop_exec_queue)
+ return;
+
+ r = sd_event_now(manager->event, clock_boottime_or_monotonic(), &usec);
+ if (r >= 0) {
+ /* check for changed config, every 3 seconds at most */
+ if (manager->last_usec == 0 ||
+ (usec - manager->last_usec) > 3 * USEC_PER_SEC) {
+ if (udev_rules_check_timestamp(manager->rules) ||
+ udev_builtin_validate(manager->udev))
+ manager_reload(manager);
+
+ manager->last_usec = usec;
+ }
+ }
+
+ udev_builtin_init(manager->udev);
+
+ if (!manager->rules) {
+ manager->rules = udev_rules_new(manager->udev, arg_resolve_names);
+ if (!manager->rules)
+ return;
+ }
+
udev_list_node_foreach(loop, &manager->events) {
struct event *event = node_to_event(loop);
@@ -759,7 +875,7 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
continue;
}
- for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) {
+ CMSG_FOREACH(cmsg, &msghdr) {
if (cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SCM_CREDENTIALS &&
cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)))
@@ -785,6 +901,9 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
event_free(worker->event);
}
+ /* we have free workers, try to schedule events */
+ event_queue_start(manager);
+
return 1;
}
@@ -801,6 +920,9 @@ static int on_uevent(sd_event_source *s, int fd, uint32_t revents, void *userdat
r = event_queue_insert(manager, dev);
if (r < 0)
udev_device_unref(dev);
+ else
+ /* we have fresh events, try to schedule them */
+ event_queue_start(manager);
}
return 1;
@@ -839,11 +961,12 @@ static int on_ctrl_msg(sd_event_source *s, int fd, uint32_t revents, void *userd
if (udev_ctrl_get_start_exec_queue(ctrl_msg) > 0) {
log_debug("udevd message (START_EXEC_QUEUE) received");
manager->stop_exec_queue = false;
+ event_queue_start(manager);
}
if (udev_ctrl_get_reload(ctrl_msg) > 0) {
log_debug("udevd message (RELOAD) received");
- manager->reload = true;
+ manager_reload(manager);
}
str = udev_ctrl_get_set_env(ctrl_msg);
@@ -882,7 +1005,7 @@ static int on_ctrl_msg(sd_event_source *s, int fd, uint32_t revents, void *userd
if (udev_ctrl_get_exit(ctrl_msg) > 0) {
log_debug("udevd message (EXIT) received");
- manager->exit = true;
+ manager_exit(manager);
/* keep reference to block the client until we exit
TODO: deal with several blocking exit requests */
manager->ctrl_conn_blocking = udev_ctrl_connection_ref(ctrl_conn);
@@ -1040,7 +1163,7 @@ static int on_sigterm(sd_event_source *s, const struct signalfd_siginfo *si, voi
assert(manager);
- manager->exit = true;
+ manager_exit(manager);
return 1;
}
@@ -1050,7 +1173,7 @@ static int on_sighup(sd_event_source *s, const struct signalfd_siginfo *si, void
assert(manager);
- manager->reload = true;
+ manager_reload(manager);
return 1;
}
@@ -1105,41 +1228,124 @@ static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, voi
worker_free(worker);
}
+ /* we can start new workers, try to schedule events */
+ event_queue_start(manager);
+
+ return 1;
+}
+
+static int on_post(sd_event_source *s, void *userdata) {
+ Manager *manager = userdata;
+ int r;
+
+ assert(manager);
+
+ if (udev_list_node_is_empty(&manager->events)) {
+ /* no pending events */
+ if (!hashmap_isempty(manager->workers)) {
+ /* there are idle workers */
+ log_debug("cleanup idle workers");
+ manager_kill_workers(manager);
+ } else {
+ /* we are idle */
+ if (manager->exit) {
+ r = sd_event_exit(manager->event, 0);
+ if (r < 0)
+ return r;
+ } else if (manager->cgroup)
+ /* cleanup possible left-over processes in our cgroup */
+ cg_kill(SYSTEMD_CGROUP_CONTROLLER, manager->cgroup, SIGKILL, false, true, NULL);
+ }
+ }
+
return 1;
}
-static int systemd_fds(int *rctrl, int *rnetlink) {
- int ctrl = -1, netlink = -1;
- int fd, n;
+static int listen_fds(int *rctrl, int *rnetlink) {
+ _cleanup_udev_unref_ struct udev *udev = NULL;
+ int ctrl_fd = -1, netlink_fd = -1;
+ int fd, n, r;
+
+ assert(rctrl);
+ assert(rnetlink);
n = sd_listen_fds(true);
- if (n <= 0)
- return -1;
+ if (n < 0)
+ return n;
for (fd = SD_LISTEN_FDS_START; fd < n + SD_LISTEN_FDS_START; fd++) {
if (sd_is_socket(fd, AF_LOCAL, SOCK_SEQPACKET, -1)) {
- if (ctrl >= 0)
- return -1;
- ctrl = fd;
+ if (ctrl_fd >= 0)
+ return -EINVAL;
+ ctrl_fd = fd;
continue;
}
if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1)) {
- if (netlink >= 0)
- return -1;
- netlink = fd;
+ if (netlink_fd >= 0)
+ return -EINVAL;
+ netlink_fd = fd;
continue;
}
- return -1;
+ return -EINVAL;
+ }
+
+ if (ctrl_fd < 0) {
+ _cleanup_udev_ctrl_unref_ struct udev_ctrl *ctrl = NULL;
+
+ udev = udev_new();
+ if (!udev)
+ return -ENOMEM;
+
+ ctrl = udev_ctrl_new(udev);
+ if (!ctrl)
+ return log_error_errno(EINVAL, "error initializing udev control socket");
+
+ r = udev_ctrl_enable_receiving(ctrl);
+ if (r < 0)
+ return log_error_errno(EINVAL, "error binding udev control socket");
+
+ fd = udev_ctrl_get_fd(ctrl);
+ if (fd < 0)
+ return log_error_errno(EIO, "could not get ctrl fd");
+
+ ctrl_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
+ if (ctrl_fd < 0)
+ return log_error_errno(errno, "could not dup ctrl fd: %m");
+ }
+
+ if (netlink_fd < 0) {
+ _cleanup_udev_monitor_unref_ struct udev_monitor *monitor = NULL;
+
+ if (!udev) {
+ udev = udev_new();
+ if (!udev)
+ return -ENOMEM;
+ }
+
+ monitor = udev_monitor_new_from_netlink(udev, "kernel");
+ if (!monitor)
+ return log_error_errno(EINVAL, "error initializing netlink socket");
+
+ (void) udev_monitor_set_receive_buffer_size(monitor, 128 * 1024 * 1024);
+
+ r = udev_monitor_enable_receiving(monitor);
+ if (r < 0)
+ return log_error_errno(EINVAL, "error binding netlink socket");
+
+ fd = udev_monitor_get_fd(monitor);
+ if (fd < 0)
+ return log_error_errno(netlink_fd, "could not get uevent fd: %m");
+
+ netlink_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
+ if (ctrl_fd < 0)
+ return log_error_errno(errno, "could not dup netlink fd: %m");
}
- if (ctrl < 0 || netlink < 0)
- return -1;
+ *rctrl = ctrl_fd;
+ *rnetlink = netlink_fd;
- log_debug("ctrl=%i netlink=%i", ctrl, netlink);
- *rctrl = ctrl;
- *rnetlink = netlink;
return 0;
}
@@ -1284,28 +1490,18 @@ static int parse_argv(int argc, char *argv[]) {
return 1;
}
-static int manager_new(Manager **ret) {
+static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cgroup) {
_cleanup_(manager_freep) Manager *manager = NULL;
- struct epoll_event ep_ctrl = { .events = EPOLLIN };
- struct epoll_event ep_inotify = { .events = EPOLLIN };
- struct epoll_event ep_signal = { .events = EPOLLIN };
- struct epoll_event ep_netlink = { .events = EPOLLIN };
- struct epoll_event ep_worker = { .events = EPOLLIN };
- sigset_t mask;
- int r, one = 1;
+ int r, fd_worker, one = 1;
assert(ret);
+ assert(fd_ctrl >= 0);
+ assert(fd_uevent >= 0);
manager = new0(Manager, 1);
if (!manager)
return log_oom();
- manager->pid = getpid();
-
- manager->fd_ep = -1;
- manager->fd_ctrl = -1;
- manager->fd_uevent = -1;
- manager->fd_signal = -1;
manager->fd_inotify = -1;
manager->worker_watch[WRITE_END] = -1;
manager->worker_watch[READ_END] = -1;
@@ -1323,54 +1519,24 @@ static int manager_new(Manager **ret) {
udev_list_node_init(&manager->events);
udev_list_init(manager->udev, &manager->properties, true);
- r = systemd_fds(&manager->fd_ctrl, &manager->fd_uevent);
- if (r >= 0) {
- /* get control and netlink socket from systemd */
- manager->ctrl = udev_ctrl_new_from_fd(manager->udev, manager->fd_ctrl);
- if (!manager->ctrl)
- return log_error_errno(EINVAL, "error taking over udev control socket");
-
- manager->monitor = udev_monitor_new_from_netlink_fd(manager->udev, "kernel", manager->fd_uevent);
- if (!manager->monitor)
- return log_error_errno(EINVAL, "error taking over netlink socket");
-
- /* get our own cgroup, we regularly kill everything udev has left behind */
- r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 0, &manager->cgroup);
- if (r < 0)
- log_warning_errno(r, "failed to get cgroup: %m");
- } else {
- /* open control and netlink socket */
- manager->ctrl = udev_ctrl_new(manager->udev);
- if (!manager->ctrl)
- return log_error_errno(EINVAL, "error initializing udev control socket");
-
- manager->fd_ctrl = udev_ctrl_get_fd(manager->ctrl);
-
- manager->monitor = udev_monitor_new_from_netlink(manager->udev, "kernel");
- if (!manager->monitor)
- return log_error_errno(EINVAL, "error initializing netlink socket");
-
- manager->fd_uevent = udev_monitor_get_fd(manager->monitor);
-
- (void) udev_monitor_set_receive_buffer_size(manager->monitor, 128 * 1024 * 1024);
- }
+ manager->cgroup = cgroup;
- r = udev_monitor_enable_receiving(manager->monitor);
- if (r < 0)
- return log_error_errno(EINVAL, "error binding netlink socket");
+ manager->ctrl = udev_ctrl_new_from_fd(manager->udev, fd_ctrl);
+ if (!manager->ctrl)
+ return log_error_errno(EINVAL, "error taking over udev control socket");
- r = udev_ctrl_enable_receiving(manager->ctrl);
- if (r < 0)
- return log_error_errno(EINVAL, "error binding udev control socket");
+ manager->monitor = udev_monitor_new_from_netlink_fd(manager->udev, "kernel", fd_uevent);
+ if (!manager->monitor)
+ return log_error_errno(EINVAL, "error taking over netlink socket");
/* unnamed socket from workers to the main daemon */
r = socketpair(AF_LOCAL, SOCK_DGRAM|SOCK_CLOEXEC, 0, manager->worker_watch);
if (r < 0)
return log_error_errno(errno, "error creating socketpair: %m");
- manager->fd_worker = manager->worker_watch[READ_END];
+ fd_worker = manager->worker_watch[READ_END];
- r = setsockopt(manager->fd_worker, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
+ r = setsockopt(fd_worker, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
if (r < 0)
return log_error_errno(errno, "could not enable SO_PASSCRED: %m");
@@ -1381,38 +1547,70 @@ static int manager_new(Manager **ret) {
udev_watch_restore(manager->udev);
/* block and listen to all signals on signalfd */
- sigfillset(&mask);
- sigprocmask(SIG_SETMASK, &mask, &manager->sigmask_orig);
- manager->fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
- if (manager->fd_signal < 0)
- return log_error_errno(errno, "error creating signalfd");
-
- ep_ctrl.data.fd = manager->fd_ctrl;
- ep_inotify.data.fd = manager->fd_inotify;
- ep_signal.data.fd = manager->fd_signal;
- ep_netlink.data.fd = manager->fd_uevent;
- ep_worker.data.fd = manager->fd_worker;
-
- manager->fd_ep = epoll_create1(EPOLL_CLOEXEC);
- if (manager->fd_ep < 0)
- return log_error_errno(errno, "error creating epoll fd: %m");
-
- if (epoll_ctl(manager->fd_ep, EPOLL_CTL_ADD, manager->fd_ctrl, &ep_ctrl) < 0 ||
- epoll_ctl(manager->fd_ep, EPOLL_CTL_ADD, manager->fd_inotify, &ep_inotify) < 0 ||
- epoll_ctl(manager->fd_ep, EPOLL_CTL_ADD, manager->fd_signal, &ep_signal) < 0 ||
- epoll_ctl(manager->fd_ep, EPOLL_CTL_ADD, manager->fd_uevent, &ep_netlink) < 0 ||
- epoll_ctl(manager->fd_ep, EPOLL_CTL_ADD, manager->fd_worker, &ep_worker) < 0)
- return log_error_errno(errno, "fail to add fds to epoll: %m");
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGHUP, SIGCHLD, -1) >= 0);
+
+ r = sd_event_default(&manager->event);
+ if (r < 0)
+ return log_error_errno(errno, "could not allocate event loop: %m");
+
+ r = sd_event_add_signal(manager->event, NULL, SIGINT, on_sigterm, manager);
+ if (r < 0)
+ return log_error_errno(r, "error creating sigint event source: %m");
+
+ r = sd_event_add_signal(manager->event, NULL, SIGTERM, on_sigterm, manager);
+ if (r < 0)
+ return log_error_errno(r, "error creating sigterm event source: %m");
+
+ r = sd_event_add_signal(manager->event, NULL, SIGHUP, on_sighup, manager);
+ if (r < 0)
+ return log_error_errno(r, "error creating sighup event source: %m");
+
+ r = sd_event_add_signal(manager->event, NULL, SIGCHLD, on_sigchld, manager);
+ if (r < 0)
+ return log_error_errno(r, "error creating sigchld event source: %m");
+
+ r = sd_event_set_watchdog(manager->event, true);
+ if (r < 0)
+ return log_error_errno(r, "error creating watchdog event source: %m");
+
+ r = sd_event_add_io(manager->event, &manager->ctrl_event, fd_ctrl, EPOLLIN, on_ctrl_msg, manager);
+ if (r < 0)
+ return log_error_errno(r, "error creating ctrl event source: %m");
+
+ /* This needs to be after the inotify and uevent handling, to make sure
+ * that the ping is send back after fully processing the pending uevents
+ * (including the synthetic ones we may create due to inotify events).
+ */
+ r = sd_event_source_set_priority(manager->ctrl_event, SD_EVENT_PRIORITY_IDLE);
+ if (r < 0)
+ return log_error_errno(r, "cold not set IDLE event priority for ctrl event source: %m");
+
+ r = sd_event_add_io(manager->event, &manager->inotify_event, manager->fd_inotify, EPOLLIN, on_inotify, manager);
+ if (r < 0)
+ return log_error_errno(r, "error creating inotify event source: %m");
+
+ r = sd_event_add_io(manager->event, &manager->uevent_event, fd_uevent, EPOLLIN, on_uevent, manager);
+ if (r < 0)
+ return log_error_errno(r, "error creating uevent event source: %m");
+
+ r = sd_event_add_io(manager->event, NULL, fd_worker, EPOLLIN, on_worker, manager);
+ if (r < 0)
+ return log_error_errno(r, "error creating worker event source: %m");
+
+ r = sd_event_add_post(manager->event, NULL, on_post, manager);
+ if (r < 0)
+ return log_error_errno(r, "error creating post event source: %m");
*ret = manager;
manager = NULL;
- return 1;
+ return 0;
}
int main(int argc, char *argv[]) {
_cleanup_(manager_freep) Manager *manager = NULL;
- int r;
+ _cleanup_free_ char *cgroup = NULL;
+ int r, fd_ctrl, fd_uevent;
log_set_target(LOG_TARGET_AUTO);
log_parse_environment();
@@ -1440,29 +1638,12 @@ int main(int argc, char *argv[]) {
arg_children_max = 8;
if (sched_getaffinity(0, sizeof (cpu_set), &cpu_set) == 0) {
- arg_children_max += CPU_COUNT(&cpu_set) * 2;
+ arg_children_max += CPU_COUNT(&cpu_set) * 2;
}
log_debug("set children_max to %u", arg_children_max);
}
- /* before opening new files, make sure std{in,out,err} fds are in a sane state */
- if (arg_daemonize) {
- int fd;
-
- fd = open("/dev/null", O_RDWR);
- if (fd < 0)
- log_error("cannot open /dev/null");
- else {
- if (write(STDOUT_FILENO, 0, 0) < 0)
- dup2(fd, STDOUT_FILENO);
- if (write(STDERR_FILENO, 0, 0) < 0)
- dup2(fd, STDERR_FILENO);
- if (fd > STDERR_FILENO)
- close(fd);
- }
- }
-
/* set umask before creating any file/directory */
r = chdir("/");
if (r < 0) {
@@ -1486,19 +1667,30 @@ int main(int argc, char *argv[]) {
dev_setup(NULL, UID_INVALID, GID_INVALID);
- r = manager_new(&manager);
- if (r < 0)
- goto exit;
-
- log_info("starting version " VERSION);
+ if (getppid() == 1) {
+ /* get our own cgroup, we regularly kill everything udev has left behind
+ we only do this on systemd systems, and only if we are directly spawned
+ by PID1. otherwise we are not guaranteed to have a dedicated cgroup */
+ r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 0, &cgroup);
+ if (r < 0)
+ log_warning_errno(r, "failed to get cgroup: %m");
+ }
- r = udev_rules_apply_static_dev_perms(manager->rules);
- if (r < 0)
- log_error_errno(r, "failed to apply permissions on static device nodes: %m");
+ r = listen_fds(&fd_ctrl, &fd_uevent);
+ if (r < 0) {
+ r = log_error_errno(r, "could not listen on fds: %m");
+ goto exit;
+ }
if (arg_daemonize) {
pid_t pid;
+ log_info("starting version " VERSION);
+
+ /* connect /dev/null to stdin, stdout, stderr */
+ if (log_get_max_level() < LOG_DEBUG)
+ (void) make_null_stdio();
+
pid = fork();
switch (pid) {
case 0:
@@ -1515,188 +1707,35 @@ int main(int argc, char *argv[]) {
setsid();
write_string_file("/proc/self/oom_score_adj", "-1000");
- } else
- sd_notify(1, "READY=1");
-
- for (;;) {
- static usec_t last_usec;
- struct epoll_event ev[8];
- int fdcount;
- int timeout;
- bool is_worker, is_signal, is_inotify, is_uevent, is_ctrl;
- int i;
-
- if (manager->exit) {
- /* close sources of new events and discard buffered events */
- if (manager->fd_ctrl >= 0) {
- epoll_ctl(manager->fd_ep, EPOLL_CTL_DEL, manager->fd_ctrl, NULL);
- manager->fd_ctrl = safe_close(manager->fd_ctrl);
- }
-
- if (manager->monitor) {
- epoll_ctl(manager->fd_ep, EPOLL_CTL_DEL, manager->fd_uevent, NULL);
- manager->monitor = udev_monitor_unref(manager->monitor);
- }
-
- if (manager->fd_inotify >= 0) {
- epoll_ctl(manager->fd_ep, EPOLL_CTL_DEL, manager->fd_inotify, NULL);
- manager->fd_inotify = safe_close(manager->fd_inotify);
- }
-
- /* discard queued events and kill workers */
- event_queue_cleanup(manager, EVENT_QUEUED);
- manager_kill_workers(manager);
-
- /* exit after all has cleaned up */
- if (udev_list_node_is_empty(&manager->events) && hashmap_isempty(manager->workers))
- break;
-
- /* timeout at exit for workers to finish */
- timeout = 30 * MSEC_PER_SEC;
- } else if (udev_list_node_is_empty(&manager->events) && hashmap_isempty(manager->workers)) {
- /* we are idle */
- timeout = -1;
-
- /* cleanup possible left-over processes in our cgroup */
- if (manager->cgroup)
- cg_kill(SYSTEMD_CGROUP_CONTROLLER, manager->cgroup, SIGKILL, false, true, NULL);
- } else {
- /* kill idle or hanging workers */
- timeout = 3 * MSEC_PER_SEC;
- }
-
- fdcount = epoll_wait(manager->fd_ep, ev, ELEMENTSOF(ev), timeout);
- if (fdcount < 0)
- continue;
-
- if (fdcount == 0) {
- struct worker *worker;
- Iterator j;
-
- /* timeout */
- if (manager->exit) {
- log_error("timeout, giving up waiting for workers to finish");
- break;
- }
-
- /* kill idle workers */
- if (udev_list_node_is_empty(&manager->events)) {
- log_debug("cleanup idle workers");
- manager_kill_workers(manager);
- }
-
- /* check for hanging events */
- HASHMAP_FOREACH(worker, manager->workers, j) {
- struct event *event = worker->event;
- usec_t ts;
-
- if (worker->state != WORKER_RUNNING)
- continue;
-
- assert(event);
-
- ts = now(CLOCK_MONOTONIC);
-
- if ((ts - event->start_usec) > arg_event_timeout_warn_usec) {
- if ((ts - event->start_usec) > arg_event_timeout_usec)
- on_event_timeout(NULL, 0, event);
- else if (!event->warned) {
- on_event_timeout_warning(NULL, 0, event);
- event->warned = true;
- }
- }
- }
-
- }
-
- is_worker = is_signal = is_inotify = is_uevent = is_ctrl = false;
- for (i = 0; i < fdcount; i++) {
- if (ev[i].data.fd == manager->fd_worker && ev[i].events & EPOLLIN)
- is_worker = true;
- else if (ev[i].data.fd == manager->fd_uevent && ev[i].events & EPOLLIN)
- is_uevent = true;
- else if (ev[i].data.fd == manager->fd_signal && ev[i].events & EPOLLIN)
- is_signal = true;
- else if (ev[i].data.fd == manager->fd_inotify && ev[i].events & EPOLLIN)
- is_inotify = true;
- else if (ev[i].data.fd == manager->fd_ctrl && ev[i].events & EPOLLIN)
- is_ctrl = true;
- }
-
- /* check for changed config, every 3 seconds at most */
- if ((now(CLOCK_MONOTONIC) - last_usec) > 3 * USEC_PER_SEC) {
- if (udev_rules_check_timestamp(manager->rules))
- manager->reload = true;
- if (udev_builtin_validate(manager->udev))
- manager->reload = true;
-
- last_usec = now(CLOCK_MONOTONIC);
- }
-
- /* reload requested, HUP signal received, rules changed, builtin changed */
- if (manager->reload) {
- manager_kill_workers(manager);
- manager->rules = udev_rules_unref(manager->rules);
- udev_builtin_exit(manager->udev);
- manager->reload = false;
- }
-
- /* event has finished */
- if (is_worker)
- on_worker(NULL, manager->fd_worker, 0, manager);
-
- /* uevent from kernel */
- if (is_uevent)
- on_uevent(NULL, manager->fd_uevent, 0, manager);
-
- /* start new events */
- if (!udev_list_node_is_empty(&manager->events) && !manager->exit && !manager->stop_exec_queue) {
- udev_builtin_init(manager->udev);
- if (!manager->rules)
- manager->rules = udev_rules_new(manager->udev, arg_resolve_names);
- if (manager->rules)
- event_queue_start(manager);
- }
+ }
- if (is_signal) {
- struct signalfd_siginfo fdsi;
- ssize_t size;
-
- size = read(manager->fd_signal, &fdsi, sizeof(struct signalfd_siginfo));
- if (size == sizeof(struct signalfd_siginfo)) {
- switch (fdsi.ssi_signo) {
- case SIGINT:
- case SIGTERM:
- on_sigterm(NULL, &fdsi, manager);
- break;
- case SIGHUP:
- on_sighup(NULL, &fdsi, manager);
- break;
- case SIGCHLD:
- on_sigchld(NULL, &fdsi, manager);
- break;
- }
- }
- }
+ r = manager_new(&manager, fd_ctrl, fd_uevent, cgroup);
+ if (r < 0) {
+ r = log_error_errno(r, "failed to allocate manager object: %m");
+ goto exit;
+ }
- /* we are shutting down, the events below are not handled anymore */
- if (manager->exit)
- continue;
+ r = udev_rules_apply_static_dev_perms(manager->rules);
+ if (r < 0)
+ log_error_errno(r, "failed to apply permissions on static device nodes: %m");
- /* device node watch */
- if (is_inotify)
- on_inotify(NULL, manager->fd_inotify, 0, manager);
+ (void) sd_notify(false,
+ "READY=1\n"
+ "STATUS=Processing...");
- /*
- * This needs to be after the inotify handling, to make sure,
- * that the ping is send back after the possibly generated
- * "change" events by the inotify device node watch.
- */
- if (is_ctrl)
- on_ctrl_msg(NULL, manager->fd_ctrl, 0, manager);
+ r = sd_event_loop(manager->event);
+ if (r < 0) {
+ log_error_errno(r, "event loop failed: %m");
+ goto exit;
}
+ sd_event_get_exit_code(manager->event, &r);
+
exit:
+ sd_notify(false,
+ "STOPPING=1\n"
+ "STATUS=Shutting down...");
+
if (manager)
udev_ctrl_cleanup(manager->ctrl);
mac_selinux_finish();