diff --git a/.depend b/.depend index 013c8d4..d47c7ea 100644 --- a/.depend +++ b/.depend @@ -1,185 +1,221 @@ src/usb_moded-android.o:\ src/usb_moded-android.c\ - config-static.h\ src/usb_moded-android.h\ src/usb_moded-config-private.h\ src/usb_moded-config.h\ - src/usb_moded-dyn-config.h\ src/usb_moded-log.h\ src/usb_moded-mac.h\ src/usb_moded-modesetting.h\ - src/usb_moded.h\ src/usb_moded-android.pic.o:\ src/usb_moded-android.c\ - config-static.h\ src/usb_moded-android.h\ src/usb_moded-config-private.h\ src/usb_moded-config.h\ - src/usb_moded-dyn-config.h\ src/usb_moded-log.h\ src/usb_moded-mac.h\ src/usb_moded-modesetting.h\ - src/usb_moded.h\ src/usb_moded-appsync-dbus.o:\ src/usb_moded-appsync-dbus.c\ - config-static.h\ src/usb_moded-appsync-dbus-private.h\ src/usb_moded-appsync-dbus.h\ src/usb_moded-appsync.h\ - src/usb_moded-config-private.h\ - src/usb_moded-config.h\ - src/usb_moded-dbus-private.h\ - src/usb_moded-dbus.h\ - src/usb_moded-dyn-config.h\ src/usb_moded-log.h\ - src/usb_moded-modes.h\ - src/usb_moded.h\ src/usb_moded-appsync-dbus.pic.o:\ src/usb_moded-appsync-dbus.c\ - config-static.h\ src/usb_moded-appsync-dbus-private.h\ src/usb_moded-appsync-dbus.h\ src/usb_moded-appsync.h\ - src/usb_moded-config-private.h\ - src/usb_moded-config.h\ - src/usb_moded-dbus-private.h\ - src/usb_moded-dbus.h\ - src/usb_moded-dyn-config.h\ src/usb_moded-log.h\ - src/usb_moded-modes.h\ - src/usb_moded.h\ src/usb_moded-appsync.o:\ src/usb_moded-appsync.c\ - src/usb_moded-appsync-dbus-private.h\ - src/usb_moded-appsync-dbus.h\ src/usb_moded-appsync.h\ - src/usb_moded-dyn-config.h\ src/usb_moded-log.h\ - src/usb_moded-modesetting.h\ src/usb_moded-systemd.h\ src/usb_moded-appsync.pic.o:\ src/usb_moded-appsync.c\ - src/usb_moded-appsync-dbus-private.h\ - src/usb_moded-appsync-dbus.h\ src/usb_moded-appsync.h\ - src/usb_moded-dyn-config.h\ src/usb_moded-log.h\ - src/usb_moded-modesetting.h\ src/usb_moded-systemd.h\ +src/usb_moded-common.o:\ + src/usb_moded-common.c\ + config-static.h\ + src/usb_moded-common.h\ + src/usb_moded-config-private.h\ + src/usb_moded-config.h\ + src/usb_moded-dbus-private.h\ + src/usb_moded-dbus.h\ + src/usb_moded-dyn-config.h\ + src/usb_moded-log.h\ + src/usb_moded-modes.h\ + src/usb_moded-worker.h\ + src/usb_moded.h\ + +src/usb_moded-common.pic.o:\ + src/usb_moded-common.c\ + config-static.h\ + src/usb_moded-common.h\ + src/usb_moded-config-private.h\ + src/usb_moded-config.h\ + src/usb_moded-dbus-private.h\ + src/usb_moded-dbus.h\ + src/usb_moded-dyn-config.h\ + src/usb_moded-log.h\ + src/usb_moded-modes.h\ + src/usb_moded-worker.h\ + src/usb_moded.h\ + src/usb_moded-config.o:\ src/usb_moded-config.c\ config-static.h\ + src/usb_moded-common.h\ src/usb_moded-config-private.h\ src/usb_moded-config.h\ + src/usb_moded-control.h\ src/usb_moded-dbus-private.h\ src/usb_moded-dbus.h\ src/usb_moded-dyn-config.h\ src/usb_moded-log.h\ src/usb_moded-modes.h\ - src/usb_moded-modesetting.h\ src/usb_moded-ssu.h\ + src/usb_moded-worker.h\ src/usb_moded.h\ src/usb_moded-config.pic.o:\ src/usb_moded-config.c\ config-static.h\ + src/usb_moded-common.h\ src/usb_moded-config-private.h\ src/usb_moded-config.h\ + src/usb_moded-control.h\ src/usb_moded-dbus-private.h\ src/usb_moded-dbus.h\ src/usb_moded-dyn-config.h\ src/usb_moded-log.h\ src/usb_moded-modes.h\ - src/usb_moded-modesetting.h\ src/usb_moded-ssu.h\ + src/usb_moded-worker.h\ src/usb_moded.h\ src/usb_moded-configfs.o:\ src/usb_moded-configfs.c\ config-static.h\ src/usb_moded-android.h\ + src/usb_moded-common.h\ src/usb_moded-config-private.h\ src/usb_moded-config.h\ src/usb_moded-configfs.h\ - src/usb_moded-dyn-config.h\ src/usb_moded-log.h\ src/usb_moded-mac.h\ - src/usb_moded-modesetting.h\ src/usb_moded.h\ src/usb_moded-configfs.pic.o:\ src/usb_moded-configfs.c\ config-static.h\ src/usb_moded-android.h\ + src/usb_moded-common.h\ src/usb_moded-config-private.h\ src/usb_moded-config.h\ src/usb_moded-configfs.h\ - src/usb_moded-dyn-config.h\ src/usb_moded-log.h\ src/usb_moded-mac.h\ - src/usb_moded-modesetting.h\ + src/usb_moded.h\ + +src/usb_moded-control.o:\ + src/usb_moded-control.c\ + config-static.h\ + src/usb_moded-common.h\ + src/usb_moded-config-private.h\ + src/usb_moded-config.h\ + src/usb_moded-control.h\ + src/usb_moded-dbus-private.h\ + src/usb_moded-dbus.h\ + src/usb_moded-dyn-config.h\ + src/usb_moded-log.h\ + src/usb_moded-modes.h\ + src/usb_moded-worker.h\ + src/usb_moded.h\ + +src/usb_moded-control.pic.o:\ + src/usb_moded-control.c\ + config-static.h\ + src/usb_moded-common.h\ + src/usb_moded-config-private.h\ + src/usb_moded-config.h\ + src/usb_moded-control.h\ + src/usb_moded-dbus-private.h\ + src/usb_moded-dbus.h\ + src/usb_moded-dyn-config.h\ + src/usb_moded-log.h\ + src/usb_moded-modes.h\ + src/usb_moded-worker.h\ src/usb_moded.h\ src/usb_moded-dbus.o:\ src/usb_moded-dbus.c\ config-static.h\ + src/usb_moded-common.h\ src/usb_moded-config-private.h\ src/usb_moded-config.h\ + src/usb_moded-control.h\ src/usb_moded-dbus-private.h\ src/usb_moded-dbus.h\ src/usb_moded-dyn-config.h\ src/usb_moded-log.h\ src/usb_moded-modes.h\ - src/usb_moded-modesetting.h\ src/usb_moded-network.h\ src/usb_moded.h\ src/usb_moded-dbus.pic.o:\ src/usb_moded-dbus.c\ config-static.h\ + src/usb_moded-common.h\ src/usb_moded-config-private.h\ src/usb_moded-config.h\ + src/usb_moded-control.h\ src/usb_moded-dbus-private.h\ src/usb_moded-dbus.h\ src/usb_moded-dyn-config.h\ src/usb_moded-log.h\ src/usb_moded-modes.h\ - src/usb_moded-modesetting.h\ src/usb_moded-network.h\ src/usb_moded.h\ src/usb_moded-devicelock.o:\ src/usb_moded-devicelock.c\ config-static.h\ + src/usb_moded-common.h\ + src/usb_moded-control.h\ src/usb_moded-dbus-private.h\ + src/usb_moded-dbus.h\ src/usb_moded-devicelock.h\ - src/usb_moded-dyn-config.h\ src/usb_moded-log.h\ - src/usb_moded-modes.h\ src/usb_moded.h\ src/usb_moded-devicelock.pic.o:\ src/usb_moded-devicelock.c\ config-static.h\ + src/usb_moded-common.h\ + src/usb_moded-control.h\ src/usb_moded-dbus-private.h\ + src/usb_moded-dbus.h\ src/usb_moded-devicelock.h\ - src/usb_moded-dyn-config.h\ src/usb_moded-log.h\ - src/usb_moded-modes.h\ src/usb_moded.h\ src/usb_moded-dsme.o:\ src/usb_moded-dsme.c\ config-static.h\ + src/usb_moded-common.h\ + src/usb_moded-control.h\ src/usb_moded-dbus-private.h\ + src/usb_moded-dbus.h\ src/usb_moded-dsme.h\ - src/usb_moded-dyn-config.h\ src/usb_moded-log.h\ src/usb_moded-modesetting.h\ src/usb_moded.h\ @@ -187,9 +223,11 @@ src/usb_moded-dsme.o:\ src/usb_moded-dsme.pic.o:\ src/usb_moded-dsme.c\ config-static.h\ + src/usb_moded-common.h\ + src/usb_moded-control.h\ src/usb_moded-dbus-private.h\ + src/usb_moded-dbus.h\ src/usb_moded-dsme.h\ - src/usb_moded-dyn-config.h\ src/usb_moded-log.h\ src/usb_moded-modesetting.h\ src/usb_moded.h\ @@ -227,6 +265,7 @@ src/usb_moded-modesetting.o:\ config-static.h\ src/usb_moded-android.h\ src/usb_moded-appsync.h\ + src/usb_moded-common.h\ src/usb_moded-config-private.h\ src/usb_moded-config.h\ src/usb_moded-configfs.h\ @@ -234,10 +273,10 @@ src/usb_moded-modesetting.o:\ src/usb_moded-dbus.h\ src/usb_moded-dyn-config.h\ src/usb_moded-log.h\ - src/usb_moded-modes.h\ src/usb_moded-modesetting.h\ src/usb_moded-modules.h\ src/usb_moded-network.h\ + src/usb_moded-worker.h\ src/usb_moded.h\ src/usb_moded-modesetting.pic.o:\ @@ -245,6 +284,7 @@ src/usb_moded-modesetting.pic.o:\ config-static.h\ src/usb_moded-android.h\ src/usb_moded-appsync.h\ + src/usb_moded-common.h\ src/usb_moded-config-private.h\ src/usb_moded-config.h\ src/usb_moded-configfs.h\ @@ -252,58 +292,62 @@ src/usb_moded-modesetting.pic.o:\ src/usb_moded-dbus.h\ src/usb_moded-dyn-config.h\ src/usb_moded-log.h\ - src/usb_moded-modes.h\ src/usb_moded-modesetting.h\ src/usb_moded-modules.h\ src/usb_moded-network.h\ + src/usb_moded-worker.h\ src/usb_moded.h\ src/usb_moded-modules.o:\ src/usb_moded-modules.c\ - config-static.h\ - src/usb_moded-config.h\ - src/usb_moded-dbus-private.h\ - src/usb_moded-dbus.h\ - src/usb_moded-dyn-config.h\ src/usb_moded-log.h\ - src/usb_moded-modes.h\ - src/usb_moded-modesetting.h\ src/usb_moded-modules.h\ - src/usb_moded.h\ src/usb_moded-modules.pic.o:\ src/usb_moded-modules.c\ - config-static.h\ - src/usb_moded-config.h\ - src/usb_moded-dbus-private.h\ - src/usb_moded-dbus.h\ - src/usb_moded-dyn-config.h\ src/usb_moded-log.h\ - src/usb_moded-modes.h\ - src/usb_moded-modesetting.h\ src/usb_moded-modules.h\ - src/usb_moded.h\ src/usb_moded-network.o:\ src/usb_moded-network.c\ config-static.h\ + src/usb_moded-common.h\ src/usb_moded-config-private.h\ src/usb_moded-config.h\ + src/usb_moded-control.h\ src/usb_moded-dyn-config.h\ src/usb_moded-log.h\ src/usb_moded-modesetting.h\ src/usb_moded-network.h\ + src/usb_moded-worker.h\ src/usb_moded.h\ src/usb_moded-network.pic.o:\ src/usb_moded-network.c\ config-static.h\ + src/usb_moded-common.h\ src/usb_moded-config-private.h\ src/usb_moded-config.h\ + src/usb_moded-control.h\ src/usb_moded-dyn-config.h\ src/usb_moded-log.h\ src/usb_moded-modesetting.h\ src/usb_moded-network.h\ + src/usb_moded-worker.h\ + src/usb_moded.h\ + +src/usb_moded-sigpipe.o:\ + src/usb_moded-sigpipe.c\ + config-static.h\ + src/usb_moded-log.h\ + src/usb_moded-sigpipe.h\ + src/usb_moded.h\ + +src/usb_moded-sigpipe.pic.o:\ + src/usb_moded-sigpipe.c\ + config-static.h\ + src/usb_moded-log.h\ + src/usb_moded-sigpipe.h\ src/usb_moded.h\ src/usb_moded-ssu.o:\ @@ -318,88 +362,116 @@ src/usb_moded-ssu.pic.o:\ src/usb_moded-systemd.o:\ src/usb_moded-systemd.c\ - config-static.h\ src/usb_moded-dbus-private.h\ src/usb_moded-dbus.h\ - src/usb_moded-dyn-config.h\ src/usb_moded-log.h\ src/usb_moded-systemd.h\ - src/usb_moded.h\ src/usb_moded-systemd.pic.o:\ src/usb_moded-systemd.c\ - config-static.h\ src/usb_moded-dbus-private.h\ src/usb_moded-dbus.h\ - src/usb_moded-dyn-config.h\ src/usb_moded-log.h\ src/usb_moded-systemd.h\ - src/usb_moded.h\ src/usb_moded-trigger.o:\ src/usb_moded-trigger.c\ config-static.h\ + src/usb_moded-common.h\ src/usb_moded-config-private.h\ src/usb_moded-config.h\ - src/usb_moded-devicelock.h\ - src/usb_moded-dyn-config.h\ + src/usb_moded-control.h\ src/usb_moded-log.h\ - src/usb_moded-modesetting.h\ src/usb_moded-trigger.h\ - src/usb_moded-udev.h\ src/usb_moded.h\ src/usb_moded-trigger.pic.o:\ src/usb_moded-trigger.c\ config-static.h\ + src/usb_moded-common.h\ src/usb_moded-config-private.h\ src/usb_moded-config.h\ - src/usb_moded-devicelock.h\ - src/usb_moded-dyn-config.h\ + src/usb_moded-control.h\ src/usb_moded-log.h\ - src/usb_moded-modesetting.h\ src/usb_moded-trigger.h\ - src/usb_moded-udev.h\ src/usb_moded.h\ src/usb_moded-udev.o:\ src/usb_moded-udev.c\ config-static.h\ + src/usb_moded-common.h\ src/usb_moded-config-private.h\ src/usb_moded-config.h\ - src/usb_moded-dyn-config.h\ + src/usb_moded-control.h\ + src/usb_moded-dbus-private.h\ + src/usb_moded-dbus.h\ src/usb_moded-log.h\ - src/usb_moded-modes.h\ src/usb_moded-udev.h\ src/usb_moded.h\ src/usb_moded-udev.pic.o:\ src/usb_moded-udev.c\ config-static.h\ + src/usb_moded-common.h\ src/usb_moded-config-private.h\ src/usb_moded-config.h\ - src/usb_moded-dyn-config.h\ + src/usb_moded-control.h\ + src/usb_moded-dbus-private.h\ + src/usb_moded-dbus.h\ src/usb_moded-log.h\ - src/usb_moded-modes.h\ src/usb_moded-udev.h\ src/usb_moded.h\ src/usb_moded-util.o:\ src/usb_moded-util.c\ + src/usb_moded-dbus-private.h\ src/usb_moded-dbus.h\ src/usb_moded-util.pic.o:\ src/usb_moded-util.c\ + src/usb_moded-dbus-private.h\ src/usb_moded-dbus.h\ +src/usb_moded-worker.o:\ + src/usb_moded-worker.c\ + config-static.h\ + src/usb_moded-android.h\ + src/usb_moded-common.h\ + src/usb_moded-configfs.h\ + src/usb_moded-control.h\ + src/usb_moded-dyn-config.h\ + src/usb_moded-log.h\ + src/usb_moded-modes.h\ + src/usb_moded-modesetting.h\ + src/usb_moded-modules.h\ + src/usb_moded-worker.h\ + src/usb_moded.h\ + +src/usb_moded-worker.pic.o:\ + src/usb_moded-worker.c\ + config-static.h\ + src/usb_moded-android.h\ + src/usb_moded-common.h\ + src/usb_moded-configfs.h\ + src/usb_moded-control.h\ + src/usb_moded-dyn-config.h\ + src/usb_moded-log.h\ + src/usb_moded-modes.h\ + src/usb_moded-modesetting.h\ + src/usb_moded-modules.h\ + src/usb_moded-worker.h\ + src/usb_moded.h\ + src/usb_moded.o:\ src/usb_moded.c\ config-static.h\ src/usb_moded-android.h\ src/usb_moded-appsync.h\ + src/usb_moded-common.h\ src/usb_moded-config-private.h\ src/usb_moded-config.h\ src/usb_moded-configfs.h\ + src/usb_moded-control.h\ src/usb_moded-dbus-private.h\ src/usb_moded-dbus.h\ src/usb_moded-devicelock.h\ @@ -407,13 +479,14 @@ src/usb_moded.o:\ src/usb_moded-dyn-config.h\ src/usb_moded-log.h\ src/usb_moded-mac.h\ - src/usb_moded-modes.h\ src/usb_moded-modesetting.h\ src/usb_moded-modules.h\ src/usb_moded-network.h\ + src/usb_moded-sigpipe.h\ src/usb_moded-systemd.h\ src/usb_moded-trigger.h\ src/usb_moded-udev.h\ + src/usb_moded-worker.h\ src/usb_moded.h\ src/usb_moded.pic.o:\ @@ -421,9 +494,11 @@ src/usb_moded.pic.o:\ config-static.h\ src/usb_moded-android.h\ src/usb_moded-appsync.h\ + src/usb_moded-common.h\ src/usb_moded-config-private.h\ src/usb_moded-config.h\ src/usb_moded-configfs.h\ + src/usb_moded-control.h\ src/usb_moded-dbus-private.h\ src/usb_moded-dbus.h\ src/usb_moded-devicelock.h\ @@ -431,13 +506,14 @@ src/usb_moded.pic.o:\ src/usb_moded-dyn-config.h\ src/usb_moded-log.h\ src/usb_moded-mac.h\ - src/usb_moded-modes.h\ src/usb_moded-modesetting.h\ src/usb_moded-modules.h\ src/usb_moded-network.h\ + src/usb_moded-sigpipe.h\ src/usb_moded-systemd.h\ src/usb_moded-trigger.h\ src/usb_moded-udev.h\ + src/usb_moded-worker.h\ src/usb_moded.h\ utils/udev-search.o:\ diff --git a/Makefile.custom b/Makefile.custom index 2660fc4..8f3be87 100644 --- a/Makefile.custom +++ b/Makefile.custom @@ -169,10 +169,13 @@ LDLIBS += $(PKG_LDLIBS) # ---------------------------------------------------------------------------- usb_moded-OBJS += src/usb_moded.o + usb_moded-OBJS += src/usb_moded-android.o usb_moded-OBJS += src/usb_moded-appsync.o +usb_moded-OBJS += src/usb_moded-common.o usb_moded-OBJS += src/usb_moded-config.o usb_moded-OBJS += src/usb_moded-configfs.o +usb_moded-OBJS += src/usb_moded-control.o usb_moded-OBJS += src/usb_moded-dbus.o usb_moded-OBJS += src/usb_moded-devicelock.o usb_moded-OBJS += src/usb_moded-dsme.o @@ -182,10 +185,12 @@ usb_moded-OBJS += src/usb_moded-mac.o usb_moded-OBJS += src/usb_moded-modesetting.o usb_moded-OBJS += src/usb_moded-modules.o usb_moded-OBJS += src/usb_moded-network.o +usb_moded-OBJS += src/usb_moded-sigpipe.o usb_moded-OBJS += src/usb_moded-ssu.o usb_moded-OBJS += src/usb_moded-systemd.o usb_moded-OBJS += src/usb_moded-trigger.o usb_moded-OBJS += src/usb_moded-udev.o +usb_moded-OBJS += src/usb_moded-worker.o usb_moded : $(usb_moded-OBJS) $(CC) -o $@ $^ $(LDFLAGS) $(LDLIBS) @@ -217,8 +222,10 @@ usb_moded_util : $(usb_moded_util-OBJS) CLEAN_SOURCES += src/usb_moded-android.c CLEAN_SOURCES += src/usb_moded-appsync-dbus.c CLEAN_SOURCES += src/usb_moded-appsync.c +CLEAN_SOURCES += src/usb_moded-common.c CLEAN_SOURCES += src/usb_moded-config.c CLEAN_SOURCES += src/usb_moded-configfs.c +CLEAN_SOURCES += src/usb_moded-control.c CLEAN_SOURCES += src/usb_moded-dbus.c CLEAN_SOURCES += src/usb_moded-devicelock.c CLEAN_SOURCES += src/usb_moded-dsme.c @@ -228,11 +235,13 @@ CLEAN_SOURCES += src/usb_moded-mac.c CLEAN_SOURCES += src/usb_moded-modesetting.c CLEAN_SOURCES += src/usb_moded-modules.c CLEAN_SOURCES += src/usb_moded-network.c +CLEAN_SOURCES += src/usb_moded-sigpipe.c CLEAN_SOURCES += src/usb_moded-ssu.c CLEAN_SOURCES += src/usb_moded-systemd.c CLEAN_SOURCES += src/usb_moded-trigger.c CLEAN_SOURCES += src/usb_moded-udev.c CLEAN_SOURCES += src/usb_moded-util.c +CLEAN_SOURCES += src/usb_moded-worker.c CLEAN_SOURCES += src/usb_moded.c CLEAN_SOURCES += utils/udev-search.c @@ -241,8 +250,10 @@ CLEAN_HEADERS += src/usb_moded-appsync-dbus-private.h CLEAN_HEADERS += src/usb_moded-appsync-dbus.h CLEAN_HEADERS += src/usb_moded-appsync.h CLEAN_HEADERS += src/usb_moded-config-private.h +CLEAN_HEADERS += src/usb_moded-common.h CLEAN_HEADERS += src/usb_moded-config.h CLEAN_HEADERS += src/usb_moded-configfs.h +CLEAN_HEADERS += src/usb_moded-control.h CLEAN_HEADERS += src/usb_moded-dbus-private.h CLEAN_HEADERS += src/usb_moded-dbus.h CLEAN_HEADERS += src/usb_moded-devicelock.h @@ -254,10 +265,12 @@ CLEAN_HEADERS += src/usb_moded-modes.h CLEAN_HEADERS += src/usb_moded-modesetting.h CLEAN_HEADERS += src/usb_moded-modules.h CLEAN_HEADERS += src/usb_moded-network.h +CLEAN_HEADERS += src/usb_moded-sigpipe.h CLEAN_HEADERS += src/usb_moded-ssu.h CLEAN_HEADERS += src/usb_moded-systemd.h CLEAN_HEADERS += src/usb_moded-trigger.h CLEAN_HEADERS += src/usb_moded-udev.h +CLEAN_HEADERS += src/usb_moded-worker.h CLEAN_HEADERS += src/usb_moded.h # Files with whitespace issues @@ -326,3 +339,19 @@ clean:: distclean:: $(RM) -r RPMS installroot + +.SUFFIXES: %.trim +.PRECIOUS: %.trim + +include_trim:: include_trim_headers include_trim_sources + +%.trim : % + find_unneeded_includes.py $(CPPFLAGS) $(CFLAGS) -- $< + touch $@ + +include_trim_headers: $(patsubst %,%.trim,$(ALL_HEADERS)) + +include_trim_sources: $(patsubst %,%.trim,$(ALL_SOURCES)) + +distclean:: + $(RM) *.trim */*.trim diff --git a/src/Makefile.am b/src/Makefile.am index 7023607..451a6ce 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,5 @@ USB_MODED_CFLAGS += -D_GNU_SOURCE +USB_MODED_LIBS += -lpthread sbin_PROGRAMS = usb_moded \ usb_moded_util @@ -24,6 +25,8 @@ usb_moded_SOURCES = \ usb_moded-modules.h \ usb_moded-log.h \ usb_moded-log.c \ + usb_moded-common.c \ + usb_moded-common.h \ usb_moded-config.c \ usb_moded-config.h \ usb_moded-network.c \ @@ -39,8 +42,14 @@ usb_moded_SOURCES = \ usb_moded-modules.c \ usb_moded-configfs.c \ usb_moded-configfs.h \ + usb_moded-worker.h \ + usb_moded-worker.c \ usb_moded-android.h \ - usb_moded-android.c + usb_moded-android.c \ + usb_moded-sigpipe.h \ + usb_moded-sigpipe.c \ + usb_moded-control.h \ + usb_moded-control.c if USE_MER_SSU usb_moded_SOURCES += \ diff --git a/src/usb_moded-android.c b/src/usb_moded-android.c index 551b8a9..d903291 100644 --- a/src/usb_moded-android.c +++ b/src/usb_moded-android.c @@ -21,19 +21,17 @@ * 02110-1301 USA */ -#include -#include - -#include "usb_moded.h" #include "usb_moded-android.h" -#include "usb_moded-log.h" -#include "usb_moded-modesetting.h" + #include "usb_moded-config-private.h" +#include "usb_moded-log.h" #include "usb_moded-mac.h" +#include "usb_moded-modesetting.h" -#include -#include #include +#include +#include +#include /* ========================================================================= * * Functions diff --git a/src/usb_moded-android.h b/src/usb_moded-android.h index b9a92b2..be33870 100644 --- a/src/usb_moded-android.h +++ b/src/usb_moded-android.h @@ -25,6 +25,7 @@ # define USB_MODED_ANDROID_H_ # include +# include /* ========================================================================= * * Constants diff --git a/src/usb_moded-appsync-dbus-private.h b/src/usb_moded-appsync-dbus-private.h index 0d72fd7..1df7ef4 100644 --- a/src/usb_moded-appsync-dbus-private.h +++ b/src/usb_moded-appsync-dbus-private.h @@ -25,7 +25,9 @@ #ifndef USB_MODED_APPSYNC_DBUS_PRIVATE_H_ # define USB_MODED_APPSYNC_DBUS_PRIVATE_H_ -#include "usb_moded-appsync-dbus.h" +# include "usb_moded-appsync-dbus.h" // NOTRIM + +# include /* ========================================================================= * * Prototypes diff --git a/src/usb_moded-appsync-dbus.c b/src/usb_moded-appsync-dbus.c index 075acd5..042f4c5 100644 --- a/src/usb_moded-appsync-dbus.c +++ b/src/usb_moded-appsync-dbus.c @@ -25,20 +25,14 @@ * 02110-1301 USA */ -#include +#include "usb_moded-appsync-dbus-private.h" + +#include "usb_moded-appsync.h" +#include "usb_moded-log.h" + #include #include -#include -#include - -#include "usb_moded-dbus-private.h" -#include "usb_moded.h" -#include "usb_moded-log.h" -#include "usb_moded-modes.h" -#include "usb_moded-config-private.h" -#include "usb_moded-appsync.h" -#include "usb_moded-appsync-dbus-private.h" /* ========================================================================= * * Prototypes @@ -183,7 +177,7 @@ static DBusHandlerResult dbusappsync_msg_handler(DBusConnection *const connectio // could not parse method call args reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, member); } - else if( appsync_mark_active(use) < 0 ) + else if( appsync_mark_active(use, 1) < 0 ) { // name could not be marked active reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, member); diff --git a/src/usb_moded-appsync.c b/src/usb_moded-appsync.c index ae4e303..79d4bb8 100644 --- a/src/usb_moded-appsync.c +++ b/src/usb_moded-appsync.c @@ -26,42 +26,39 @@ * 02110-1301 USA */ -#include -#include -#include -#include -#include -#include -#include - -#include -#include - #include "usb_moded-appsync.h" -#include "usb_moded-appsync-dbus-private.h" -#include "usb_moded-modesetting.h" + #include "usb_moded-log.h" #include "usb_moded-systemd.h" +#include + +#include +#include + /* ========================================================================= * * Prototypes * ========================================================================= */ /* -- appsync -- */ -static void appsync_free_elem (struct list_elem *elem); +static void appsync_free_elem (list_elem_t *elem); static void appsync_free_elem_cb (gpointer elem, gpointer user_data); void appsync_free_appsync_list (void); static gint appsync_list_sort_func (gconstpointer a, gconstpointer b); void appsync_read_list (int diag); -static struct list_elem *appsync_read_file (const gchar *filename, int diag); +static list_elem_t *appsync_read_file (const gchar *filename, int diag); int appsync_activate_sync (const char *mode); int appsync_activate_sync_post (const char *mode); int appsync_mark_active (const gchar *name, int post); + +#ifdef APP_SYNC_DBUS static gboolean appsync_enumerate_usb_cb (gpointer data); static void appsync_start_enumerate_usb_timer (void); static void appsync_cancel_enumerate_usb_timer(void); static void appsync_enumerate_usb (void); +#endif + void appsync_stop_apps (int post); int appsync_stop (gboolean force); @@ -69,21 +66,21 @@ int appsync_stop (gboolean force); * Data * ========================================================================= */ -static GList *sync_list = NULL; +static GList *appsync_sync_list = NULL; -static guint enumerate_usb_id = 0; -static struct timeval sync_tv = {0, 0}; #ifdef APP_SYNC_DBUS -static int no_dbus = 0; +static guint appsync_enumerate_usb_id = 0; +static struct timeval appsync_sync_tv = {0, 0}; +static int appsync_no_dbus = 0; // enabled until disabled due to failures #else -static int no_dbus = 0; +static int appsync_no_dbus = 1; // always disabled #endif /* APP_SYNC_DBUS */ /* ========================================================================= * * Functions * ========================================================================= */ -static void appsync_free_elem(struct list_elem *elem) +static void appsync_free_elem(list_elem_t *elem) { g_free(elem->name); g_free(elem->launch); @@ -99,12 +96,12 @@ static void appsync_free_elem_cb(gpointer elem, gpointer user_data) void appsync_free_appsync_list(void) { - if( sync_list != 0 ) + if( appsync_sync_list != 0 ) { - /*g_list_free_full(sync_list, appsync_free_elem); */ - g_list_foreach (sync_list, appsync_free_elem_cb, NULL); - g_list_free (sync_list); - sync_list = 0; + /*g_list_free_full(appsync_sync_list, appsync_free_elem); */ + g_list_foreach (appsync_sync_list, appsync_free_elem_cb, NULL); + g_list_free (appsync_sync_list); + appsync_sync_list = 0; log_debug("Appsync list freed\n"); } } @@ -119,7 +116,7 @@ void appsync_read_list(int diag) GDir *confdir = 0; const gchar *dirname; - struct list_elem *list_item; + list_elem_t *list_item; appsync_free_appsync_list(); @@ -138,7 +135,7 @@ void appsync_read_list(int diag) { log_debug("Read file %s\n", dirname); if( (list_item = appsync_read_file(dirname, diag)) ) - sync_list = g_list_append(sync_list, list_item); + appsync_sync_list = g_list_append(appsync_sync_list, list_item); } cleanup: @@ -146,26 +143,26 @@ void appsync_read_list(int diag) /* sort list alphabetically so services for a mode * can be run in a certain order */ - sync_list=g_list_sort(sync_list, appsync_list_sort_func); + appsync_sync_list=g_list_sort(appsync_sync_list, appsync_list_sort_func); /* set up session bus connection if app sync in use * so we do not need to make the time consuming connect * operation at enumeration time ... */ - if( sync_list ) + if( appsync_sync_list ) { log_debug("Sync list valid\n"); -#ifdef APP_SYN_DBUS +#ifdef APP_SYNC_DBUS dbusappsync_init_connection(); #endif } } -static struct list_elem *appsync_read_file(const gchar *filename, int diag) +static list_elem_t *appsync_read_file(const gchar *filename, int diag) { gchar *full_filename = NULL; GKeyFile *settingsfile = NULL; - struct list_elem *list_item = NULL; + list_elem_t *list_item = NULL; if(diag) { @@ -223,21 +220,25 @@ int appsync_activate_sync(const char *mode) log_debug("activate sync"); +#ifdef APP_SYNC_DBUS /* Get start of activation timestamp */ - gettimeofday(&sync_tv, 0); + gettimeofday(&appsync_sync_tv, 0); +#endif - if( sync_list == 0 ) + if( appsync_sync_list == 0 ) { - log_debug("No sync list! Enumerating\n"); + log_debug("No sync list!"); +#ifdef APP_SYNC_DBUS appsync_enumerate_usb(); +#endif return 0; } /* Count apps that need to be activated for this mode and * mark them as currently inactive */ - for( iter = sync_list; iter; iter = g_list_next(iter) ) + for( iter = appsync_sync_list; iter; iter = g_list_next(iter) ) { - struct list_elem *data = iter->data; + list_elem_t *data = iter->data; if(!strcmp(data->mode, mode)) { @@ -253,9 +254,11 @@ int appsync_activate_sync(const char *mode) /* If there is nothing to activate, enumerate immediately */ if(count <= 0) { - log_debug("Nothing to launch.\n"); + log_debug("Nothing to launch\n"); +#ifdef APP_SYNC_DBUS appsync_enumerate_usb(); - return(0); +#endif + return 0; } #ifdef APP_SYNC_DBUS @@ -263,17 +266,17 @@ int appsync_activate_sync(const char *mode) if(!dbusappsync_init()) { log_debug("dbus setup failed => skipping dbus launched apps \n"); - no_dbus = 1; + appsync_no_dbus = 1; } -#endif /* APP_SYNC_DBUS */ /* start timer */ appsync_start_enumerate_usb_timer(); +#endif /* go through list and launch apps */ - for( iter = sync_list; iter; iter = g_list_next(iter) ) + for( iter = appsync_sync_list; iter; iter = g_list_next(iter) ) { - struct list_elem *data = iter->data; + list_elem_t *data = iter->data; if(!strcmp(mode, data->mode)) { /* do not launch items marked as post, will be launched after usb is up */ @@ -292,12 +295,11 @@ int appsync_activate_sync(const char *mode) { /* skipping if dbus session bus is not available, * or not compiled in */ - if(no_dbus) + if(appsync_no_dbus) appsync_mark_active(data->name, 0); #ifdef APP_SYNC_DBUS - else - if(!dbusappsync_launch_app(data->launch)) - appsync_mark_active(data->name, 0); + else if(!dbusappsync_launch_app(data->launch)) + appsync_mark_active(data->name, 0); else goto error; #endif /* APP_SYNC_DBUS */ @@ -305,11 +307,11 @@ int appsync_activate_sync(const char *mode) } } - return(0); + return 0; error: log_warning("Error launching a service!\n"); - return(1); + return 1; } int appsync_activate_sync_post(const char *mode) @@ -318,7 +320,7 @@ int appsync_activate_sync_post(const char *mode) log_debug("activate post sync"); - if( sync_list == 0 ) + if( appsync_sync_list == 0 ) { log_debug("No sync list! skipping post sync\n"); return 0; @@ -329,14 +331,14 @@ int appsync_activate_sync_post(const char *mode) if(!dbusappsync_init()) { log_debug("dbus setup failed => skipping dbus launched apps \n"); - no_dbus = 1; + appsync_no_dbus = 1; } #endif /* APP_SYNC_DBUS */ /* go through list and launch apps */ - for( iter = sync_list; iter; iter = g_list_next(iter) ) + for( iter = appsync_sync_list; iter; iter = g_list_next(iter) ) { - struct list_elem *data = iter->data; + list_elem_t *data = iter->data; if(!strcmp(mode, data->mode)) { /* launch only items marked as post, others are already running */ @@ -353,22 +355,21 @@ int appsync_activate_sync_post(const char *mode) { /* skipping if dbus session bus is not available, * or not compiled in */ - if(no_dbus) + if(appsync_no_dbus) continue; #ifdef APP_SYNC_DBUS - else - if(dbusappsync_launch_app(data->launch) != 0) - goto error; + else if(dbusappsync_launch_app(data->launch) != 0) + goto error; #endif /* APP_SYNC_DBUS */ } } } - return(0); + return 0; error: log_warning("Error launching a service!\n"); - return(1); + return 1; } int appsync_mark_active(const gchar *name, int post) @@ -380,9 +381,9 @@ int appsync_mark_active(const gchar *name, int post) log_debug("%s-enum-app %s is started\n", post ? "post" : "pre", name); - for( iter = sync_list; iter; iter = g_list_next(iter) ) + for( iter = appsync_sync_list; iter; iter = g_list_next(iter) ) { - struct list_elem *data = iter->data; + list_elem_t *data = iter->data; if(!strcmp(data->name, name)) { @@ -403,18 +404,21 @@ int appsync_mark_active(const gchar *name, int post) } if( !post && !missing ) { - log_debug("All pre-enum-apps active. Let's enumerate\n"); + log_debug("All pre-enum-apps active"); +#ifdef APP_SYNC_DBUS appsync_enumerate_usb(); +#endif } /* -1=not found, 0=already active, 1=activated now */ return ret; } +#ifdef APP_SYNC_DBUS static gboolean appsync_enumerate_usb_cb(gpointer data) { (void)data; - enumerate_usb_id = 0; + appsync_enumerate_usb_id = 0; log_debug("handling enumeration timeout"); appsync_enumerate_usb(); /* return false to stop the timer from repeating */ @@ -424,17 +428,23 @@ static gboolean appsync_enumerate_usb_cb(gpointer data) static void appsync_start_enumerate_usb_timer(void) { log_debug("scheduling enumeration timeout"); - if( enumerate_usb_id ) - g_source_remove(enumerate_usb_id), enumerate_usb_id = 0; - enumerate_usb_id = g_timeout_add_seconds(2, appsync_enumerate_usb_cb, NULL); + if( appsync_enumerate_usb_id ) + g_source_remove(appsync_enumerate_usb_id), appsync_enumerate_usb_id = 0; + /* NOTE: This was effectively hazard free before blocking mode switch + * was offloaded to a worker thread - if APP_SYNC_DBUS is ever + * enabled again, this needs to be revisited to avoid timer + * scheduled from worker thread getting triggered in mainloop + * context before the mode switch activity is finished. + */ + appsync_enumerate_usb_id = g_timeout_add_seconds(2, appsync_enumerate_usb_cb, NULL); } static void appsync_cancel_enumerate_usb_timer(void) { - if( enumerate_usb_id ) + if( appsync_enumerate_usb_id ) { log_debug("canceling enumeration timeout"); - g_source_remove(enumerate_usb_id), enumerate_usb_id = 0; + g_source_remove(appsync_enumerate_usb_id), appsync_enumerate_usb_id = 0; } } @@ -442,27 +452,28 @@ static void appsync_enumerate_usb(void) { struct timeval tv; + log_debug("Enumerating"); + /* Stop the timer in case of explicit enumeration call */ appsync_cancel_enumerate_usb_timer(); /* Debug: how long it took from sync start to get here */ gettimeofday(&tv, 0); - timersub(&tv, &sync_tv, &tv); + timersub(&tv, &appsync_sync_tv, &tv); log_debug("sync to enum: %.3f seconds", tv.tv_sec + tv.tv_usec * 1e-6); -#ifdef APP_SYNC_DBUS /* remove dbus service */ dbusappsync_cleanup(); -#endif /* APP_SYNC_DBUS */ } +#endif /* APP_SYNC_DBUS */ void appsync_stop_apps(int post) { GList *iter = 0; - for( iter = sync_list; iter; iter = g_list_next(iter) ) + for( iter = appsync_sync_list; iter; iter = g_list_next(iter) ) { - struct list_elem *data = iter->data; + list_elem_t *data = iter->data; if(data->systemd && data->state == APP_STATE_ACTIVE && data->post == post) { @@ -483,9 +494,9 @@ int appsync_stop(gboolean force) GList *iter; log_debug("assuming all applications are active"); - for( iter = sync_list; iter; iter = g_list_next(iter) ) + for( iter = appsync_sync_list; iter; iter = g_list_next(iter) ) { - struct list_elem *data = iter->data; + list_elem_t *data = iter->data; data->state = APP_STATE_ACTIVE; } } @@ -497,6 +508,8 @@ int appsync_stop(gboolean force) appsync_stop_apps(0); /* Do not leave active timers behind */ +#ifdef APP_SYNC_DBUS appsync_cancel_enumerate_usb_timer(); - return(0); +#endif + return 0; } diff --git a/src/usb_moded-appsync.h b/src/usb_moded-appsync.h index f96a665..967199a 100644 --- a/src/usb_moded-appsync.h +++ b/src/usb_moded-appsync.h @@ -26,6 +26,8 @@ #ifndef USB_MODED_APPSYNC_H_ # define USB_MODED_APPSYNC_H_ +# include + /* ========================================================================= * * Constants * ========================================================================= */ @@ -46,7 +48,7 @@ /** Application activation state */ -typedef enum { +typedef enum app_state_t { /** Application is not relevant for the current mode */ APP_STATE_DONTCARE = 0, /** Application should be started */ @@ -58,7 +60,7 @@ typedef enum { /** * keep all the needed info together for launching an app */ -typedef struct list_elem +typedef struct list_elem_t { char *name; /**< name of the app to launch */ char *mode; /**< mode in which to launch the app */ @@ -66,7 +68,7 @@ typedef struct list_elem app_state_t state; /**< marker to check if the app has started sucessfully */ int systemd; /**< marker to know if we start it with systemd or not */ int post; /**< marker to indicate when to start the app */ -} list_elem; +} list_elem_t; /* ========================================================================= * * Prototypes diff --git a/src/usb_moded-common.c b/src/usb_moded-common.c new file mode 100644 index 0000000..01b6799 --- /dev/null +++ b/src/usb_moded-common.c @@ -0,0 +1,515 @@ +#include "usb_moded-common.h" + +#include "usb_moded.h" +#include "usb_moded-config-private.h" +#include "usb_moded-dbus-private.h" +#include "usb_moded-dyn-config.h" +#include "usb_moded-log.h" +#include "usb_moded-modes.h" +#include "usb_moded-worker.h" + +#include +#include +#include +#include +#include + +/* ========================================================================= * + * Types + * ========================================================================= */ + +/** Mapping usb mode from internal to hardware/broadcast use */ +typedef struct modemapping_t +{ + /** Any valid usb mode */ + const char *internal_mode; + + /** Mode to use for usb configuration, or NULL = internal */ + const char *hardware_mode; + + /** Mode to use for D-Bus broadcast, or NULL = internal */ + const char *external_mode; +} modemapping_t; + +/* ========================================================================= * + * Prototypes + * ========================================================================= */ + +/* -- cable -- */ + +const char *cable_state_repr(cable_state_t state); + +/* -- common -- */ + +const char *common_map_mode_to_hardware (const char *internal_mode); +const char *common_map_mode_to_external (const char *internal_mode); +void common_send_supported_modes_signal (void); +void common_send_available_modes_signal (void); +void common_send_hidden_modes_signal (void); +void common_send_whitelisted_modes_signal(void); +static void common_write_to_sysfs_file (const char *path, const char *text); +void common_acquire_wakelock (const char *wakelock_name); +void common_release_wakelock (const char *wakelock_name); +int common_system_ (const char *file, int line, const char *func, const char *command); +FILE *common_popen_ (const char *file, int line, const char *func, const char *command, const char *type); +waitres_t common_wait (unsigned tot_ms, bool (*ready_cb)(void *aptr), void *aptr); +bool common_msleep_ (const char *file, int line, const char *func, unsigned msec); +static bool common_mode_in_list (const char *mode, char *const *modes); +int common_valid_mode (const char *mode); +gchar *common_get_mode_list (mode_list_type_t type); + +/* ========================================================================= * + * Functions + * ========================================================================= */ + +/* ------------------------------------------------------------------------- * + * CABLE_STATE + * ------------------------------------------------------------------------- */ + +const char *cable_state_repr(cable_state_t state) +{ + static const char * const lut[CABLE_STATE_NUMOF] = { + [CABLE_STATE_UNKNOWN] = "unknown", + [CABLE_STATE_DISCONNECTED] = "disconnected", + [CABLE_STATE_CHARGER_CONNECTED] = "charger_connected", + [CABLE_STATE_PC_CONNECTED] = "pc_connected", + }; + return lut[state]; +} + +/* ------------------------------------------------------------------------- * + * MODE_MAPPING + * ------------------------------------------------------------------------- */ + +static const modemapping_t common_modemapping[] = +{ + { + .internal_mode = MODE_UNDEFINED, + .hardware_mode = MODE_CHARGING, + .external_mode = 0, + }, + { + .internal_mode = MODE_ASK, + .hardware_mode = MODE_CHARGING, + .external_mode = 0, + }, + { + .internal_mode = MODE_MASS_STORAGE, + .hardware_mode = 0, + .external_mode = 0, + }, + { + .internal_mode = MODE_DEVELOPER, + .hardware_mode = 0, + .external_mode = 0, + }, + { + .internal_mode = MODE_MTP, + .hardware_mode = 0, + .external_mode = 0, + }, + { + .internal_mode = MODE_HOST, + .hardware_mode = 0, + .external_mode = 0, + }, + { + .internal_mode = MODE_CONNECTION_SHARING, + .hardware_mode = 0, + .external_mode = 0, + }, + { + .internal_mode = MODE_DIAG, + .hardware_mode = 0, + .external_mode = 0, + }, + { + .internal_mode = MODE_ADB, + .hardware_mode = 0, + .external_mode = 0, + }, + { + .internal_mode = MODE_PC_SUITE, + .hardware_mode = 0, + .external_mode = 0, + }, + { + .internal_mode = MODE_CHARGING, + .hardware_mode = MODE_CHARGING, + .external_mode = 0, + }, + { + .internal_mode = MODE_CHARGING_FALLBACK, + .hardware_mode = MODE_CHARGING, + .external_mode = 0, + }, + { + .internal_mode = MODE_CHARGER, + .hardware_mode = MODE_CHARGING, + .external_mode = 0, + }, + // sentinel + { + .internal_mode = 0, + .hardware_mode = 0, + .external_mode = 0, + } +}; + +const char * +common_map_mode_to_hardware(const char *internal_mode) +{ + const char *hardware_mode = 0; + + for( size_t i = 0; common_modemapping[i].internal_mode; ++i ) { + if( strcmp(common_modemapping[i].internal_mode, internal_mode) ) + continue; + hardware_mode = common_modemapping[i].hardware_mode; + break; + } + return hardware_mode ?: internal_mode; +} + +const char * +common_map_mode_to_external(const char *internal_mode) +{ + const char *external_mode = 0; + + for( size_t i = 0; common_modemapping[i].internal_mode; ++i ) { + if( strcmp(common_modemapping[i].internal_mode, internal_mode) ) + continue; + external_mode = common_modemapping[i].external_mode; + break; + } + return external_mode ?: internal_mode; +} + +/* ------------------------------------------------------------------------- * + * DBUS_NOTIFICATIONS + * ------------------------------------------------------------------------- */ + +/** Send supported modes signal + */ +void common_send_supported_modes_signal(void) +{ + gchar *mode_list = common_get_mode_list(SUPPORTED_MODES_LIST); + umdbus_send_supported_modes_signal(mode_list); + g_free(mode_list); +} + +/** Send available modes signal + */ +void common_send_available_modes_signal(void) +{ + gchar *mode_list = common_get_mode_list(AVAILABLE_MODES_LIST); + umdbus_send_available_modes_signal(mode_list); + g_free(mode_list); +} + +/** Send hidden modes signal + */ +void common_send_hidden_modes_signal(void) +{ + gchar *mode_list = config_get_hidden_modes(); + umdbus_send_hidden_modes_signal(mode_list); + g_free(mode_list); +} + +/** Send whitelisted modes signal + */ +void common_send_whitelisted_modes_signal(void) +{ + gchar *mode_list = config_get_mode_whitelist(); + umdbus_send_whitelisted_modes_signal(mode_list); + g_free(mode_list); +} + +/* ------------------------------------------------------------------------- * + * SYSFS_IO + * ------------------------------------------------------------------------- */ + +/** Write string to already existing sysfs file + * + * Note: Attempts to write to nonexisting files are silently ignored. + * + * @param path Where to write + * @param text What to write + */ +static void common_write_to_sysfs_file(const char *path, const char *text) +{ + int fd = -1; + + if (!path || !text) + goto EXIT; + + if ((fd = open(path, O_WRONLY)) == -1) { + if (errno != ENOENT) { + log_warning("%s: open for writing failed: %m", path); + } + goto EXIT; + } + + if (write(fd, text, strlen(text)) == -1) { + log_warning("%s: write failed : %m", path); + goto EXIT; + } +EXIT: + if (fd != -1) + close(fd); +} + +/* ------------------------------------------------------------------------- * + * WAKELOCKS + * ------------------------------------------------------------------------- */ + +/** Acquire wakelock via sysfs + * + * Wakelock must be released via common_release_wakelock(). + * + * Automatically terminating wakelock is used, so that we + * do not block suspend indefinately in case usb_moded + * gets stuck or crashes. + * + * Note: The name should be unique within the system. + * + * @param wakelock_name Wake lock to be acquired + */ +void common_acquire_wakelock(const char *wakelock_name) +{ + char buff[256]; + snprintf(buff, sizeof buff, "%s %lld", + wakelock_name, + USB_MODED_SUSPEND_DELAY_MAXIMUM_MS * 1000000LL); + common_write_to_sysfs_file("/sys/power/wake_lock", buff); + +#if VERBOSE_WAKELOCKING + log_debug("common_acquire_wakelock %s", wakelock_name); +#endif +} + +/** Release wakelock via sysfs + * + * @param wakelock_name Wake lock to be released + */ +void common_release_wakelock(const char *wakelock_name) +{ +#if VERBOSE_WAKELOCKING + log_debug("common_release_wakelock %s", wakelock_name); +#endif + + common_write_to_sysfs_file("/sys/power/wake_unlock", wakelock_name); +} + +/* ------------------------------------------------------------------------- * + * BLOCKING_OPERATION + * ------------------------------------------------------------------------- */ + +/** Wrapper to give visibility to blocking system() calls usb-moded is making + */ +int +common_system_(const char *file, int line, const char *func, + const char *command) +{ + log_debug("EXEC %s; from %s:%d: %s()", + command, file, line, func); + + int rc = system(command); + + if( rc != 0 ) + log_warning("EXEC %s; exit code is %d", command, rc); + + return rc; +} + +/** Wrapper to give visibility subprocesses usb-moded is invoking via popen() + */ +FILE * +common_popen_(const char *file, int line, const char *func, + const char *command, const char *type) +{ + log_debug("EXEC %s; from %s:%d: %s()", + command, file, line, func); + + return popen(command, type); +} + +waitres_t +common_wait(unsigned tot_ms, bool (*ready_cb)(void *aptr), void *aptr) +{ + struct timespec ts; + + waitres_t res = WAIT_FAILED; + + for( ;; ) { + unsigned nap_ms = (tot_ms > 200) ? 200 : tot_ms; + + ts.tv_sec = (nap_ms / 1000); + ts.tv_nsec = (nap_ms % 1000); + ts.tv_nsec *= 1000 * 1000; + + for( ;; ) { + if( ready_cb && ready_cb(aptr) ) { + res = WAIT_READY; + goto EXIT; + } + + if( tot_ms <= 0 ) { + res = WAIT_TIMEOUT; + goto EXIT; + } + + if( worker_bailing_out() ) { + log_warning("wait canceled"); + goto EXIT; + } + + if( nanosleep(&ts, &ts) == 0 ) + break; + + if( errno != EINTR ) { + log_warning("wait failed: %m"); + goto EXIT; + } + } + + tot_ms -= nap_ms; + } + +EXIT: + return res; +} + +/** Wrapper to give visibility to blocking sleeps usb-moded is making + */ +bool +common_msleep_(const char *file, int line, const char *func, unsigned msec) +{ + log_debug("SLEEP %u.%03u seconds; from %s:%d: %s()", + msec / 1000u, msec % 1000u,file, line, func); + return common_wait(msec, 0, 0) == WAIT_TIMEOUT; +} + +/* ------------------------------------------------------------------------- * + * MISC + * ------------------------------------------------------------------------- */ + +/* check if a mode is in a list */ +static bool common_mode_in_list(const char *mode, char * const *modes) +{ + int i; + + if (!modes) + return false; + + for(i = 0; modes[i] != NULL; i++) + { + if(!strcmp(modes[i], mode)) + return true; + } + return false; +} + +/** check if a given usb_mode exists + * + * @param mode The mode to look for + * + * @return 0 if mode exists, 1 if it does not exist + */ +int common_valid_mode(const char *mode) +{ + int valid = 1; + /* MODE_ASK, MODE_CHARGER and MODE_CHARGING_FALLBACK are not modes that are settable seen their special 'internal' status + * so we only check the modes that are announed outside. Only exception is the built in MODE_CHARGING */ + if(!strcmp(MODE_CHARGING, mode)) { + valid = 0; + } + else + { + gchar *whitelist_value = 0; + gchar **whitelist_array = 0; + + if( (whitelist_value = config_get_mode_whitelist()) ) + whitelist_array = g_strsplit(whitelist_value, ",", 0); + + for( GList *iter = usbmoded_get_modelist(); iter; iter = g_list_next(iter) ) { + mode_list_elem_t *data = iter->data; + if( strcmp(mode, data->mode_name) ) + continue; + + if (!whitelist_array || common_mode_in_list(data->mode_name, whitelist_array)) + valid = 0; + break; + } + + g_strfreev(whitelist_array); + g_free(whitelist_value); + } + return valid; +} + +/** make a list of all available usb modes + * + * @param type The type of list to return. Supported or available. + * + * @return a comma-separated list of modes (MODE_ASK not included as it is not a real mode) + */ +gchar *common_get_mode_list(mode_list_type_t type) +{ + GString *mode_list_str = g_string_new(NULL); + + gchar *hidden_modes_value = 0; + gchar **hidden_modes_array = 0; + + gchar *whitelist_value = 0; + gchar **whitelist_array = 0; + + if( usbmoded_get_diag_mode() ) + { + /* diag mode. there is only one active mode */ + g_string_append(mode_list_str, MODE_DIAG); + goto EXIT; + } + + if( (hidden_modes_value = config_get_hidden_modes()) ) + hidden_modes_array = g_strsplit(hidden_modes_value, ",", 0); + + switch( type ) { + case SUPPORTED_MODES_LIST: + /* All modes that are not hidden */ + break; + + case AVAILABLE_MODES_LIST: + /* All whitelisted modes that are not hidden */ + if( (whitelist_value = config_get_mode_whitelist()) ) + whitelist_array = g_strsplit(whitelist_value, ",", 0); + break; + } + + for( GList *iter = usbmoded_get_modelist(); iter; iter = g_list_next(iter) ) + { + mode_list_elem_t *data = iter->data; + + /* skip items in the hidden list */ + if (common_mode_in_list(data->mode_name, hidden_modes_array)) + continue; + + /* if there is a whitelist skip items not in the list */ + if (whitelist_array && !common_mode_in_list(data->mode_name, whitelist_array)) + continue; + + g_string_append(mode_list_str, data->mode_name); + g_string_append(mode_list_str, ", "); + } + + /* End with charging mode */ + g_string_append(mode_list_str, MODE_CHARGING); + +EXIT: + g_strfreev(whitelist_array); + g_free(whitelist_value); + + g_strfreev(hidden_modes_array); + g_free(hidden_modes_value); + + return g_string_free(mode_list_str, false); +} diff --git a/src/usb_moded-common.h b/src/usb_moded-common.h new file mode 100644 index 0000000..d8d06fe --- /dev/null +++ b/src/usb_moded-common.h @@ -0,0 +1,70 @@ +#ifndef USB_MODED_COMMON_H_ +# define USB_MODED_COMMON_H_ + +# include +# include +# include + +/* ========================================================================= * + * Types + * ========================================================================= */ + +/** Mode list types + */ +typedef enum mode_list_type_t { + /** All configured modes */ + SUPPORTED_MODES_LIST, + /** Configured modes that can be activated */ + AVAILABLE_MODES_LIST +} mode_list_type_t; + +typedef enum { + CABLE_STATE_UNKNOWN, + CABLE_STATE_DISCONNECTED, + CABLE_STATE_CHARGER_CONNECTED, + CABLE_STATE_PC_CONNECTED, + CABLE_STATE_NUMOF +} cable_state_t; + +typedef enum waitres_t +{ + WAIT_FAILED, + WAIT_READY, + WAIT_TIMEOUT, +} waitres_t; + +/* ========================================================================= * + * Functions + * ========================================================================= */ + +/* -- cable -- */ + +const char *cable_state_repr(cable_state_t state); + +/* -- common -- */ + +const char *common_map_mode_to_hardware (const char *internal_mode); +const char *common_map_mode_to_external (const char *internal_mode); +void common_send_supported_modes_signal (void); +void common_send_available_modes_signal (void); +void common_send_hidden_modes_signal (void); +void common_send_whitelisted_modes_signal(void); +void common_acquire_wakelock (const char *wakelock_name); +void common_release_wakelock (const char *wakelock_name); +int common_system_ (const char *file, int line, const char *func, const char *command); +FILE *common_popen_ (const char *file, int line, const char *func, const char *command, const char *type); +waitres_t common_wait (unsigned tot_ms, bool (*ready_cb)(void *aptr), void *aptr); +bool common_msleep_ (const char *file, int line, const char *func, unsigned msec); +int common_valid_mode (const char *mode); +gchar *common_get_mode_list (mode_list_type_t type); + +/* ========================================================================= * + * Macros + * ========================================================================= */ + +# define common_system(command) common_system_(__FILE__,__LINE__,__FUNCTION__,(command)) +# define common_popen(command, type) common_popen_(__FILE__,__LINE__,__FUNCTION__,(command),(type)) +# define common_msleep(msec) common_msleep_(__FILE__,__LINE__,__FUNCTION__,(msec)) +# define common_sleep(sec) common_msleep_(__FILE__,__LINE__,__FUNCTION__,(sec)*1000) + +#endif /* USB_MODED_COMMON_H_ */ diff --git a/src/usb_moded-config-private.h b/src/usb_moded-config-private.h index 6c682f5..89b33d3 100644 --- a/src/usb_moded-config-private.h +++ b/src/usb_moded-config-private.h @@ -36,6 +36,8 @@ # include "usb_moded-config.h" +# include + /* ========================================================================= * * Prototypes * ========================================================================= */ diff --git a/src/usb_moded-config.c b/src/usb_moded-config.c index 4f97338..a3109d4 100644 --- a/src/usb_moded-config.c +++ b/src/usb_moded-config.c @@ -31,30 +31,27 @@ * 02110-1301 USA */ -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include "usb_moded.h" -#include "usb_moded-config.h" #include "usb_moded-config-private.h" + +#include "usb_moded-control.h" +#include "usb_moded-dbus-private.h" +#include "usb_moded-dyn-config.h" #include "usb_moded-log.h" #include "usb_moded-modes.h" -#include "usb_moded-modesetting.h" -#include "usb_moded-dbus-private.h" +#include "usb_moded-worker.h" #ifdef USE_MER_SSU # include "usb_moded-ssu.h" #endif +#include + +#include +#include +#include +#include +#include + /* ========================================================================= * * Prototypes * ========================================================================= */ @@ -116,12 +113,12 @@ static int config_validate_ip(const char *ipadd) unsigned char c; if (sscanf(ipadd, "%3u.%3u.%3u.%3u%c", &b1, &b2, &b3, &b4, &c) != 4) - return(-1); + return -1; if ((b1 | b2 | b3 | b4) > 255) - return(-1); + return -1; if (strspn(ipadd, "0123456789.") < strlen(ipadd)) - return(-1); + return -1; /* all ok */ return 0; } @@ -137,53 +134,53 @@ char *config_find_mounts(void) ret = g_strdup(FS_MOUNT_DEFAULT); log_debug("Default mount = %s\n", ret); } - return(ret); + return ret; } int config_find_sync(void) { - return(config_get_conf_int(FS_SYNC_ENTRY, FS_SYNC_KEY)); + return config_get_conf_int(FS_SYNC_ENTRY, FS_SYNC_KEY); } char * config_find_alt_mount(void) { - return(config_get_conf_string(ALT_MOUNT_ENTRY, ALT_MOUNT_KEY)); + return config_get_conf_string(ALT_MOUNT_ENTRY, ALT_MOUNT_KEY); } char * config_find_udev_path(void) { - return(config_get_conf_string(UDEV_PATH_ENTRY, UDEV_PATH_KEY)); + return config_get_conf_string(UDEV_PATH_ENTRY, UDEV_PATH_KEY); } char * config_find_udev_subsystem(void) { - return(config_get_conf_string(UDEV_PATH_ENTRY, UDEV_SUBSYSTEM_KEY)); + return config_get_conf_string(UDEV_PATH_ENTRY, UDEV_SUBSYSTEM_KEY); } char * config_check_trigger(void) { - return(config_get_conf_string(TRIGGER_ENTRY, TRIGGER_PATH_KEY)); + return config_get_conf_string(TRIGGER_ENTRY, TRIGGER_PATH_KEY); } char * config_get_trigger_subsystem(void) { - return(config_get_conf_string(TRIGGER_ENTRY, TRIGGER_UDEV_SUBSYSTEM)); + return config_get_conf_string(TRIGGER_ENTRY, TRIGGER_UDEV_SUBSYSTEM); } char * config_get_trigger_mode(void) { - return(config_get_conf_string(TRIGGER_ENTRY, TRIGGER_MODE_KEY)); + return config_get_conf_string(TRIGGER_ENTRY, TRIGGER_MODE_KEY); } char * config_get_trigger_property(void) { - return(config_get_conf_string(TRIGGER_ENTRY, TRIGGER_PROPERTY_KEY)); + return config_get_conf_string(TRIGGER_ENTRY, TRIGGER_PROPERTY_KEY); } char * config_get_trigger_value(void) { - return(config_get_conf_string(TRIGGER_ENTRY, TRIGGER_PROPERTY_VALUE_KEY)); + return config_get_conf_string(TRIGGER_ENTRY, TRIGGER_PROPERTY_VALUE_KEY); } static char * config_get_network_ip(void) @@ -191,37 +188,37 @@ static char * config_get_network_ip(void) char * ip = config_get_kcmdline_string(NETWORK_IP_KEY); if (ip != NULL) if(!config_validate_ip(ip)) - return(ip); + return ip; - return(config_get_conf_string(NETWORK_ENTRY, NETWORK_IP_KEY)); + return config_get_conf_string(NETWORK_ENTRY, NETWORK_IP_KEY); } static char * config_get_network_interface(void) { - return(config_get_conf_string(NETWORK_ENTRY, NETWORK_INTERFACE_KEY)); + return config_get_conf_string(NETWORK_ENTRY, NETWORK_INTERFACE_KEY); } static char * config_get_network_gateway(void) { char * gw = config_get_kcmdline_string(NETWORK_GATEWAY_KEY); if (gw != NULL) - return(gw); + return gw; - return(config_get_conf_string(NETWORK_ENTRY, NETWORK_GATEWAY_KEY)); + return config_get_conf_string(NETWORK_ENTRY, NETWORK_GATEWAY_KEY); } static char * config_get_network_netmask(void) { char * netmask = config_get_kcmdline_string(NETWORK_NETMASK_KEY); if (netmask != NULL) - return(netmask); + return netmask; - return(config_get_conf_string(NETWORK_ENTRY, NETWORK_NETMASK_KEY)); + return config_get_conf_string(NETWORK_ENTRY, NETWORK_NETMASK_KEY); } static char * config_get_network_nat_interface(void) { - return(config_get_conf_string(NETWORK_ENTRY, NETWORK_NAT_INTERFACE_KEY)); + return config_get_conf_string(NETWORK_ENTRY, NETWORK_NAT_INTERFACE_KEY); } /* create basic conffile with sensible defaults */ @@ -284,7 +281,7 @@ static int config_get_conf_int(const gchar *entry, const gchar *key) } g_strfreev(origkeys); g_key_file_free(settingsfile); - return(ret); + return ret; } @@ -321,7 +318,7 @@ static char * config_get_conf_string(const gchar *entry, const gchar *key) g_strfreev(origkeys); end: g_key_file_free(settingsfile); - return(tmp_char); + return tmp_char; } @@ -340,16 +337,16 @@ static char * config_get_kcmdline_string(const char *entry) if ((fd = open("/proc/cmdline", O_RDONLY)) < 0) { log_debug("could not read /proc/cmdline"); - return(ret); + return ret; } - len = read(fd, cmdLine, sizeof(cmdLine) - 1); + len = read(fd, cmdLine, sizeof cmdLine - 1); close(fd); if (len <= 0) { log_debug("kernel command line was empty"); - return(ret); + return ret; } cmdLine[len] = '\0'; @@ -359,7 +356,7 @@ static char * config_get_kcmdline_string(const char *entry) if (!g_shell_parse_argv(cmdLine, &argc, &argv, &optErr)) { g_error_free(optErr); - return(ret); + return ret; } /* find the ip token */ @@ -398,16 +395,25 @@ static char * config_get_kcmdline_string(const char *entry) g_strfreev(argv); g_strfreev(network_tokens); - return(ret); + return ret; } char * config_get_mode_setting(void) { - char * mode = config_get_kcmdline_string(MODE_SETTING_KEY); - if (mode != NULL) - return(mode); + char *mode = 0; - return(config_get_conf_string(MODE_SETTING_ENTRY, MODE_SETTING_KEY)); + /* Kernel command line can be used to override settings */ + if( (mode = config_get_kcmdline_string(MODE_SETTING_KEY)) ) + goto EXIT; + + if( (mode = config_get_conf_string(MODE_SETTING_ENTRY, MODE_SETTING_KEY)) ) + goto EXIT; + + /* If no default mode is configured, treat it as charging only */ + mode = g_strdup(MODE_CHARGING); + +EXIT: + return mode; } /* * @param settingsfile: already opened settingsfile we want to read an entry from @@ -458,14 +464,14 @@ set_config_result_t config_set_config_setting(const char *entry, const char *key ret = SET_CONFIG_UPDATED; g_free(keyfile); - return (ret); + return ret; } set_config_result_t config_set_mode_setting(const char *mode) { - if (strcmp(mode, MODE_ASK) && usbmoded_valid_mode(mode)) + if (strcmp(mode, MODE_ASK) && common_valid_mode(mode)) return SET_CONFIG_ERROR; - return (config_set_config_setting(MODE_SETTING_ENTRY, MODE_SETTING_KEY, mode)); + return config_set_config_setting(MODE_SETTING_ENTRY, MODE_SETTING_KEY, mode); } /* Builds the string used for hidden modes, when hide set to one builds the @@ -540,14 +546,14 @@ set_config_result_t config_set_hide_mode_setting(const char *mode) } if(ret == SET_CONFIG_UPDATED) { - usbmoded_send_hidden_modes_signal(); - usbmoded_send_supported_modes_signal(); - usbmoded_send_available_modes_signal(); + common_send_hidden_modes_signal(); + common_send_supported_modes_signal(); + common_send_available_modes_signal(); } g_free(hidden_modes); - return(ret); + return ret; } set_config_result_t config_set_unhide_mode_setting(const char *mode) @@ -561,14 +567,14 @@ set_config_result_t config_set_unhide_mode_setting(const char *mode) } if(ret == SET_CONFIG_UPDATED) { - usbmoded_send_hidden_modes_signal(); - usbmoded_send_supported_modes_signal(); - usbmoded_send_available_modes_signal(); + common_send_hidden_modes_signal(); + common_send_supported_modes_signal(); + common_send_available_modes_signal(); } g_free(hidden_modes); - return(ret); + return ret; } set_config_result_t config_set_mode_whitelist(const char *whitelist) @@ -580,22 +586,22 @@ set_config_result_t config_set_mode_whitelist(const char *whitelist) const char *current_mode; mode_setting = config_get_mode_setting(); - if (strcmp(mode_setting, MODE_ASK) && usbmoded_valid_mode(mode_setting)) + if (strcmp(mode_setting, MODE_ASK) && common_valid_mode(mode_setting)) config_set_mode_setting(MODE_ASK); g_free(mode_setting); - current_mode = usbmoded_get_usb_mode(); + current_mode = control_get_usb_mode(); if (!strcmp(current_mode, MODE_UNDEFINED)) { /* Disconnected -> do nothing */ } - else if (strcmp(current_mode, MODE_CHARGING_FALLBACK) && strcmp(current_mode, MODE_ASK) && usbmoded_valid_mode(current_mode)) { + else if (strcmp(current_mode, MODE_CHARGING_FALLBACK) && strcmp(current_mode, MODE_ASK) && common_valid_mode(current_mode)) { /* Invalid mode that is not MODE_ASK or MODE_CHARGING_FALLBACK * -> switch to MODE_CHARGING_FALLBACK */ - usbmoded_set_usb_mode(MODE_CHARGING_FALLBACK); + control_set_usb_mode(MODE_CHARGING_FALLBACK); } umdbus_send_whitelisted_modes_signal(whitelist); - usbmoded_send_available_modes_signal(); + common_send_available_modes_signal(); } return ret; @@ -613,7 +619,7 @@ set_config_result_t config_set_mode_in_whitelist(const char *mode, int allowed) g_free(whitelist); - return(ret); + return ret; } /* @@ -671,7 +677,7 @@ set_config_result_t config_set_network_setting(const char *config, const char *s char * config_get_network_setting(const char *config) { char * ret = 0; - struct mode_list_elem *data; + mode_list_elem_t *data; if(!strcmp(config, NETWORK_IP_KEY)) { @@ -690,7 +696,7 @@ char * config_get_network_setting(const char *config) goto end; /* no interface override specified, let's use the one * from the mode config */ - data = usbmoded_get_usb_mode_data(); + data = worker_get_usb_mode_data(); if(data) { if(data->network_interface) @@ -702,7 +708,7 @@ char * config_get_network_setting(const char *config) ret = strdup("usb0"); } else if(!strcmp(config, NETWORK_GATEWAY_KEY)) - return(config_get_network_gateway()); + return config_get_network_gateway(); else if(!strcmp(config, NETWORK_NETMASK_KEY)) { ret = config_get_network_netmask(); @@ -710,12 +716,12 @@ char * config_get_network_setting(const char *config) ret = strdup("255.255.255.0"); } else if(!strcmp(config, NETWORK_NAT_INTERFACE_KEY)) - return(config_get_network_nat_interface()); + return config_get_network_nat_interface(); else /* no matching keys, return error */ - return(NULL); + return NULL; end: - return(ret); + return ret; } /** @@ -890,7 +896,7 @@ char * config_get_android_manufacturer(void) char * config_get_android_vendor_id(void) { - return(config_get_conf_string(ANDROID_ENTRY, ANDROID_VENDOR_ID_KEY)); + return config_get_conf_string(ANDROID_ENTRY, ANDROID_VENDOR_ID_KEY); } char * config_get_android_product(void) @@ -910,19 +916,19 @@ char * config_get_android_product(void) char * config_get_android_product_id(void) { - return(config_get_conf_string(ANDROID_ENTRY, ANDROID_PRODUCT_ID_KEY)); + return config_get_conf_string(ANDROID_ENTRY, ANDROID_PRODUCT_ID_KEY); } char * config_get_hidden_modes(void) { - return(config_get_conf_string(MODE_SETTING_ENTRY, MODE_HIDE_KEY)); + return config_get_conf_string(MODE_SETTING_ENTRY, MODE_HIDE_KEY); } char * config_get_mode_whitelist(void) { - return(config_get_conf_string(MODE_SETTING_ENTRY, MODE_WHITELIST_KEY)); + return config_get_conf_string(MODE_SETTING_ENTRY, MODE_WHITELIST_KEY); } int config_is_roaming_not_allowed(void) { - return(config_get_conf_int(NETWORK_ENTRY, NO_ROAMING_KEY)); + return config_get_conf_int(NETWORK_ENTRY, NO_ROAMING_KEY); } diff --git a/src/usb_moded-configfs.c b/src/usb_moded-configfs.c index b798c73..5c458a8 100644 --- a/src/usb_moded-configfs.c +++ b/src/usb_moded-configfs.c @@ -22,21 +22,21 @@ #include "usb_moded-configfs.h" -#include - -#include -#include -#include - -#include - #include "usb_moded.h" #include "usb_moded-android.h" -#include "usb_moded-log.h" -#include "usb_moded-modesetting.h" +#include "usb_moded-common.h" #include "usb_moded-config-private.h" +#include "usb_moded-log.h" #include "usb_moded-mac.h" +#include + +#include +#include +#include +#include +#include + /* ========================================================================= * * Constants * ========================================================================= */ @@ -598,7 +598,7 @@ configfs_init_values(void) /* Prep: mtp_mode */ configfs_register_function(FUNCTION_MTP); if( access("/dev/mtp/ep0", F_OK) == -1 ) { - usbmoded_system("/bin/mount -o uid=100000,gid=100000 -t functionfs mtp /dev/mtp"); + common_system("/bin/mount -o uid=100000,gid=100000 -t functionfs mtp /dev/mtp"); } /* Prep: developer_mode */ diff --git a/src/usb_moded-control.c b/src/usb_moded-control.c new file mode 100644 index 0000000..4e1dfdf --- /dev/null +++ b/src/usb_moded-control.c @@ -0,0 +1,345 @@ +/** + * @file usb_moded-control.c + * + * Copyright (C) 2013-2018 Jolla. All rights reserved. + * + * @author: Philippe De Swert + * @author: Simo Piiroinen + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Lesser GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program 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 + * General Public License for more details. + * + * You should have received a copy of the Lesser GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include "usb_moded-control.h" + +#include "usb_moded-config-private.h" +#include "usb_moded-dbus-private.h" +#include "usb_moded-dyn-config.h" +#include "usb_moded-log.h" +#include "usb_moded-modes.h" +#include "usb_moded-worker.h" + +#include +#include + +/* ========================================================================= * + * Prototypes + * ========================================================================= */ + +/* -- usbmoded -- */ + +void control_rethink_usb_charging_fallback(void); +const char *control_get_external_mode (void); +static void control_set_external_mode (const char *mode); +void control_clear_external_mode (void); +static void control_update_external_mode (void); +const char *control_get_usb_mode (void); +void control_clear_internal_mode (void); +void control_set_usb_mode (const char *mode); +void control_mode_switched (const char *override); +void control_select_usb_mode (void); +void control_set_cable_state (cable_state_t cable_state); +cable_state_t control_get_cable_state (void); +void control_clear_cable_state (void); +bool control_get_connection_state (void); + +/* ========================================================================= * + * Data + * ========================================================================= */ + +/* The external mode; + * + * What was the last mode signaled over D-Bus. + */ +static char *control_external_mode = NULL; + +/** The logical mode name + * + * Full set of valid modes can occur here + */ +static char *control_internal_mode = NULL; + +/** Connection status + * + * Access only via: + * - control_set_cable_state() + * - control_get_connection_state() + */ +static cable_state_t control_cable_state = CABLE_STATE_UNKNOWN; + +/* ========================================================================= * + * Functions + * ========================================================================= */ + +/** Check if we can/should leave charging fallback mode + * + * Called when device lock status, or device status (dsme) + * changes. + */ +void +control_rethink_usb_charging_fallback(void) +{ + /* Cable must be connected to a pc */ + if( control_get_cable_state() != CABLE_STATE_PC_CONNECTED ) + goto EXIT; + + /* Switching can happen only from MODE_UNDEFINED + * or MODE_CHARGING_FALLBACK */ + const char *usb_mode = control_get_usb_mode(); + + if( strcmp(usb_mode, MODE_UNDEFINED) && + strcmp(usb_mode, MODE_CHARGING_FALLBACK) ) + goto EXIT; + + if( !usbmoded_can_export() ) { + log_notice("exporting data not allowed; stay in %s", usb_mode); + goto EXIT; + } + + log_debug("attempt to leave %s", usb_mode); + control_select_usb_mode(); + +EXIT: + return; +} + +const char *control_get_external_mode(void) +{ + return control_external_mode ?: MODE_UNDEFINED; +} + +static void control_set_external_mode(const char *mode) +{ + gchar *previous = control_external_mode; + if( !g_strcmp0(previous, mode) ) + goto EXIT; + + log_debug("external_mode: %s -> %s", + previous, mode); + + control_external_mode = g_strdup(mode); + g_free(previous); + + // DO THE DBUS BROADCAST + + if( !strcmp(control_external_mode, MODE_ASK) ) { + /* send signal, mode will be set when the dialog service calls + * the set_mode method call. */ + umdbus_send_state_signal(USB_CONNECTED_DIALOG_SHOW); + } + + umdbus_send_state_signal(control_external_mode); + +EXIT: + return; +} + +void control_clear_external_mode(void) +{ + g_free(control_external_mode), + control_external_mode = 0; +} + +static void control_update_external_mode(void) +{ + const char *internal_mode = control_get_usb_mode(); + const char *external_mode = common_map_mode_to_external(internal_mode); + + control_set_external_mode(external_mode); +} + +/** get the usb mode + * + * @return the currently set mode + * + */ +const char * control_get_usb_mode(void) +{ + return control_internal_mode; +} + +void control_clear_internal_mode(void) +{ + g_free(control_internal_mode), + control_internal_mode = 0; +} + +/** set the usb mode + * + * @param mode The requested USB mode + */ +void control_set_usb_mode(const char *mode) +{ + gchar *previous = control_internal_mode; + if( !g_strcmp0(previous, mode) ) + goto EXIT; + + log_debug("internal_mode: %s -> %s", + previous, mode); + + control_internal_mode = g_strdup(mode); + g_free(previous); + + /* Invalidate current mode for the duration of mode transition */ + control_set_external_mode(MODE_BUSY); + + /* Propagate down to gadget config */ + worker_request_hardware_mode(control_internal_mode); + +EXIT: + return; +} + +/* Worker thread has finished mode switch + * + * @param mode The activated USB mode + */ +void control_mode_switched(const char *mode) +{ + /* Update state data - without retriggering the worker thread + */ + if( g_strcmp0(control_internal_mode, mode) ) { + log_debug("internal_mode: %s -> %s", + control_internal_mode, mode); + g_free(control_internal_mode), + control_internal_mode = g_strdup(mode); + } + + /* Propagate up to D-Bus */ + control_update_external_mode(); + + return; +} + +/** set the chosen usb state + * + * gauge what mode to enter and then call control_set_usb_mode() + * + */ +void control_select_usb_mode(void) +{ + char *mode_to_set = 0; + + if( usbmoded_get_rescue_mode() ) { + log_debug("Entering rescue mode!\n"); + control_set_usb_mode(MODE_DEVELOPER); + goto EXIT; + } + + if( usbmoded_get_diag_mode() ) { + /* Assumption is that in diag-mode there is only + * one mode configured i.e. list head is diag-mode. */ + GList *iter = usbmoded_get_modelist(); + if( !iter ) { + log_err("Diagnostic mode is not configured!"); + } + else { + mode_list_elem_t *data = iter->data; + log_debug("Entering diagnostic mode!"); + control_set_usb_mode(data->mode_name); + } + goto EXIT; + } + + mode_to_set = config_get_mode_setting(); + + /* If there is only one allowed mode, use it without + * going through ask-mode */ + if( !strcmp(MODE_ASK, mode_to_set) ) { + // FIXME free() vs g_free() conflict + gchar *available = common_get_mode_list(AVAILABLE_MODES_LIST); + if( *available && !strchr(available, ',') ) { + free(mode_to_set), mode_to_set = available, available = 0; + } + g_free(available); + } + + if( mode_to_set && usbmoded_can_export() ) { + control_set_usb_mode(mode_to_set); + } + else { + /* config is corrupted or we do not have a mode configured, fallback to charging + * We also fall back here in case the device is locked and we do not + * export the system contents. Or if we are in acting dead mode. + */ + control_set_usb_mode(MODE_CHARGING_FALLBACK); + } +EXIT: + free(mode_to_set); +} + +/** set the usb connection status + * + * @param cable_state CABLE_STATE_DISCONNECTED, ... + */ +void control_set_cable_state(cable_state_t cable_state) +{ + cable_state_t prev = control_cable_state; + control_cable_state = cable_state; + + if( control_cable_state == prev ) + goto EXIT; + + log_debug("control_cable_state: %s -> %s", + cable_state_repr(prev), + cable_state_repr(control_cable_state)); + + switch( control_cable_state ) { + default: + case CABLE_STATE_DISCONNECTED: + control_set_usb_mode(MODE_UNDEFINED); + break; + case CABLE_STATE_CHARGER_CONNECTED: + control_set_usb_mode(MODE_CHARGER); + break; + case CABLE_STATE_PC_CONNECTED: + control_select_usb_mode(); + break; + } + +EXIT: + return; +} + +/** get the usb connection status + * + * @return CABLE_STATE_DISCONNECTED, ... + */ +cable_state_t control_get_cable_state(void) +{ + return control_cable_state; +} + +void control_clear_cable_state(void) +{ + control_cable_state = CABLE_STATE_UNKNOWN; +} + +/** Get if the cable (pc or charger) is connected or not + * + * @ return true if connected, false if disconnected + */ +bool control_get_connection_state(void) +{ + bool connected = false; + switch( control_get_cable_state() ) { + case CABLE_STATE_CHARGER_CONNECTED: + case CABLE_STATE_PC_CONNECTED: + connected = true; + break; + default: + break; + } + return connected; +} diff --git a/src/usb_moded-control.h b/src/usb_moded-control.h new file mode 100644 index 0000000..0ad22e3 --- /dev/null +++ b/src/usb_moded-control.h @@ -0,0 +1,45 @@ +/** + * @file usb_moded-control.h + * + * Copyright (C) 2013-2018 Jolla. All rights reserved. + * + * @author: Philippe De Swert + * @author: Simo Piiroinen + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Lesser GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program 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 + * General Public License for more details. + * + * You should have received a copy of the Lesser GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef USB_MODED_CONTROL_H_ +# define USB_MODED_CONTROL_H_ + +# include "usb_moded.h" +# include "usb_moded-common.h" + +/* -- usbmoded -- */ + +void control_rethink_usb_charging_fallback(void); +const char *control_get_external_mode (void); +void control_clear_external_mode (void); +const char *control_get_usb_mode (void); +void control_clear_internal_mode (void); +void control_set_usb_mode (const char *mode); +void control_mode_switched (const char *override); +void control_select_usb_mode (void); +void control_set_cable_state (cable_state_t cable_state); +cable_state_t control_get_cable_state (void); +void control_clear_cable_state (void); +bool control_get_connection_state (void); + +#endif /* USB_MODED_CONTROL_H_ */ diff --git a/src/usb_moded-dbus-private.h b/src/usb_moded-dbus-private.h index 837b8f0..cf55720 100644 --- a/src/usb_moded-dbus-private.h +++ b/src/usb_moded-dbus-private.h @@ -27,7 +27,7 @@ #ifndef USB_MODED_DBUS_PRIVATE_H_ # define USB_MODED_DBUS_PRIVATE_H_ -# include "usb_moded-dbus.h" +# include "usb_moded-dbus.h" // NOTRIM # include # include diff --git a/src/usb_moded-dbus.c b/src/usb_moded-dbus.c index 6a06107..b7274a0 100644 --- a/src/usb_moded-dbus.c +++ b/src/usb_moded-dbus.c @@ -30,22 +30,18 @@ * 02110-1301 USA */ -#include -#include - -#include -#include -#include - #include "usb_moded-dbus-private.h" -#include "usb_moded-appsync-dbus-private.h" -#include "usb_moded.h" -#include "usb_moded-modes.h" -#include "usb_moded-modesetting.h" -#include "usb_moded-config.h" + #include "usb_moded-config-private.h" -#include "usb_moded-network.h" +#include "usb_moded-control.h" #include "usb_moded-log.h" +#include "usb_moded-modes.h" +#include "usb_moded-network.h" + +#include +#include + +#include /* ========================================================================= * * Constants @@ -82,11 +78,11 @@ gboolean umdbus_get_name_owner_async (const char *name, * Data * ========================================================================= */ -static DBusConnection *dbus_connection_sys = NULL; -static gboolean have_service_name = FALSE; +static DBusConnection *umdbus_connection = NULL; +static gboolean umdbus_service_name_acquired = FALSE; /** Introspect xml format string for parents of USB_MODE_OBJECT */ -static const char intospect_template[] = +static const char umdbus_introspect_template[] = "\n" "\n" " \n" @@ -104,7 +100,7 @@ static const char intospect_template[] = "\n"; /** Introspect xml data for object path USB_MODE_OBJECT */ -static const char introspect_usb_moded[] = +static const char umdbus_introspect_usbmoded[] = "\n" "\n" @@ -194,25 +190,41 @@ static const char introspect_usb_moded[] = */ static void umdbus_send_config_signal(const char *section, const char *key, const char *value) { - log_debug("broadcast signal %s(%s, %s, %s)\n", USB_MODE_CONFIG_SIGNAL_NAME, section, key, value); + DBusMessage* msg = 0; - if( !have_service_name ) - { + if( !section || !key || !value ) { + log_err("config notification with NULL %s", + !section ? "section" : !key ? "key" : value); + goto EXIT; + } + + if( !umdbus_service_name_acquired ) { log_err("config notification without service: [%s] %s=%s", section, key, value); + goto EXIT; } - else if (dbus_connection_sys) - { - DBusMessage* msg = dbus_message_new_signal(USB_MODE_OBJECT, USB_MODE_INTERFACE, USB_MODE_CONFIG_SIGNAL_NAME); - if (msg) { - dbus_message_append_args(msg, DBUS_TYPE_STRING, §ion, - DBUS_TYPE_STRING, &key, - DBUS_TYPE_STRING, &value, - DBUS_TYPE_INVALID); - dbus_connection_send(dbus_connection_sys, msg, NULL); - dbus_message_unref(msg); - } + + if( !umdbus_connection ) { + log_err("config notification without connection: [%s] %s=%s", + section, key, value); + goto EXIT; } + + log_debug("broadcast signal %s(%s, %s, %s)\n", USB_MODE_CONFIG_SIGNAL_NAME, section, key, value); + + msg = dbus_message_new_signal(USB_MODE_OBJECT, USB_MODE_INTERFACE, USB_MODE_CONFIG_SIGNAL_NAME); + if( !msg ) + goto EXIT; + + dbus_message_append_args(msg, DBUS_TYPE_STRING, §ion, + DBUS_TYPE_STRING, &key, + DBUS_TYPE_STRING, &value, + DBUS_TYPE_INVALID); + dbus_connection_send(umdbus_connection, msg, NULL); + +EXIT: + if( msg ) + dbus_message_unref(msg); } static DBusHandlerResult umdbus_msg_handler(DBusConnection *const connection, DBusMessage *const msg, gpointer const user_data) @@ -240,8 +252,8 @@ static DBusHandlerResult umdbus_msg_handler(DBusConnection *const connection, DB usbmoded_set_init_done(true); /* Auto-disable rescue mode when bootup is finished */ - if( usbmoded_rescue_mode ) { - usbmoded_rescue_mode = FALSE; + if( usbmoded_get_rescue_mode() ) { + usbmoded_set_rescue_mode(false); log_debug("init done reached - rescue mode disabled"); } } @@ -254,7 +266,7 @@ static DBusHandlerResult umdbus_msg_handler(DBusConnection *const connection, DB if(!strcmp(member, USB_MODE_STATE_REQUEST)) { - const char *mode = usbmoded_get_external_mode(); + const char *mode = control_get_external_mode(); /* To the outside we want to keep CHARGING and CHARGING_FALLBACK the same */ if(!strcmp(MODE_CHARGING_FALLBACK, mode)) @@ -264,32 +276,40 @@ static DBusHandlerResult umdbus_msg_handler(DBusConnection *const connection, DB } else if(!strcmp(member, USB_MODE_STATE_SET)) { - char *use = 0; - DBusError err = DBUS_ERROR_INIT; + const char *mode = control_get_external_mode(); + char *use = 0; + DBusError err = DBUS_ERROR_INIT; - if(!dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &use, DBUS_TYPE_INVALID)) + if(!dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &use, DBUS_TYPE_INVALID)) { + log_err("parse error: %s: %s", err.name, err.message); reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, member); - else - { - /* check if usb is connected, since it makes no sense to change mode if it isn't */ - if( usbmoded_get_cable_state() != CABLE_STATE_PC_CONNECTED ) { - log_warning("USB not connected, not changing mode!\n"); - goto error_reply; - } - /* check if the mode exists */ - if(usbmoded_valid_mode(use)) - goto error_reply; - /* do not change mode if the mode requested is the one already set */ - if(strcmp(use, usbmoded_get_usb_mode()) != 0) - { - usbmoded_set_usb_mode(use); - } + } + else if( control_get_cable_state() != CABLE_STATE_PC_CONNECTED ) { + /* Mode change makes no sence unless we have a PC connection */ + log_warning("Mode '%s' requested while not connected to pc", use); + } + else if( common_valid_mode(use) ) { + /* Mode does not exist */ + log_warning("Unknown mode '%s' requested", use); + } + else if( !g_strcmp0(mode, MODE_BUSY) ) { + /* In middle of a pending mode switch */ + log_warning("Mode '%s' requested while busy", use); + } + else { + log_debug("Mode '%s' requested", use); + /* Initiate mode switch */ + control_set_usb_mode(use); + + /* Acknowledge that the mode request was accepted */ if((reply = dbus_message_new_method_return(msg))) dbus_message_append_args (reply, DBUS_TYPE_STRING, &use, DBUS_TYPE_INVALID); - else - error_reply: - reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, member); } + + /* Default to returning a generic error reply */ + if( !reply ) + reply = dbus_message_new_error(msg, DBUS_ERROR_FAILED, member); + dbus_error_free(&err); } else if(!strcmp(member, USB_MODE_CONFIG_SET)) @@ -421,20 +441,13 @@ static DBusHandlerResult umdbus_msg_handler(DBusConnection *const connection, DB { char *config = config_get_mode_setting(); - if(!config) - { - /* Config is corrupted or we do not have a mode - * configured, fallback to undefined. */ - config = g_strdup(MODE_UNDEFINED); - } - if((reply = dbus_message_new_method_return(msg))) dbus_message_append_args (reply, DBUS_TYPE_STRING, &config, DBUS_TYPE_INVALID); g_free(config); } else if(!strcmp(member, USB_MODE_LIST)) { - gchar *mode_list = usbmoded_get_mode_list(SUPPORTED_MODES_LIST); + gchar *mode_list = common_get_mode_list(SUPPORTED_MODES_LIST); if((reply = dbus_message_new_method_return(msg))) dbus_message_append_args (reply, DBUS_TYPE_STRING, (const char *) &mode_list, DBUS_TYPE_INVALID); @@ -442,7 +455,7 @@ static DBusHandlerResult umdbus_msg_handler(DBusConnection *const connection, DB } else if(!strcmp(member, USB_MODE_AVAILABLE_MODES_GET)) { - gchar *mode_list = usbmoded_get_mode_list(AVAILABLE_MODES_LIST); + gchar *mode_list = common_get_mode_list(AVAILABLE_MODES_LIST); if((reply = dbus_message_new_method_return(msg))) dbus_message_append_args (reply, DBUS_TYPE_STRING, (const char *) &mode_list, DBUS_TYPE_INVALID); @@ -450,7 +463,7 @@ static DBusHandlerResult umdbus_msg_handler(DBusConnection *const connection, DB } else if(!strcmp(member, USB_MODE_RESCUE_OFF)) { - usbmoded_rescue_mode = FALSE; + usbmoded_set_rescue_mode(false); log_debug("Rescue mode off\n "); reply = dbus_message_new_method_return(msg); } @@ -539,7 +552,7 @@ static DBusHandlerResult umdbus_msg_handler(DBusConnection *const connection, DB if( pos[len] == 0 ) { /* Full length USB_MODE_OBJECT requested */ - xml = introspect_usb_moded; + xml = umdbus_introspect_usbmoded; } else if( pos[len] == '/' ) { @@ -550,7 +563,7 @@ static DBusHandlerResult umdbus_msg_handler(DBusConnection *const connection, DB pos += len + 1; len = strcspn(pos, "/"); child = g_strndup(pos, len); - xml = tmp = g_strdup_printf(intospect_template, + xml = tmp = g_strdup_printf(umdbus_introspect_template, parent, child); g_free(child); g_free(parent); @@ -563,7 +576,7 @@ static DBusHandlerResult umdbus_msg_handler(DBusConnection *const connection, DB pos += 1; len = strcspn(pos, "/"); child = g_strndup(pos, len); - xml = tmp = g_strdup_printf(intospect_template, + xml = tmp = g_strdup_printf(umdbus_introspect_template, parent, child); g_free(child); } @@ -610,8 +623,8 @@ static DBusHandlerResult umdbus_msg_handler(DBusConnection *const connection, DB DBusConnection *umdbus_get_connection(void) { DBusConnection *connection = 0; - if( dbus_connection_sys ) - connection = dbus_connection_ref(dbus_connection_sys); + if( umdbus_connection ) + connection = dbus_connection_ref(umdbus_connection); else log_err("something asked for connection ref while unconnected"); return connection; @@ -628,24 +641,24 @@ gboolean umdbus_init_connection(void) DBusError error = DBUS_ERROR_INIT; /* connect to system bus */ - if ((dbus_connection_sys = dbus_bus_get(DBUS_BUS_SYSTEM, &error)) == NULL) + if ((umdbus_connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error)) == NULL) { log_debug("Failed to open connection to system message bus; %s\n", error.message); goto EXIT; } /* Initialise message handlers */ - if (!dbus_connection_add_filter(dbus_connection_sys, umdbus_msg_handler, NULL, NULL)) + if (!dbus_connection_add_filter(umdbus_connection, umdbus_msg_handler, NULL, NULL)) goto EXIT; /* Listen to init-done signals */ - dbus_bus_add_match(dbus_connection_sys, INIT_DONE_MATCH, 0); + dbus_bus_add_match(umdbus_connection, INIT_DONE_MATCH, 0); /* Re-check flag file after adding signal listener */ usbmoded_probe_init_done(); /* Connect D-Bus to the mainloop */ - dbus_connection_setup_with_g_main(dbus_connection_sys, NULL); + dbus_connection_setup_with_g_main(umdbus_connection, NULL); /* everything went fine */ status = TRUE; @@ -666,12 +679,12 @@ gboolean umdbus_init_service(void) DBusError error = DBUS_ERROR_INIT; int ret; - if( !dbus_connection_sys ) { + if( !umdbus_connection ) { goto EXIT; } /* Acquire D-Bus service */ - ret = dbus_bus_request_name(dbus_connection_sys, USB_MODE_SERVICE, DBUS_NAME_FLAG_DO_NOT_QUEUE, &error); + ret = dbus_bus_request_name(umdbus_connection, USB_MODE_SERVICE, DBUS_NAME_FLAG_DO_NOT_QUEUE, &error); if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { log_debug("failed claiming dbus name\n"); @@ -680,7 +693,7 @@ gboolean umdbus_init_service(void) goto EXIT; } log_debug("claimed name %s", USB_MODE_SERVICE); - have_service_name = TRUE; + umdbus_service_name_acquired = TRUE; /* everything went fine */ status = TRUE; @@ -693,16 +706,16 @@ gboolean umdbus_init_service(void) */ static void umdbus_cleanup_service(void) { - if( !have_service_name ) + if( !umdbus_service_name_acquired ) goto EXIT; - have_service_name = FALSE; + umdbus_service_name_acquired = FALSE; log_debug("release name %s", USB_MODE_SERVICE); - if( dbus_connection_sys && - dbus_connection_get_is_connected(dbus_connection_sys) ) + if( umdbus_connection && + dbus_connection_get_is_connected(umdbus_connection) ) { - dbus_bus_release_name(dbus_connection_sys, USB_MODE_SERVICE, NULL); + dbus_bus_release_name(umdbus_connection, USB_MODE_SERVICE, NULL); } EXIT: @@ -716,14 +729,14 @@ static void umdbus_cleanup_service(void) void umdbus_cleanup(void) { /* clean up system bus connection */ - if (dbus_connection_sys != NULL) + if (umdbus_connection != NULL) { umdbus_cleanup_service(); - dbus_connection_remove_filter(dbus_connection_sys, umdbus_msg_handler, NULL); + dbus_connection_remove_filter(umdbus_connection, umdbus_msg_handler, NULL); - dbus_connection_unref(dbus_connection_sys), - dbus_connection_sys = NULL; + dbus_connection_unref(umdbus_connection), + umdbus_connection = NULL; } } @@ -739,15 +752,20 @@ static int umdbus_send_signal_ex(const char *signal_type, const char *content) int result = 1; DBusMessage* msg = 0; + /* Assume NULL content equals no value / empty list, and that skipping + * signal broadcast is never preferable over sending empty string. */ + if( !content ) + content = ""; + log_debug("broadcast signal %s(%s)\n", signal_type, content); - if( !have_service_name ) + if( !umdbus_service_name_acquired ) { log_err("sending signal without service: %s(%s)", signal_type, content); goto EXIT; } - if(!dbus_connection_sys) + if(!umdbus_connection) { log_err("Dbus system connection broken!\n"); goto EXIT; @@ -768,7 +786,7 @@ static int umdbus_send_signal_ex(const char *signal_type, const char *content) } // send the message on the correct bus and flush the connection - if (!dbus_connection_send(dbus_connection_sys, msg, 0)) + if (!dbus_connection_send(umdbus_connection, msg, 0)) { log_debug("Failed sending message. Out Of Memory!\n"); goto EXIT; @@ -792,7 +810,7 @@ static int umdbus_send_signal_ex(const char *signal_type, const char *content) */ int umdbus_send_state_signal(const char *state_ind) { - return(umdbus_send_signal_ex(USB_MODE_SIGNAL_NAME, state_ind)); + return umdbus_send_signal_ex(USB_MODE_SIGNAL_NAME, state_ind); } /** @@ -804,7 +822,7 @@ int umdbus_send_state_signal(const char *state_ind) */ int umdbus_send_error_signal(const char *error) { - return(umdbus_send_signal_ex(USB_MODE_ERROR_SIGNAL_NAME, error)); + return umdbus_send_signal_ex(USB_MODE_ERROR_SIGNAL_NAME, error); } /** @@ -816,7 +834,7 @@ int umdbus_send_error_signal(const char *error) */ int umdbus_send_supported_modes_signal(const char *supported_modes) { - return(umdbus_send_signal_ex(USB_MODE_SUPPORTED_MODES_SIGNAL_NAME, supported_modes)); + return umdbus_send_signal_ex(USB_MODE_SUPPORTED_MODES_SIGNAL_NAME, supported_modes); } /** @@ -828,7 +846,7 @@ int umdbus_send_supported_modes_signal(const char *supported_modes) */ int umdbus_send_available_modes_signal(const char *available_modes) { - return(umdbus_send_signal_ex(USB_MODE_AVAILABLE_MODES_SIGNAL_NAME, available_modes)); + return umdbus_send_signal_ex(USB_MODE_AVAILABLE_MODES_SIGNAL_NAME, available_modes); } /** @@ -840,7 +858,7 @@ int umdbus_send_available_modes_signal(const char *available_modes) */ int umdbus_send_hidden_modes_signal(const char *hidden_modes) { - return(umdbus_send_signal_ex(USB_MODE_HIDDEN_MODES_SIGNAL_NAME, hidden_modes)); + return umdbus_send_signal_ex(USB_MODE_HIDDEN_MODES_SIGNAL_NAME, hidden_modes); } /** @@ -851,7 +869,7 @@ int umdbus_send_hidden_modes_signal(const char *hidden_modes) */ int umdbus_send_whitelisted_modes_signal(const char *whitelist) { - return(umdbus_send_signal_ex(USB_MODE_WHITELISTED_MODES_SIGNAL_NAME, whitelist)); + return umdbus_send_signal_ex(USB_MODE_WHITELISTED_MODES_SIGNAL_NAME, whitelist); } /** Async reply handler for umdbus_get_name_owner_async() @@ -914,7 +932,7 @@ gboolean umdbus_get_name_owner_async(const char *name, DBusMessage *req = 0; DBusPendingCall *pc = 0; - if(!dbus_connection_sys) + if(!umdbus_connection) goto EXIT; req = dbus_message_new_method_call(DBUS_INTERFACE_DBUS, @@ -933,7 +951,7 @@ gboolean umdbus_get_name_owner_async(const char *name, goto EXIT; } - if( !dbus_connection_send_with_reply(dbus_connection_sys, req, &pc, -1) ) + if( !dbus_connection_send_with_reply(umdbus_connection, req, &pc, -1) ) goto EXIT; if( !pc ) diff --git a/src/usb_moded-devicelock.c b/src/usb_moded-devicelock.c index bc90a9f..bd2efa5 100644 --- a/src/usb_moded-devicelock.c +++ b/src/usb_moded-devicelock.c @@ -32,32 +32,29 @@ * Interacts with the devicelock to know if we can expose the system contents or not */ -#include -#include -#include -#include - #include "usb_moded-devicelock.h" -#include "usb_moded-log.h" -#include "usb_moded.h" -#include "usb_moded-modes.h" + +#include "usb_moded-control.h" #include "usb_moded-dbus-private.h" +#include "usb_moded-log.h" + +#include /* ========================================================================= * * Types * ========================================================================= */ /** Devicelock states */ -typedef enum +typedef enum devicelock_state_t { /** Devicelock is not active */ - DEVICE_LOCK_UNLOCKED = 0, + DEVICELOCK_UNLOCKED = 0, /** Devicelock is active */ - DEVICE_LOCK_LOCKED = 1, + DEVICELOCK_LOCKED = 1, /** Initial startup value; from usb-moded p.o.v. equals locked */ - DEVICE_LOCK_UNDEFINED = 2, + DEVICELOCK_UNDEFINED = 2, } devicelock_state_t; /* ========================================================================= * @@ -90,7 +87,7 @@ void devicelock_stop_listener (void); static DBusConnection *devicelock_con = NULL; /* Cached devicelock state */ -static devicelock_state_t device_lock_state = DEVICE_LOCK_UNDEFINED; +static devicelock_state_t devicelock_state = DEVICELOCK_UNDEFINED; /* Flag for: devicelock is available on system bus */ static gboolean devicelock_is_available = FALSE; @@ -104,13 +101,13 @@ static gboolean devicelock_is_available = FALSE; static const char * devicelock_state_repr(devicelock_state_t state) { - const char *repr = "DEVICE_LOCK_"; + const char *repr = "DEVICELOCK_"; switch( state ) { - case DEVICE_LOCK_UNLOCKED: repr = "DEVICE_LOCK_UNLOCKED"; break; - case DEVICE_LOCK_LOCKED: repr = "DEVICE_LOCK_LOCKED"; break; - case DEVICE_LOCK_UNDEFINED: repr = "DEVICE_LOCK_UNDEFINED"; break; + case DEVICELOCK_UNLOCKED: repr = "DEVICELOCK_UNLOCKED"; break; + case DEVICELOCK_LOCKED: repr = "DEVICELOCK_LOCKED"; break; + case DEVICELOCK_UNDEFINED: repr = "DEVICELOCK_UNDEFINED"; break; default: break; } @@ -128,7 +125,7 @@ devicelock_state_repr(devicelock_state_t state) */ bool devicelock_have_export_permission(void) { - bool unlocked = (device_lock_state == DEVICE_LOCK_UNLOCKED); + bool unlocked = (devicelock_state == DEVICELOCK_UNLOCKED); return unlocked; } @@ -139,15 +136,15 @@ bool devicelock_have_export_permission(void) static void devicelock_state_changed(devicelock_state_t state) { - if( device_lock_state == state ) + if( devicelock_state == state ) goto EXIT; log_debug("devicelock state: %s -> %s", - devicelock_state_repr(device_lock_state), + devicelock_state_repr(devicelock_state), devicelock_state_repr(state)); - device_lock_state = state; + devicelock_state = state; - usbmoded_rethink_usb_charging_fallback(); + control_rethink_usb_charging_fallback(); EXIT: return; @@ -167,7 +164,7 @@ static void devicelock_state_cancel(void) static void devicelock_state_query_cb(DBusPendingCall *pending, void *aptr) { DBusMessage *rsp = 0; - dbus_int32_t dta = DEVICE_LOCK_UNDEFINED; + dbus_int32_t dta = DEVICELOCK_UNDEFINED; DBusError err = DBUS_ERROR_INIT; (void)aptr; @@ -253,7 +250,7 @@ static void devicelock_state_query(void) static void devicelock_state_signal(DBusMessage *msg) { DBusError err = DBUS_ERROR_INIT; - dbus_int32_t dta = DEVICE_LOCK_LOCKED; + dbus_int32_t dta = DEVICELOCK_LOCKED; if( !dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &dta, @@ -283,7 +280,7 @@ static void devicelock_available_changed(const char *owner) devicelock_is_available ? "running" : "stopped"); /* Forget cached device state */ - devicelock_state_changed(DEVICE_LOCK_UNDEFINED); + devicelock_state_changed(DEVICELOCK_UNDEFINED); /* Query current state on devicelock startup */ if( devicelock_is_available ) { diff --git a/src/usb_moded-dsme.c b/src/usb_moded-dsme.c index 2cef64a..ddf278c 100644 --- a/src/usb_moded-dsme.c +++ b/src/usb_moded-dsme.c @@ -22,15 +22,15 @@ * 02110-1301 USA */ -#include - -#include - -#include "usb_moded.h" #include "usb_moded-dsme.h" -#include "usb_moded-modesetting.h" + +#include "usb_moded-control.h" #include "usb_moded-dbus-private.h" #include "usb_moded-log.h" +#include "usb_moded-modesetting.h" + +#include +#include #include #include @@ -133,7 +133,7 @@ static const struct } dsme_states[] = { #define DSME_STATE(NAME, VALUE) { #NAME, DSME_STATE_##NAME }, -#include +#include // NOTRIM #undef DSME_STATE }; @@ -200,7 +200,7 @@ dsme_state_update(dsme_state_t state) dsme_user_state = user_state; log_debug("in user state: %s", dsme_user_state ? "true" : "false"); - usbmoded_rethink_usb_charging_fallback(); + control_rethink_usb_charging_fallback(); } /* Handle entry to / exit from SHUTDOWN / REBOOT state */ diff --git a/src/usb_moded-dsme.h b/src/usb_moded-dsme.h index 9f21c8b..11c3ff8 100644 --- a/src/usb_moded-dsme.h +++ b/src/usb_moded-dsme.h @@ -22,12 +22,14 @@ */ #ifndef MEEGOLOCK -# warning usb_moded-dsme.h included without enabling MEEGOLOCK +# warning usb_moded-dsme.h used without enabling MEEGOLOCK #endif #ifndef USB_MODED_DSME_H_ # define USB_MODED_DSME_H_ +# include + /* ========================================================================= * * Prototypes * ========================================================================= */ diff --git a/src/usb_moded-dyn-config.c b/src/usb_moded-dyn-config.c index 2380257..c769fb8 100644 --- a/src/usb_moded-dyn-config.c +++ b/src/usb_moded-dyn-config.c @@ -26,34 +26,29 @@ * 02110-1301 USA */ -#include -#include -#include -#include - -#include -#include - #include "usb_moded-dyn-config.h" + #include "usb_moded-log.h" +#include + /* ========================================================================= * * Prototypes * ========================================================================= */ /* -- dynconfig -- */ -void dynconfig_free_list_item(mode_list_elem *list_item); +void dynconfig_free_list_item(mode_list_elem_t *list_item); void dynconfig_free_mode_list(GList *modelist); static gint dynconfig_compare_modes (gconstpointer a, gconstpointer b); GList *dynconfig_read_mode_list(int diag); -static struct mode_list_elem *dynconfig_read_mode_file(const gchar *filename); +static mode_list_elem_t *dynconfig_read_mode_file(const gchar *filename); /* ========================================================================= * * Functions * ========================================================================= */ -void dynconfig_free_list_item(mode_list_elem *list_item) +void dynconfig_free_list_item(mode_list_elem_t *list_item) { if( list_item ) { free(list_item->mode_name); @@ -91,8 +86,8 @@ void dynconfig_free_mode_list(GList *modelist) static gint dynconfig_compare_modes(gconstpointer a, gconstpointer b) { - struct mode_list_elem *aa = (struct mode_list_elem *)a; - struct mode_list_elem *bb = (struct mode_list_elem *)b; + mode_list_elem_t *aa = (mode_list_elem_t *)a; + mode_list_elem_t *bb = (mode_list_elem_t *)b; return g_strcmp0(aa->mode_name, bb->mode_name); } @@ -102,7 +97,7 @@ GList *dynconfig_read_mode_list(int diag) GDir *confdir; GList *modelist = NULL; const gchar *dirname; - struct mode_list_elem *list_item; + mode_list_elem_t *list_item; gchar *full_filename = NULL; if(diag) @@ -130,14 +125,14 @@ GList *dynconfig_read_mode_list(int diag) log_debug("Mode confdir open failed or file is incomplete/invalid.\n"); modelist = g_list_sort (modelist, dynconfig_compare_modes); - return(modelist); + return modelist; } -static struct mode_list_elem *dynconfig_read_mode_file(const gchar *filename) +static mode_list_elem_t *dynconfig_read_mode_file(const gchar *filename) { bool success = false; GKeyFile *settingsfile = g_key_file_new(); - struct mode_list_elem *list_item = NULL; + mode_list_elem_t *list_item = NULL; if( !g_key_file_load_from_file(settingsfile, filename, G_KEY_FILE_NONE, NULL) ) { log_err("%s: can't read mode configuration file", filename); diff --git a/src/usb_moded-dyn-config.h b/src/usb_moded-dyn-config.h index 099574a..ba79f01 100644 --- a/src/usb_moded-dyn-config.h +++ b/src/usb_moded-dyn-config.h @@ -30,6 +30,8 @@ #ifndef USB_MODED_DYN_CONFIG_H_ # define USB_MODED_DYN_CONFIG_H_ +# include + /* ========================================================================= * * Constants * ========================================================================= */ @@ -91,7 +93,7 @@ /** * Struct keeping all the data needed for the definition of a dynamic mode */ -typedef struct mode_list_elem +typedef struct mode_list_elem_t { char *mode_name; /**< Mode name */ char *mode_module; /**< Needed module for given mode */ @@ -117,7 +119,7 @@ typedef struct mode_list_elem # ifdef CONNMAN char* connman_tethering; /**< Connman's tethering technology path */ # endif -} mode_list_elem; +} mode_list_elem_t; /* ========================================================================= * * Prototypes @@ -125,7 +127,7 @@ typedef struct mode_list_elem /* -- dynconfig -- */ -void dynconfig_free_list_item(mode_list_elem *list_item); +void dynconfig_free_list_item(mode_list_elem_t *list_item); void dynconfig_free_mode_list(GList *modelist); GList *dynconfig_read_mode_list(int diag); diff --git a/src/usb_moded-log.c b/src/usb_moded-log.c index dd72bee..b86cf77 100644 --- a/src/usb_moded-log.c +++ b/src/usb_moded-log.c @@ -25,15 +25,12 @@ * 02110-1301 USA */ -#include -#include -#include -#include +#include "usb_moded-log.h" + #include -#include -#include -#include "usb_moded-log.h" +#include +#include /* ========================================================================= * * Prototypes diff --git a/src/usb_moded-log.h b/src/usb_moded-log.h index 85d0d42..0b37a38 100644 --- a/src/usb_moded-log.h +++ b/src/usb_moded-log.h @@ -24,10 +24,6 @@ # define USB_MODED_LOG_H_ # include -# include -# include -# include -# include # include # include @@ -47,6 +43,12 @@ enum LOG_TO_SYSLOG, // log to syslog }; +enum +{ + LOG_MIN_LEVEL = LOG_CRIT, + LOG_MAX_LEVEL = LOG_DEBUG, +}; + /* ========================================================================= * * Prototypes * ========================================================================= */ diff --git a/src/usb_moded-mac.c b/src/usb_moded-mac.c index e7f788d..2669c4e 100644 --- a/src/usb_moded-mac.c +++ b/src/usb_moded-mac.c @@ -21,10 +21,14 @@ * 02110-1301 USA */ -#include #include "usb_moded-mac.h" + #include "usb_moded-log.h" +#include +#include +#include + /* ========================================================================= * * Prototypes * ========================================================================= */ @@ -93,7 +97,7 @@ char * mac_read_mac(void) if(!g_ether) { log_warning("Failed to read mac address from /etc/modprobe.d/g_ether.conf\n"); - return(NULL); + return NULL; } test = fseek(g_ether, 26, SEEK_SET); if(test == -1) @@ -101,7 +105,7 @@ char * mac_read_mac(void) fclose(g_ether); return 0; } - mac = malloc(sizeof(char) *17); + mac = malloc(17); if(mac) read = fread(mac, 1, 17, g_ether); if(read == 17) @@ -111,5 +115,5 @@ char * mac_read_mac(void) free(mac); fclose(g_ether); - return(ret); + return ret; } diff --git a/src/usb_moded-modesetting.c b/src/usb_moded-modesetting.c index 8d96b0d..3c99836 100644 --- a/src/usb_moded-modesetting.c +++ b/src/usb_moded-modesetting.c @@ -28,27 +28,26 @@ * 02110-1301 USA */ -#include -#include -#include -#include -#include -#include -#include - -#include +#include "usb_moded-modesetting.h" #include "usb_moded.h" -#include "usb_moded-modules.h" -#include "usb_moded-modes.h" -#include "usb_moded-log.h" -#include "usb_moded-dbus-private.h" + +#include "usb_moded-android.h" #include "usb_moded-appsync.h" +#include "usb_moded-common.h" #include "usb_moded-config-private.h" -#include "usb_moded-modesetting.h" -#include "usb_moded-network.h" -#include "usb_moded-android.h" #include "usb_moded-configfs.h" +#include "usb_moded-dbus-private.h" +#include "usb_moded-log.h" +#include "usb_moded-modules.h" +#include "usb_moded-network.h" +#include "usb_moded-worker.h" + +#include +#include +#include +#include +#include /* ========================================================================= * * Prototypes @@ -63,10 +62,8 @@ static char *modesetting_strip (char *str); static char *modesetting_read_from_file (const char *path, size_t maxsize); int modesetting_write_to_file_real (const char *file, int line, const char *func, const char *path, const char *text); -static gboolean modesetting_network_retry_cb (gpointer data); - -static bool modesetting_enter_mass_storage_mode (struct mode_list_elem *data); -static int modesetting_leave_mass_storage_mode (struct mode_list_elem *data); +static bool modesetting_enter_mass_storage_mode (mode_list_elem_t *data); +static int modesetting_leave_mass_storage_mode (mode_list_elem_t *data); static void modesetting_report_mass_storage_blocker(const char *mountpoint, int try); bool modesetting_enter_dynamic_mode (void); @@ -80,7 +77,6 @@ void modesetting_quit (void); * ========================================================================= */ static GHashTable *tracked_values = 0; -static guint modesetting_network_retry_id = 0; /* ========================================================================= * * Functions @@ -274,13 +270,6 @@ int modesetting_write_to_file_real(const char *file, int line, const char *func, return err; } -static gboolean modesetting_network_retry_cb(gpointer data) -{ - modesetting_network_retry_id = 0; - network_up(data); - return(FALSE); -} - #include typedef struct storage_info_t @@ -301,21 +290,21 @@ bool modesetting_is_mounted(const char *mountpoint) { char cmd[256]; snprintf(cmd, sizeof cmd, "/bin/mountpoint -q '%s'", mountpoint); - return usbmoded_system(cmd) == 0; + return common_system(cmd) == 0; } bool modesetting_mount(const char *mountpoint) { char cmd[256]; snprintf(cmd, sizeof cmd, "/bin/mount '%s'", mountpoint); - return usbmoded_system(cmd) == 0; + return common_system(cmd) == 0; } bool modesetting_unmount(const char *mountpoint) { char cmd[256]; snprintf(cmd, sizeof cmd, "/bin/umount '%s'", mountpoint); - return usbmoded_system(cmd) == 0; + return common_system(cmd) == 0; } gchar *modesetting_mountdev(const char *mountpoint) @@ -416,7 +405,7 @@ modesetting_get_storage_info(size_t *pcount) return *pcount = count, info; } -static bool modesetting_enter_mass_storage_mode(struct mode_list_elem *data) +static bool modesetting_enter_mass_storage_mode(mode_list_elem_t *data) { bool ack = false; size_t count = 0; @@ -466,7 +455,7 @@ static bool modesetting_enter_mass_storage_mode(struct mode_list_elem *data) log_warning("failed to unmount %s - wait a bit", mountpnt); modesetting_report_mass_storage_blocker(mountpnt, 1); - usbmoded_sleep(1); + common_sleep(1); } } @@ -510,12 +499,12 @@ static bool modesetting_enter_mass_storage_mode(struct mode_list_elem *data) modules_unload_module(MODULE_MASS_STORAGE); snprintf(tmp, sizeof tmp, "modprobe %s luns=%zd \n", MODULE_MASS_STORAGE, count); log_debug("usb-load command = %s \n", tmp); - if( usbmoded_system(tmp) != 0 ) + if( common_system(tmp) != 0 ) goto EXIT; } /* activate mounts after sleeping 1s to be sure enumeration happened and autoplay will work in windows*/ - usbmoded_sleep(1); + common_sleep(1); for( size_t i = 0 ; i < count; ++i ) { const gchar *mountdev = info[i].si_mountdevice; @@ -552,8 +541,10 @@ static bool modesetting_enter_mass_storage_mode(struct mode_list_elem *data) return ack; } -static int modesetting_leave_mass_storage_mode(struct mode_list_elem *data) +static int modesetting_leave_mass_storage_mode(mode_list_elem_t *data) { + (void)data; + bool ack = false; size_t count = 0; storage_info_t *info = 0; @@ -653,7 +644,7 @@ static void modesetting_report_mass_storage_blocker(const char *mountpoint, int lsof_command = g_strconcat("lsof ", mountpoint, NULL); - if( (stream = usbmoded_popen(lsof_command, "r")) ) + if( (stream = common_popen(lsof_command, "r")) ) { char *text = 0; size_t size = 0; @@ -684,8 +675,7 @@ bool modesetting_enter_dynamic_mode(void) { bool ack = false; - struct mode_list_elem *data; - int network = 1; + mode_list_elem_t *data; log_debug("DYNAMIC MODE: SETUP"); @@ -693,7 +683,7 @@ bool modesetting_enter_dynamic_mode(void) * Is a dynamic mode? * - - - - - - - - - - - - - - - - - - - */ - if( !(data = usbmoded_get_usb_mode_data()) ) { + if( !(data = worker_get_usb_mode_data()) ) { log_debug("No dynamic mode data to setup"); goto EXIT; } @@ -776,21 +766,22 @@ bool modesetting_enter_dynamic_mode(void) char command[256]; g_snprintf(command, 256, "ifdown %s ; ifup %s", data->network_interface, data->network_interface); - usbmoded_system(command); + common_system(command); #else network_down(data); - network = network_up(data); -#endif /* DEBIAN */ - } + int error = network_up(data); - /* try a second time to bring up the network if it failed the first time, - * this can happen with functionfs based gadgets (which is why we sleep for a bit */ - if(network != 0 && data->network) - { - log_debug("Retry setting up the network later\n"); - if(modesetting_network_retry_id) - g_source_remove(modesetting_network_retry_id); - modesetting_network_retry_id = g_timeout_add_seconds(3, modesetting_network_retry_cb, data); + /* In case of failure, retry upto 3 times */ + for( int i = 0; error && i < 3; ++i ) { + log_warning("Retry setting up the network"); + if( !common_msleep(1000) ) + break; + if( !(error = network_up(data)) ) + log_warning("Setting up the network succeeded"); + } + if( error ) + log_err("Setting up the network failed"); +#endif /* DEBIAN */ } /* Needs to be called before application post synching so @@ -807,7 +798,7 @@ bool modesetting_enter_dynamic_mode(void) { log_debug("Dynamic mode is appsync: do post actions"); /* let's sleep for a bit (350ms) to allow interfaces to settle before running postsync */ - usbmoded_msleep(350); + common_msleep(350); appsync_activate_sync_post(data->mode_name); } @@ -834,19 +825,9 @@ void modesetting_leave_dynamic_mode(void) { log_debug("DYNAMIC MODE: CLEANUP"); - struct mode_list_elem *data; + mode_list_elem_t *data; - data = usbmoded_get_usb_mode_data(); - - /* - - - - - - - - - - - - - - - - - - - * - * Do not leave timers behind - * - - - - - - - - - - - - - - - - - - - */ - - if(modesetting_network_retry_id) - { - g_source_remove(modesetting_network_retry_id); - modesetting_network_retry_id = 0; - } + data = worker_get_usb_mode_data(); /* - - - - - - - - - - - - - - - - - - - * * Is a dynamic mode? diff --git a/src/usb_moded-modesetting.h b/src/usb_moded-modesetting.h index d3eabbe..4ae9c46 100644 --- a/src/usb_moded-modesetting.h +++ b/src/usb_moded-modesetting.h @@ -29,8 +29,6 @@ #ifndef USB_MODED_MODESETTING_H_ # define USB_MODED_MODESETTING_H_ -# include "usb_moded-dyn-config.h" - # include /* ========================================================================= * diff --git a/src/usb_moded-modules.c b/src/usb_moded-modules.c index aae64d8..fb54921 100644 --- a/src/usb_moded-modules.c +++ b/src/usb_moded-modules.c @@ -27,23 +27,16 @@ * 02110-1301 USA */ +#include "usb_moded-modules.h" + +#include "usb_moded-log.h" + #include -#include #include -#include - -#include -#include #include -#include "usb_moded.h" -#include "usb_moded-modules.h" -#include "usb_moded-log.h" -#include "usb_moded-config.h" -#include "usb_moded-dbus-private.h" -#include "usb_moded-modesetting.h" -#include "usb_moded-modes.h" +#include /* ========================================================================= * * Prototypes @@ -231,7 +224,7 @@ int modules_load_module(const char *module) log_info("Module %s loaded successfully\n", module); else log_info("Module %s failed to load\n", module); - return(ret); + return ret; } /** unload module @@ -258,5 +251,5 @@ int modules_unload_module(const char *module) ret = kmod_module_remove_module(mod, KMOD_REMOVE_NOWAIT); kmod_module_unref(mod); - return(ret); + return ret; } diff --git a/src/usb_moded-network.c b/src/usb_moded-network.c index 14d7a4b..034adda 100644 --- a/src/usb_moded-network.c +++ b/src/usb_moded-network.c @@ -28,26 +28,22 @@ /*============================================================================= */ -#include -#include -#include -#include - -#include -#include - -#include - -#include "usb_moded.h" #include "usb_moded-network.h" + #include "usb_moded-config-private.h" +#include "usb_moded-control.h" #include "usb_moded-log.h" #include "usb_moded-modesetting.h" +#include "usb_moded-worker.h" + +#include + +#include +#include +#include #if CONNMAN || OFONO # include -# include -# include #endif /* ========================================================================= * @@ -63,7 +59,7 @@ * ========================================================================= */ /** IP forwarding configuration block */ -typedef struct ipforward_data +typedef struct ipforward_data_t { /** Address of primary DNS */ char *dns1; @@ -71,7 +67,7 @@ typedef struct ipforward_data char *dns2; /** Interface from which packets should be forwarded */ char *nat_interface; -}ipforward_data; +}ipforward_data_t; /* ========================================================================= * * Prototypes @@ -79,16 +75,16 @@ typedef struct ipforward_data /* -- network -- */ -static void network_free_ipforward_data (struct ipforward_data *ipforward); +static void network_free_ipforward_data (ipforward_data_t *ipforward); static int network_check_interface (char *interface); -static char *network_get_interface (struct mode_list_elem *data); -static int network_set_usb_ip_forward (struct mode_list_elem *data, struct ipforward_data *ipforward); +static char *network_get_interface (mode_list_elem_t *data); +static int network_set_usb_ip_forward (mode_list_elem_t *data, ipforward_data_t *ipforward); static void network_clean_usb_ip_forward(void); static int network_checklink (void); -static int network_write_udhcpd_conf (struct ipforward_data *ipforward, struct mode_list_elem *data); -int network_set_up_dhcpd (struct mode_list_elem *data); -int network_up (struct mode_list_elem *data); -int network_down (struct mode_list_elem *data); +static int network_write_udhcpd_conf (ipforward_data_t *ipforward, mode_list_elem_t *data); +int network_set_up_dhcpd (mode_list_elem_t *data); +int network_up (mode_list_elem_t *data); +int network_down (mode_list_elem_t *data); int network_update (void); /* -- connman -- */ @@ -97,10 +93,10 @@ int network_update (void); static gboolean connman_try_set_tethering (DBusConnection *connection, const char *path, gboolean on); gboolean connman_set_tethering (const char *path, gboolean on); static char *connman_parse_manager_reply (DBusMessage *reply, const char *req_service); -static int connman_fill_connection_data(DBusMessage *reply, struct ipforward_data *ipforward); +static int connman_fill_connection_data(DBusMessage *reply, ipforward_data_t *ipforward); static int connman_set_cellular_online (DBusConnection *dbus_conn_connman, const char *service, int retry); static int connman_wifi_power_control (DBusConnection *dbus_conn_connman, int on); -static int connman_get_connection_data (struct ipforward_data *ipforward); +static int connman_get_connection_data (ipforward_data_t *ipforward); static int connman_reset_state (void); #endif @@ -114,7 +110,7 @@ static const char default_interface[] = "usb0"; * Functions * ========================================================================= */ -static void network_free_ipforward_data (struct ipforward_data *ipforward) +static void network_free_ipforward_data (ipforward_data_t *ipforward) { if(ipforward) { @@ -143,7 +139,7 @@ static int network_check_interface(char *interface) return ret; } -static char* network_get_interface(struct mode_list_elem *data) +static char* network_get_interface(mode_list_elem_t *data) { (void)data; // FIXME: why is this passed in the 1st place? @@ -178,14 +174,14 @@ static char* network_get_interface(struct mode_list_elem *data) * Turn on ip forwarding on the usb interface * @return: 0 on success, 1 on failure */ -static int network_set_usb_ip_forward(struct mode_list_elem *data, struct ipforward_data *ipforward) +static int network_set_usb_ip_forward(mode_list_elem_t *data, ipforward_data_t *ipforward) { char *interface, *nat_interface; char command[128]; interface = network_get_interface(data); if(interface == NULL) - return(1); + return 1; nat_interface = config_get_network_setting(NETWORK_NAT_INTERFACE_KEY); if((nat_interface == NULL) && (ipforward->nat_interface != NULL)) nat_interface = strdup(ipforward->nat_interface); @@ -198,22 +194,22 @@ static int network_set_usb_ip_forward(struct mode_list_elem *data, struct ipforw #endif free(interface); free(nat_interface); - return(1); + return 1; } write_to_file("/proc/sys/net/ipv4/ip_forward", "1"); snprintf(command, 128, "/sbin/iptables -t nat -A POSTROUTING -o %s -j MASQUERADE", nat_interface); - usbmoded_system(command); + common_system(command); snprintf(command, 128, "/sbin/iptables -A FORWARD -i %s -o %s -m state --state RELATED,ESTABLISHED -j ACCEPT", nat_interface, interface); - usbmoded_system(command); + common_system(command); snprintf(command, 128, "/sbin/iptables -A FORWARD -i %s -o %s -j ACCEPT", interface, nat_interface); - usbmoded_system(command); + common_system(command); free(interface); free(nat_interface); log_debug("ipforwarding success!\n"); - return(0); + return 0; } /** @@ -225,7 +221,7 @@ static void network_clean_usb_ip_forward(void) connman_reset_state(); #endif write_to_file("/proc/sys/net/ipv4/ip_forward", "0"); - usbmoded_system("/sbin/iptables -F FORWARD"); + common_system("/sbin/iptables -F FORWARD"); } #ifdef OFONO @@ -298,7 +294,7 @@ static int get_roaming(void) ret = 1; } - return(ret); + return ret; } #endif @@ -306,7 +302,7 @@ static int get_roaming(void) /** * Read dns settings from /etc/resolv.conf */ -static int resolv_conf_dns(struct ipforward_data *ipforward) +static int resolv_conf_dns(ipforward_data_t *ipforward) { FILE *resolv; int i = 0, count = 0; @@ -316,7 +312,7 @@ static int resolv_conf_dns(struct ipforward_data *ipforward) resolv = fopen("/etc/resolv.conf", "r"); if (resolv == NULL) - return(1); + return 1; /* we don't expect more than 10 lines in /etc/resolv.conf */ for (i=0; i < 10; i++) @@ -341,29 +337,29 @@ static int resolv_conf_dns(struct ipforward_data *ipforward) end: free(line); fclose(resolv); - return(0); + return 0; } #endif static int network_checklink(void) { int ret = -1; - char dest[sizeof(UDHCP_CONFIG_PATH)+1]; - size_t len = readlink(UDHCP_CONFIG_LINK, dest, sizeof(dest)-1); + char dest[sizeof UDHCP_CONFIG_PATH + 1]; + size_t len = readlink(UDHCP_CONFIG_LINK, dest, sizeof dest - 1); if (len > 0) { dest[len] = 0; ret = strcmp(dest, UDHCP_CONFIG_PATH); } - return(ret); + return ret; } /** * Write udhcpd.conf * @ipforward : NULL if we want a simple config, otherwise include dns info etc... */ -static int network_write_udhcpd_conf(struct ipforward_data *ipforward, struct mode_list_elem *data) +static int network_write_udhcpd_conf(ipforward_data_t *ipforward, mode_list_elem_t *data) { FILE *conffile; char *ip, *interface, *netmask; @@ -377,19 +373,19 @@ static int network_write_udhcpd_conf(struct ipforward_data *ipforward, struct mo if(conffile == NULL) { log_debug("Error creating "UDHCP_CONFIG_PATH"!\n"); - return(1); + return 1; } interface = network_get_interface(data); if(interface == NULL) { fclose(conffile); - return(1); + return 1; } /* generate start and end ip based on the setting */ ip = config_get_network_setting(NETWORK_IP_KEY); - ipstart = malloc(sizeof(char)*15); - ipend = malloc(sizeof(char)*15); + ipstart = malloc(15); + ipend = malloc(15); while(i < 15) { if(dot < 3) @@ -456,12 +452,12 @@ static int network_write_udhcpd_conf(struct ipforward_data *ipforward, struct mo { log_debug("Error creating link "UDHCP_CONFIG_LINK" -> "UDHCP_CONFIG_PATH": %m\n"); unlink(UDHCP_CONFIG_PATH); - return(1); + return 1; } end: log_debug(UDHCP_CONFIG_LINK" created\n"); - return(0); + return 0; } #ifdef CONNMAN @@ -537,7 +533,8 @@ gboolean connman_set_tethering(const char *path, gboolean on) { if (i>0) { - usbmoded_msleep(200); + if( !common_msleep(200) ) + break; } if (connman_try_set_tethering(connection, path, on)) { @@ -586,7 +583,7 @@ static char * connman_parse_manager_reply(DBusMessage *reply, const char *req_se if(strstr(service, req_service)) { log_debug("%s service found!\n", req_service); - return(strdup(service)); + return strdup(service); } } } @@ -595,10 +592,10 @@ static char * connman_parse_manager_reply(DBusMessage *reply, const char *req_se iter = origiter; } log_debug("end of list\n"); - return(0); + return 0; } -static int connman_fill_connection_data(DBusMessage *reply, struct ipforward_data *ipforward) +static int connman_fill_connection_data(DBusMessage *reply, ipforward_data_t *ipforward) { DBusMessageIter array_iter, dict_iter, inside_dict_iter, variant_iter; DBusMessageIter sub_array_iter, string_iter; @@ -634,7 +631,7 @@ static int connman_fill_connection_data(DBusMessage *reply, struct ipforward_dat if(type != DBUS_TYPE_STRING) { /* not online */ - return(1); + return 1; } dbus_message_iter_get_basic(&string_iter, &string); log_debug("dns = %s\n", string); @@ -645,12 +642,12 @@ static int connman_fill_connection_data(DBusMessage *reply, struct ipforward_dat log_debug("No secundary dns\n"); /* FIXME: set the same dns for dns2 to avoid breakage */ ipforward->dns2 = strdup(string); - return(0); + return 0; } dbus_message_iter_get_basic(&string_iter, &string); log_debug("dns2 = %s\n", string); ipforward->dns2 = strdup(string); - return(0); + return 0; } } else if(!strcmp(string, "State")) @@ -670,7 +667,7 @@ static int connman_fill_connection_data(DBusMessage *reply, struct ipforward_dat /* if in ready state connection might be up anyway */ if(strcmp(string, "ready")) log_debug("Not online. Turning on cellular data connection.\n"); - return(1); + return 1; } } @@ -710,7 +707,7 @@ static int connman_fill_connection_data(DBusMessage *reply, struct ipforward_dat dbus_message_iter_next (&dict_iter); type = dbus_message_iter_get_arg_type(&dict_iter); } - return(0); + return 0; } /** @@ -754,7 +751,7 @@ static int connman_set_cellular_online(DBusConnection *dbus_conn_connman, const /* we don't care for the reply, which is empty anyway if all goes well */ ret = !dbus_connection_send(dbus_conn_connman, msg, NULL); /* sleep for the connection to come up */ - usbmoded_sleep(5); + common_sleep(5); /* make sure the message is sent before cleaning up and closing the connection */ dbus_connection_flush(dbus_conn_connman); dbus_message_unref(msg); @@ -763,7 +760,7 @@ static int connman_set_cellular_online(DBusConnection *dbus_conn_connman, const if(wifi) free(wifi); - return(ret); + return ret; } /* @@ -825,15 +822,15 @@ static int connman_wifi_power_control(DBusConnection *dbus_conn_connman, int on) /* /net/connman/technology/wifi net.connman.Technology.SetProperty string:Powered variant:boolean:false */ if(wifistatus && !on) - usbmoded_system("/bin/dbus-send --print-reply --type=method_call --system --dest=net.connman /net/connman/technology/wifi net.connman.Technology.SetProperty string:Powered variant:boolean:false"); + common_system("/bin/dbus-send --print-reply --type=method_call --system --dest=net.connman /net/connman/technology/wifi net.connman.Technology.SetProperty string:Powered variant:boolean:false"); if(wifistatus && on) /* turn on wifi after tethering is over and wifi was on before */ - usbmoded_system("/bin/dbus-send --print-reply --type=method_call --system --dest=net.connman /net/connman/technology/wifi net.connman.Technology.SetProperty string:Powered variant:boolean:true"); + common_system("/bin/dbus-send --print-reply --type=method_call --system --dest=net.connman /net/connman/technology/wifi net.connman.Technology.SetProperty string:Powered variant:boolean:true"); - return(0); + return 0; } -static int connman_get_connection_data(struct ipforward_data *ipforward) +static int connman_get_connection_data(ipforward_data_t *ipforward) { DBusConnection *dbus_conn_connman = NULL; DBusMessage *msg = NULL, *reply = NULL; @@ -891,7 +888,7 @@ static int connman_get_connection_data(struct ipforward_data *ipforward) dbus_connection_unref(dbus_conn_connman); dbus_error_free(&error); free(service); - return(ret); + return ret; } static int connman_reset_state(void) @@ -912,16 +909,16 @@ static int connman_reset_state(void) dbus_connection_unref(dbus_conn_connman); dbus_error_free(&error); - return(0); + return 0; } #endif /* CONNMAN */ /** * Write out /etc/udhcpd.conf conf so the config is available when it gets started */ -int network_set_up_dhcpd(struct mode_list_elem *data) +int network_set_up_dhcpd(mode_list_elem_t *data) { - struct ipforward_data *ipforward = NULL; + ipforward_data_t *ipforward = NULL; int ret = 1; /* Set up nat info only if it is required */ @@ -936,8 +933,7 @@ int network_set_up_dhcpd(struct mode_list_elem *data) goto end; } #endif /* OFONO */ - ipforward = malloc(sizeof(struct ipforward_data)); - memset(ipforward, 0, sizeof(struct ipforward_data)); + ipforward = calloc(1, sizeof *ipforward); #ifdef CONNMAN if(connman_get_connection_data(ipforward)) { @@ -959,7 +955,7 @@ int network_set_up_dhcpd(struct mode_list_elem *data) end: /* the function checks if ipforward is NULL or not */ network_free_ipforward_data(ipforward); - return(ret); + return ret; } #if CONNMAN_WORKS_BETTER @@ -1000,7 +996,7 @@ static int append_variant(DBusMessageIter *iter, const char *property, * Activate the network interface * */ -int network_up(struct mode_list_elem *data) +int network_up(mode_list_elem_t *data) { char *ip = NULL, *gateway = NULL; int ret = -1; @@ -1015,11 +1011,11 @@ int network_up(struct mode_list_elem *data) const char *service = NULL; /* make sure connman will recognize the gadget interface NEEDED? */ - //usbmoded_system("/bin/dbus-send --print-reply --type=method_call --system --dest=net.connman /net/connman/technology/gadget net.connman.Technology.SetProperty string:Powered variant:boolean:true"); - //usbmoded_system("/sbin/ifconfig rndis0 up"); + //common_system("/bin/dbus-send --print-reply --type=method_call --system --dest=net.connman /net/connman/technology/gadget net.connman.Technology.SetProperty string:Powered variant:boolean:true"); + //common_system("/sbin/ifconfig rndis0 up"); log_debug("waiting for connman to pick up interface\n"); - usbmoded_sleep(1); + common_sleep(1); dbus_error_init(&error); if( (dbus_conn_connman = dbus_bus_get(DBUS_BUS_SYSTEM, &error)) == 0 ) @@ -1039,7 +1035,7 @@ int network_up(struct mode_list_elem *data) } if(service == NULL) - return(1); + return 1; log_debug("gadget = %s\n", service); /* now we need to configure the connection */ @@ -1112,7 +1108,7 @@ int network_up(struct mode_list_elem *data) free(ip); if(gateway) free(gateway); - return(ret); + return ret; #else char command[128]; @@ -1122,7 +1118,7 @@ int network_up(struct mode_list_elem *data) interface = network_get_interface(data); if(interface == NULL) - return(1); + return 1; /* interface found, so we can get all the rest */ ip = config_get_network_setting(NETWORK_IP_KEY); @@ -1132,25 +1128,25 @@ int network_up(struct mode_list_elem *data) if(!strcmp(ip, "dhcp")) { sprintf(command, "dhclient -d %s\n", interface); - ret = usbmoded_system(command); + ret = common_system(command); if(ret != 0) { sprintf(command, "udhcpc -i %s\n", interface); - usbmoded_system(command); + common_system(command); } } else { sprintf(command, "ifconfig %s %s %s\n", interface, ip, netmask); - usbmoded_system(command); + common_system(command); } /* TODO: Check first if there is a gateway set */ if(gateway) { sprintf(command, "route add default gw %s\n", gateway); - usbmoded_system(command); + common_system(command); } free(interface); @@ -1158,7 +1154,7 @@ int network_up(struct mode_list_elem *data) free(ip); free(netmask); - return(0); + return 0; #endif /* CONNMAN */ } @@ -1166,7 +1162,7 @@ int network_up(struct mode_list_elem *data) * Deactivate the network interface * */ -int network_down(struct mode_list_elem *data) +int network_down(mode_list_elem_t *data) { #if CONNMAN_WORKS_BETTER DBusConnection *dbus_conn_connman = NULL; @@ -1194,7 +1190,7 @@ int network_down(struct mode_list_elem *data) } if(service == NULL) - return(1); + return 1; /* Finally we can shut it down */ if ((msg = dbus_message_new_method_call("net.connman", service, "net.connman.Service", "Disconnect")) != NULL) @@ -1212,17 +1208,17 @@ int network_down(struct mode_list_elem *data) network_clean_usb_ip_forward(); dbus_error_free(&error); - return(ret); + return ret; #else char *interface; char command[128]; interface = network_get_interface(data); if(interface == NULL) - return(0); + return 0; sprintf(command, "ifconfig %s down\n", interface); - usbmoded_system(command); + common_system(command); /* dhcp client shutdown happens on disconnect automatically */ if(data->nat) @@ -1230,7 +1226,7 @@ int network_down(struct mode_list_elem *data) free(interface); - return(0); + return 0; #endif /* CONNMAN_IS_EVER_FIXED_FOR_USB */ } @@ -1240,8 +1236,8 @@ int network_down(struct mode_list_elem *data) */ int network_update(void) { - if( usbmoded_get_cable_state() == CABLE_STATE_PC_CONNECTED ) { - struct mode_list_elem *data = usbmoded_get_usb_mode_data(); + if( control_get_cable_state() == CABLE_STATE_PC_CONNECTED ) { + mode_list_elem_t *data = worker_get_usb_mode_data(); if( data && data->network ) { network_down(data); network_up(data); diff --git a/src/usb_moded-network.h b/src/usb_moded-network.h index efe3b42..10166ce 100644 --- a/src/usb_moded-network.h +++ b/src/usb_moded-network.h @@ -41,9 +41,9 @@ gboolean connman_set_tethering(const char *path, gboolean on); /* -- network -- */ -int network_set_up_dhcpd(struct mode_list_elem *data); -int network_up (struct mode_list_elem *data); -int network_down (struct mode_list_elem *data); +int network_set_up_dhcpd(mode_list_elem_t *data); +int network_up (mode_list_elem_t *data); +int network_down (mode_list_elem_t *data); int network_update (void); #endif /* USB_MODED_NETWORK_H_ */ diff --git a/src/usb_moded-sigpipe.c b/src/usb_moded-sigpipe.c new file mode 100644 index 0000000..45c5e0c --- /dev/null +++ b/src/usb_moded-sigpipe.c @@ -0,0 +1,207 @@ +/** + * @file usb_moded-sigpipe.c + * + * Copyright (C) 2010 Nokia Corporation. All rights reserved. + * Copyright (C) 2012-2018 Jolla. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Lesser GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program 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 + * General Public License for more details. + * + * You should have received a copy of the Lesser GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include "usb_moded-sigpipe.h" + +#include "usb_moded.h" +#include "usb_moded-log.h" + +#include +#include +#include +#include + +/* ========================================================================= * + * Prototypes + * ========================================================================= */ + +/* -- sigpipe -- */ + +static gboolean sigpipe_read_signal_cb(GIOChannel *channel, GIOCondition condition, gpointer data); +static void sigpipe_trap_signal_cb(int sig); +static bool sigpipe_crate_pipe (void); +static void sigpipe_trap_signals (void); +bool sigpipe_init (void); + +/* ========================================================================= * + * Data + * ========================================================================= */ + +/** Pipe fd for transferring signals to mainloop context */ +static int sigpipe_fd = -1; + +/** Glib io watch callback for reading signals from signal pipe + * + * @param channel glib io channel + * @param condition wakeup reason + * @param data user data (unused) + * + * @return TRUE to keep the iowatch, or FALSE to disable it + */ +static gboolean +sigpipe_read_signal_cb(GIOChannel *channel, + GIOCondition condition, + gpointer data) +{ + gboolean keep_watch = FALSE; + + int fd, rc, sig; + + (void)data; + + /* Should never happen, but we must disable the io watch + * if the pipe fd still goes into unexpected state ... */ + if( condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL) ) + goto EXIT; + + if( (fd = g_io_channel_unix_get_fd(channel)) == -1 ) + goto EXIT; + + /* If the actual read fails, terminate with core dump */ + rc = TEMP_FAILURE_RETRY(read(fd, &sig, sizeof sig)); + if( rc != (int)sizeof sig ) + abort(); + + /* handle the signal */ + usbmoded_handle_signal(sig); + + keep_watch = TRUE; + +EXIT: + if( !keep_watch ) + log_crit("disabled signal handler io watch\n"); + + return keep_watch; +} + +/** Async signal handler for writing signals to signal pipe + * + * @param sig the signal number to pass to mainloop via pipe + */ +static void +sigpipe_trap_signal_cb(int sig) +{ + /* NOTE: This function *MUST* be kept async-signal-safe! */ + + static volatile int exit_tries = 0; + + int rc; + + /* Restore signal handler */ + signal(sig, sigpipe_trap_signal_cb); + + switch( sig ) + { + case SIGINT: + case SIGQUIT: + case SIGTERM: + /* If we receive multiple signals that should have + * caused the process to exit, assume that mainloop + * is stuck and terminate with core dump. */ + if( ++exit_tries >= 2 ) + abort(); + break; + + default: + break; + } + + /* Transfer the signal to mainloop via pipe ... */ + rc = TEMP_FAILURE_RETRY(write(sigpipe_fd, &sig, sizeof sig)); + + /* ... or terminate with core dump in case of failures */ + if( rc != (int)sizeof sig ) + abort(); +} + +/** Create a pipe and io watch for handling signal from glib mainloop + * + * @return true on success, or false in case of errors + */ +static bool +sigpipe_crate_pipe(void) +{ + bool res = false; + GIOChannel *chn = 0; + int pfd[2] = { -1, -1 }; + + if( pipe2(pfd, O_CLOEXEC) == -1 ) + goto EXIT; + + if( (chn = g_io_channel_unix_new(pfd[0])) == 0 ) + goto EXIT; + + if( !g_io_add_watch(chn, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, + sigpipe_read_signal_cb, 0) ) + goto EXIT; + + g_io_channel_set_close_on_unref(chn, true), pfd[0] = -1; + sigpipe_fd = pfd[1], pfd[1] = -1; + + res = true; + +EXIT: + if( chn ) g_io_channel_unref(chn); + if( pfd[0] != -1 ) close(pfd[0]); + if( pfd[1] != -1 ) close(pfd[1]); + + return res; +} + +/** Install async signal handlers + */ +static void +sigpipe_trap_signals(void) +{ + static const int sig[] = + { + SIGINT, + SIGQUIT, + SIGTERM, + SIGHUP, + -1 + }; + + for( size_t i = 0; sig[i] != -1; ++i ) + { + signal(sig[i], sigpipe_trap_signal_cb); + } +} + +/** Initialize signal trapping + * + * @return true on success, or false in case of errors + */ +bool +sigpipe_init(void) +{ + bool success = false; + + if( !sigpipe_crate_pipe() ) + goto EXIT; + + sigpipe_trap_signals(); + + success = true; + +EXIT: + return success; +} diff --git a/src/usb_moded-sigpipe.h b/src/usb_moded-sigpipe.h new file mode 100644 index 0000000..e16488b --- /dev/null +++ b/src/usb_moded-sigpipe.h @@ -0,0 +1,31 @@ +/** + * @file usb_moded-sigpipe.c + * + * Copyright (C) 2010 Nokia Corporation. All rights reserved. + * Copyright (C) 2012-2018 Jolla. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Lesser GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program 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 + * General Public License for more details. + * + * You should have received a copy of the Lesser GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef USB_MODED_SIGPIPE_H_ +# define USB_MODED_SIGPIPE_H_ + +#include + +/* -- sigpipe -- */ + +bool sigpipe_init(void); + +#endif /* USB_MODED_SIGPIPE_H_ */ diff --git a/src/usb_moded-ssu.c b/src/usb_moded-ssu.c index 7f62b2a..e46c147 100644 --- a/src/usb_moded-ssu.c +++ b/src/usb_moded-ssu.c @@ -20,11 +20,15 @@ * 02110-1301 USA */ -#include -#include #include "usb_moded-ssu.h" + #include "usb_moded-log.h" +#include +#include + +#include + /* ========================================================================= * * Prototypes * ========================================================================= */ diff --git a/src/usb_moded-ssu.h b/src/usb_moded-ssu.h index 77080e8..81ab749 100644 --- a/src/usb_moded-ssu.h +++ b/src/usb_moded-ssu.h @@ -23,6 +23,8 @@ #ifndef USB_MODED_SSU_H_ # define USB_MODED_SSU_H_ +# include + /* ========================================================================= * * Prototypes * ========================================================================= */ diff --git a/src/usb_moded-systemd.c b/src/usb_moded-systemd.c index 026fe44..e09980f 100644 --- a/src/usb_moded-systemd.c +++ b/src/usb_moded-systemd.c @@ -22,17 +22,10 @@ * 02110-1301 USA */ -#include -#include - -#include -#include -#include +#include "usb_moded-systemd.h" #include "usb_moded-dbus-private.h" -#include "usb_moded.h" #include "usb_moded-log.h" -#include "usb_moded-systemd.h" /* ========================================================================= * * Constants diff --git a/src/usb_moded-systemd.h b/src/usb_moded-systemd.h index a69f441..d8c2a7e 100644 --- a/src/usb_moded-systemd.h +++ b/src/usb_moded-systemd.h @@ -22,6 +22,8 @@ #ifndef USB_MODED_SYSTEMD_H_ # define USB_MODED_SYSTEMD_H_ +# include + /* ========================================================================= * * Constants * ========================================================================= */ diff --git a/src/usb_moded-trigger.c b/src/usb_moded-trigger.c index 830b590..9a25760 100644 --- a/src/usb_moded-trigger.c +++ b/src/usb_moded-trigger.c @@ -25,26 +25,16 @@ * 02110-1301 USA */ -#include -#include -#include -#include - -#include +#include "usb_moded-trigger.h" -#include +#include "usb_moded-config-private.h" +#include "usb_moded-control.h" +#include "usb_moded-log.h" -#include +#include +#include -#include "usb_moded.h" -#include "usb_moded-log.h" -#include "usb_moded-config-private.h" -#include "usb_moded-udev.h" -#include "usb_moded-modesetting.h" -#include "usb_moded-trigger.h" -#if defined MEEGOLOCK -# include "usb_moded-devicelock.h" -#endif /* MEEGOLOCK */ +#include /* ========================================================================= * * Prototypes @@ -257,7 +247,7 @@ static void trigger_parse_udev_properties(struct udev_device *dev) goto EXIT; } - usbmoded_set_usb_mode(trigger_mode); + control_set_usb_mode(trigger_mode); EXIT: free(trigger_value); diff --git a/src/usb_moded-trigger.h b/src/usb_moded-trigger.h index 30603f9..6a15980 100644 --- a/src/usb_moded-trigger.h +++ b/src/usb_moded-trigger.h @@ -25,6 +25,8 @@ #ifndef USB_MODED_TRIGGER_H_ # define USB_MODED_TRIGGER_H_ +# include + /* ========================================================================= * * Prototypes * ========================================================================= */ diff --git a/src/usb_moded-udev.c b/src/usb_moded-udev.c index dbe8f39..5142d85 100644 --- a/src/usb_moded-udev.c +++ b/src/usb_moded-udev.c @@ -27,24 +27,16 @@ * 02110-1301 USA */ -#include -#include -#include -#include -#include - -#include - -#include - -#include +#include "usb_moded-udev.h" -#include "usb_moded-log.h" #include "usb_moded-config-private.h" -#include "usb_moded-udev.h" -#include "usb_moded.h" -#include "usb_moded-modes.h" +#include "usb_moded-control.h" #include "usb_moded-dbus-private.h" +#include "usb_moded-log.h" + +#include + +#include /* ========================================================================= * * Prototypes @@ -215,7 +207,7 @@ static void umudev_cable_state_changed(void) } /* Then act on usb mode */ - usbmoded_set_cable_state(umudev_cable_state_active); + control_set_cable_state(umudev_cable_state_active); } static void umudev_cable_state_from_udev(cable_state_t curr) @@ -251,8 +243,8 @@ static void umudev_cable_state_from_udev(cable_state_t curr) gint delay = 100; if( curr == CABLE_STATE_PC_CONNECTED && prev != CABLE_STATE_UNKNOWN ) { - if( delay < usbmoded_cable_connection_delay ) - delay = usbmoded_cable_connection_delay; + if( delay < usbmoded_get_cable_connection_delay() ) + delay = usbmoded_get_cable_connection_delay(); } umudev_cable_state_start_timer(delay); @@ -286,8 +278,8 @@ static gboolean umudev_io_input_cb(GIOChannel *iochannel, GIOCondition cond, gpo gboolean continue_watching = TRUE; - /* No code paths are allowed to bypass the usbmoded_release_wakelock() call below */ - usbmoded_acquire_wakelock(USB_MODED_WAKELOCK_PROCESS_INPUT); + /* No code paths are allowed to bypass the common_release_wakelock() call below */ + common_acquire_wakelock(USB_MODED_WAKELOCK_PROCESS_INPUT); if( cond & G_IO_IN ) { @@ -325,7 +317,7 @@ static gboolean umudev_io_input_cb(GIOChannel *iochannel, GIOCondition cond, gpo log_crit("udev io watch disabled"); } - usbmoded_release_wakelock(USB_MODED_WAKELOCK_PROCESS_INPUT); + common_release_wakelock(USB_MODED_WAKELOCK_PROCESS_INPUT); return continue_watching; } @@ -365,7 +357,7 @@ static void umudev_parse_properties(struct udev_device *dev, bool initial) /* Transition period = Connection status derived from udev * events disagrees with usb-moded side bookkeeping. */ - if( connected != usbmoded_get_connection_state() ) { + if( connected != control_get_connection_state() ) { /* Enable udev property diagnostic logging */ warnings = true; /* Block suspend briefly */ @@ -491,7 +483,7 @@ gboolean umudev_init(void) char *configured_device = NULL; char *configured_subsystem = NULL; struct udev_device *dev = 0; - static GIOChannel *iochannel = 0; + GIOChannel *iochannel = 0; int ret = 0; diff --git a/src/usb_moded-util.c b/src/usb_moded-util.c index 6c7c047..2e74838 100644 --- a/src/usb_moded-util.c +++ b/src/usb_moded-util.c @@ -23,14 +23,12 @@ * 02110-1301 USA */ +#include "usb_moded-dbus-private.h" + #include #include #include -#include #include -#include - -#include "usb_moded-dbus-private.h" /* ========================================================================= * * Prototypes diff --git a/src/usb_moded-worker.c b/src/usb_moded-worker.c new file mode 100644 index 0000000..baa8b98 --- /dev/null +++ b/src/usb_moded-worker.c @@ -0,0 +1,883 @@ +/** + * @file usb_moded-worker.c + * + * Copyright (C) 2013-2018 Jolla. All rights reserved. + * + * @author: Philippe De Swert + * @author: Simo Piiroinen + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Lesser GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program 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 + * General Public License for more details. + * + * You should have received a copy of the Lesser GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include "usb_moded-worker.h" + +#include "usb_moded-android.h" +#include "usb_moded-configfs.h" +#include "usb_moded-control.h" +#include "usb_moded-dyn-config.h" +#include "usb_moded-log.h" +#include "usb_moded-modes.h" +#include "usb_moded-modesetting.h" +#include "usb_moded-modules.h" + +#include + +#include // NOTRIM +#include +#include +#include +#include + +/* ========================================================================= * + * Prototypes + * ========================================================================= */ + +/* -- worker -- */ + +static bool worker_thread_p (void); +bool worker_bailing_out (void); +static bool worker_mode_is_mtp_mode (const char *mode); +static bool worker_is_mtpd_running (void); +static bool worker_stop_mtpd (void); +static bool worker_start_mtpd (void); +static bool worker_switch_to_charging (void); +const char *worker_get_kernel_module (void); +bool worker_set_kernel_module (const char *module); +void worker_clear_kernel_module (void); +mode_list_elem_t *worker_get_usb_mode_data (void); +void worker_set_usb_mode_data (mode_list_elem_t *data); +static const char *worker_get_activated_mode_locked(void); +static bool worker_set_activated_mode_locked(const char *mode); +static const char *worker_get_requested_mode_locked(void); +static bool worker_set_requested_mode_locked(const char *mode); +void worker_request_hardware_mode (const char *mode); +void worker_clear_hardware_mode (void); +static void worker_execute (void); +void worker_switch_to_mode (const char *mode); +static guint worker_add_iowatch (int fd, bool close_on_unref, GIOCondition cnd, GIOFunc io_cb, gpointer aptr); +static void *worker_thread_cb (void *aptr); +static gboolean worker_notify_cb (GIOChannel *chn, GIOCondition cnd, gpointer data); +static bool worker_start_thread (void); +static void worker_stop_thread (void); +static void worker_delete_eventfd (void); +static bool worker_create_eventfd (void); +bool worker_init (void); +void worker_quit (void); +void worker_wakeup (void); +static void worker_notify (void); + +/* ========================================================================= * + * Data + * ========================================================================= */ + +static pthread_t worker_thread_id = 0; + +static pthread_mutex_t worker_mutex = PTHREAD_MUTEX_INITIALIZER; + +/** Flag for: Main thread has changed target mode worker should apply + * + * Worker should bailout from synchronous activities related to + * ongoing activation of a usb mode. + */ +static volatile bool worker_bailout_requested = false; + +/** Flag for: Worker thread is cleaning up after abandoning mode switch + * + * Asynchronous activities on mode cleanup should be executed without + * bailing out. + */ +static volatile bool worker_bailout_handled = false; + +#define WORKER_LOCKED_ENTER do {\ + if( pthread_mutex_lock(&worker_mutex) != 0 ) { \ + log_crit("WORKER LOCK FAILED");\ + _exit(EXIT_FAILURE);\ + }\ +}while(0) + +#define WORKER_LOCKED_LEAVE do {\ + if( pthread_mutex_unlock(&worker_mutex) != 0 ) { \ + log_crit("WORKER UNLOCK FAILED");\ + _exit(EXIT_FAILURE);\ + }\ +}while(0) + +/* ========================================================================= * + * Functions + * ========================================================================= */ + +static bool +worker_thread_p(void) +{ + return worker_thread_id && worker_thread_id == pthread_self(); +} + +bool +worker_bailing_out(void) +{ + // ref: see common_msleep_() + return (worker_thread_p() && + worker_bailout_requested && + !worker_bailout_handled); +} + +/* ------------------------------------------------------------------------- * + * MTP_DAEMON + * ------------------------------------------------------------------------- */ + +/** Maximum time to wait for mtpd to start [ms] + * + * This needs to include time to start systemd unit + * plus however long it might take for mtpd to scan + * all files exposed over mtp. On a slow device with + * lots of files it can easily take over 30 seconds, + * especially during the 1st mtp connect after reboot. + * + * Use two minutes as some kind of worst case estimate. + */ +static unsigned worker_mtp_start_delay = 120 * 1000; + +/** Maximum time to wait for mtpd to stop [ms] + * + * This is just regular service stop. Expected to + * take max couple of seconds, but use someting + * in the ballbark of systemd default i.e. 15 seconds + */ +static unsigned worker_mtp_stop_delay = 15 * 1000; + +static bool worker_mode_is_mtp_mode(const char *mode) +{ + return mode && !strcmp(mode, "mtp_mode"); +} + +static bool worker_is_mtpd_running(void) +{ + /* ep0 becomes available when /dev/mtp is mounted. + * + * ep1, ep2, ep3 exist while mtp daemon is running, + * has ep0 opened and has written config data to it. + */ + static const char * const lut[] = { + "/dev/mtp/ep0", + "/dev/mtp/ep1", + "/dev/mtp/ep2", + "/dev/mtp/ep3", + 0 + }; + + bool ack = true; + + for( size_t i = 0; lut[i]; ++i ) { + if( access(lut[i], F_OK) == -1 ) { + ack = false; + break; + } + } + + return ack; +} + +static bool +worker_mtpd_running_p(void *aptr) +{ + (void)aptr; + return worker_is_mtpd_running(); +} + +static bool +worker_mtpd_stopped_p(void *aptr) +{ + (void)aptr; + return !worker_is_mtpd_running(); +} + +static bool +worker_stop_mtpd(void) +{ + bool ack = false; + + if( worker_mtpd_stopped_p(0) ) { + log_debug("mtp daemon is not running"); + goto SUCCESS; + } + + int rc = common_system("systemctl-user stop buteo-mtp.service"); + if( rc != 0 ) { + log_warning("failed to stop mtp daemon; exit code = %d", rc); + goto FAILURE; + } + + if( common_wait(worker_mtp_stop_delay, worker_mtpd_stopped_p, 0) != WAIT_READY ) { + log_warning("failed to stop mtp daemon; giving up"); + goto FAILURE; + } + + log_debug("mtp daemon has stopped"); + +SUCCESS: + ack = true; + +FAILURE: + return ack; +} + +static bool +worker_start_mtpd(void) +{ + bool ack = false; + + if( worker_mtpd_running_p(0) ) { + log_debug("mtp daemon is running"); + goto SUCCESS; + } + + int rc = common_system("systemctl-user start buteo-mtp.service"); + if( rc != 0 ) { + log_warning("failed to start mtp daemon; exit code = %d", rc); + goto FAILURE; + } + + if( common_wait(worker_mtp_start_delay, worker_mtpd_running_p, 0) != WAIT_READY ) { + log_warning("failed to start mtp daemon; giving up"); + goto FAILURE; + } + + log_debug("mtp daemon has started"); + +SUCCESS: + ack = true; + +FAILURE: + return ack; +} + +static bool worker_switch_to_charging(void) +{ + bool ack = true; + + if( android_set_charging_mode() ) + goto SUCCESS; + + if( configfs_set_charging_mode() ) + goto SUCCESS; + + if( modules_in_use() ) { + if( worker_set_kernel_module(MODULE_MASS_STORAGE) ) + goto SUCCESS; + worker_set_kernel_module(MODULE_NONE); + } + + log_err("switch to charging mode failed"); + + ack = false; +SUCCESS: + return ack; +} + +/* ------------------------------------------------------------------------- * + * KERNEL_MODULE + * ------------------------------------------------------------------------- */ + +/** The module name for the specific mode */ +static char *worker_kernel_module = NULL; + +/** get the supposedly loaded module + * + * @return The name of the loaded module + * + */ +const char * worker_get_kernel_module(void) +{ + return worker_kernel_module ?: MODULE_NONE; +} + +/** set the loaded module + * + * @param module The module name for the requested mode + * + */ +bool worker_set_kernel_module(const char *module) +{ + bool ack = false; + + if( !module ) + module = MODULE_NONE; + + const char *current = worker_get_kernel_module(); + + log_debug("current module: %s -> %s", current, module); + + if( !g_strcmp0(current, module) ) + goto SUCCESS; + + if( modules_unload_module(current) != 0 ) + goto EXIT; + + free(worker_kernel_module), worker_kernel_module = 0; + + if( modules_load_module(module) != 0 ) + goto EXIT; + + if( g_strcmp0(module, MODULE_NONE) ) + worker_kernel_module = strdup(module); + +SUCCESS: + ack = true; +EXIT: + return ack; +} + +void worker_clear_kernel_module(void) +{ + free(worker_kernel_module), worker_kernel_module = 0; +} + +/* ------------------------------------------------------------------------- * + * MODE_DATA + * ------------------------------------------------------------------------- */ + +/** Contains the mode data */ +static mode_list_elem_t *worker_mode_data = NULL; + +/** get the usb mode data + * + * @return a pointer to the usb mode data + * + */ +mode_list_elem_t *worker_get_usb_mode_data(void) +{ + return worker_mode_data; +} + +/** set the mode_list_elem_t data + * + * @param data mode_list_element pointer + * + */ +void worker_set_usb_mode_data(mode_list_elem_t *data) +{ + worker_mode_data = data; +} + +/* ------------------------------------------------------------------------- * + * HARDWARE_MODE + * ------------------------------------------------------------------------- */ + +/* The hardware mode name + * + * How the usb hardware has been configured. + * + * For example internal_mode=MODE_ASK gets + * mapped to hardware_mode=MODE_CHARGING */ +static gchar *worker_requested_mode = NULL; + +static gchar *worker_activated_mode = NULL; + +static const char * +worker_get_activated_mode_locked(void) +{ + return worker_activated_mode ?: MODE_UNDEFINED; +} + +static bool +worker_set_activated_mode_locked(const char *mode) +{ + bool changed = false; + const char *prev = worker_get_activated_mode_locked(); + + if( !g_strcmp0(prev, mode) ) + goto EXIT; + + log_debug("activated_mode: %s -> %s", prev, mode); + g_free(worker_activated_mode), + worker_activated_mode = g_strdup(mode); + changed = true; + +EXIT: + return changed; +} + +static const char * +worker_get_requested_mode_locked(void) +{ + return worker_requested_mode ?: MODE_UNDEFINED; +} + +static bool +worker_set_requested_mode_locked(const char *mode) +{ + bool changed = false; + const char *prev = worker_get_requested_mode_locked(); + + if( !g_strcmp0(prev, mode) ) + goto EXIT; + + log_debug("requested_mode: %s -> %s", prev, mode); + g_free(worker_requested_mode), + worker_requested_mode = g_strdup(mode); + changed = true; + +EXIT: + return changed; +} + +void worker_request_hardware_mode(const char *mode) +{ + WORKER_LOCKED_ENTER; + + if( !worker_set_requested_mode_locked(mode) ) + goto EXIT; + + worker_wakeup(); + +EXIT: + WORKER_LOCKED_LEAVE; + return; +} + +void worker_clear_hardware_mode(void) +{ + WORKER_LOCKED_ENTER; + g_free(worker_requested_mode), worker_requested_mode = 0; + WORKER_LOCKED_LEAVE; +} + +static void +worker_execute(void) +{ + WORKER_LOCKED_ENTER; + + const char *activated = worker_get_activated_mode_locked(); + const char *requested = worker_get_requested_mode_locked(); + const char *activate = common_map_mode_to_hardware(requested); + + log_debug("activated = %s", activated); + log_debug("requested = %s", requested); + log_debug("activate = %s", activate); + + bool changed = g_strcmp0(activated, activate) != 0; + + WORKER_LOCKED_LEAVE; + + if( changed ) + worker_switch_to_mode(activate); + else + worker_notify(); + + return; +} + +/* ------------------------------------------------------------------------- * + * MODE_SWITCH + * ------------------------------------------------------------------------- */ + +void +worker_switch_to_mode(const char *mode) +{ + const char *override = 0; + + /* set return to 1 to be sure to error out if no matching mode is found either */ + + log_debug("Cleaning up previous mode"); + + if( !worker_mode_is_mtp_mode(mode) ) + worker_stop_mtpd(); + + if( worker_get_usb_mode_data() ) { + modesetting_leave_dynamic_mode(); + worker_set_usb_mode_data(NULL); + } + + log_debug("Setting %s\n", mode); + + /* Mode mapping should mean we only see MODE_CHARGING here, but just + * in case redirect fixed charging related things to charging ... */ + + if( !strcmp(mode, MODE_CHARGING) || + !strcmp(mode, MODE_CHARGING_FALLBACK) || + !strcmp(mode, MODE_CHARGER) || + !strcmp(mode, MODE_UNDEFINED) || + !strcmp(mode, MODE_ASK)) { + goto CHARGE; + } + + if( !usbmoded_can_export() ) { + log_warning("Policy does not allow mode: %s", mode); + goto FAILED; + } + + /* go through all the dynamic modes if the modelist exists*/ + for( GList *iter = usbmoded_get_modelist(); iter; iter = g_list_next(iter) ) + { + mode_list_elem_t *data = iter->data; + if( strcmp(mode, data->mode_name) ) + continue; + + log_debug("Matching mode %s found.\n", mode); + + /* set data before calling any of the dynamic mode functions + * as they will use the worker_get_usb_mode_data function */ + worker_set_usb_mode_data(data); + + if( worker_mode_is_mtp_mode(mode) ) { + if( !worker_start_mtpd() ) + goto FAILED; + } + + if( !worker_set_kernel_module(data->mode_module) ) + goto FAILED; + + if( !modesetting_enter_dynamic_mode() ) + goto FAILED; + + goto SUCCESS; + } + + log_warning("Matching mode %s was not found.", mode); + +FAILED: + worker_bailout_handled = true; + + /* Undo any changes we might have might have already done */ + if( worker_get_usb_mode_data() ) { + log_debug("Cleaning up failed mode switch"); + + if( worker_mode_is_mtp_mode(mode) ) + worker_stop_mtpd(); + + modesetting_leave_dynamic_mode(); + worker_set_usb_mode_data(NULL); + } + + override = MODE_CHARGING; + log_warning("mode setting failed, try %s", override); + +CHARGE: + if( worker_switch_to_charging() ) + goto SUCCESS; + + log_crit("failed to activate charging, all bets are off"); + + /* FIXME: double check this error path */ + + /* If we get here then usb_module loading failed, + * no mode matched, and charging setup failed too. + */ + + override = MODE_UNDEFINED; + log_warning("mode setting failed, fallback to %s", override); + worker_set_kernel_module(MODULE_NONE); + +SUCCESS: + + WORKER_LOCKED_ENTER; + if( override ) { + worker_set_activated_mode_locked(override); + worker_set_requested_mode_locked(override); + } + else { + worker_set_activated_mode_locked(mode); + } + WORKER_LOCKED_LEAVE; + + worker_notify(); + + return; +} + +/* ------------------------------------------------------------------------- * + * WORKER_THREAD + * ------------------------------------------------------------------------- */ + +/** eventfd descriptor for waking up worker thread after adding new jobs */ +static int worker_req_evfd = -1; + +/** eventfd descriptor for waking up main thread after executing jobs */ +static int worker_rsp_evfd = -1; + +/** I/O watch identifier for worker_rsp_evfd */ +static guint worker_rsp_wid = 0; + +static guint +worker_add_iowatch(int fd, bool close_on_unref, + GIOCondition cnd, GIOFunc io_cb, gpointer aptr) +{ + guint wid = 0; + GIOChannel *chn = 0; + + if( !(chn = g_io_channel_unix_new(fd)) ) + goto cleanup; + + g_io_channel_set_close_on_unref(chn, close_on_unref); + + cnd |= G_IO_ERR | G_IO_HUP | G_IO_NVAL; + + if( !(wid = g_io_add_watch(chn, cnd, io_cb, aptr)) ) + goto cleanup; + +cleanup: + if( chn != 0 ) g_io_channel_unref(chn); + + return wid; + +} + +static void *worker_thread_cb(void *aptr) +{ + (void)aptr; + + /* Async cancellation, but disabled */ + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0); + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0); + + /* Leave INT/TERM signal processing up to the main thread */ + sigset_t ss; + sigemptyset(&ss); + sigaddset(&ss, SIGINT); + sigaddset(&ss, SIGTERM); + pthread_sigmask(SIG_BLOCK, &ss, 0); + + /* Loop until explicitly canceled */ + for( ;; ) { + /* Async cancellation point at wait() */ + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0); + uint64_t cnt = 0; + int rc = read(worker_req_evfd, &cnt, sizeof cnt); + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0); + + if( rc == -1 ) { + if( errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK ) + continue; + log_err("read: %m"); + goto EXIT; + } + + if( rc != sizeof cnt ) + continue; + + if( cnt > 0 ) { + worker_bailout_requested = false; + worker_bailout_handled = false; + worker_execute(); + } + + } +EXIT: + return 0; +} + +static gboolean +worker_notify_cb(GIOChannel *chn, GIOCondition cnd, gpointer data) +{ + (void)data; + + gboolean keep_going = FALSE; + + if( !worker_rsp_wid ) + goto cleanup_nak; + + int fd = g_io_channel_unix_get_fd(chn); + + if( fd < 0 ) + goto cleanup_nak; + + if( cnd & ~G_IO_IN ) + goto cleanup_nak; + + if( !(cnd & G_IO_IN) ) + goto cleanup_ack; + + uint64_t cnt = 0; + + int rc = read(fd, &cnt, sizeof cnt); + + if( rc == 0 ) { + log_err("unexpected eof"); + goto cleanup_nak; + } + + if( rc == -1 ) { + if( errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK ) + goto cleanup_ack; + + log_err("read error: %m"); + goto cleanup_nak; + } + + if( rc != sizeof cnt ) + goto cleanup_nak; + + { + WORKER_LOCKED_ENTER; + const char *mode = worker_get_requested_mode_locked(); + gchar *work = g_strdup(mode); + WORKER_LOCKED_LEAVE; + + control_mode_switched(work); + g_free(work); + } + +cleanup_ack: + keep_going = TRUE; + +cleanup_nak: + + if( !keep_going ) { + worker_rsp_wid = 0; + log_crit("worker notifications disabled"); + } + + return keep_going; +} + +static bool +worker_start_thread(void) +{ + bool ack = false; + int err = pthread_create(&worker_thread_id, 0, worker_thread_cb, 0); + if( err ) { + worker_thread_id = 0; + log_err("failed to start worker thread"); + } + else { + ack = true; + log_debug("worker thread started"); + } + + return ack; +} + +static void +worker_stop_thread(void) +{ + if( !worker_thread_id ) + goto EXIT; + + log_debug("stopping worker thread"); + int err = pthread_cancel(worker_thread_id); + if( err ) { + log_err("failed to cancel worker thread"); + } + else { + log_debug("waiting for worker thread to exit ..."); + void *ret = 0; + struct timespec tmo = { 0, 0}; + clock_gettime(CLOCK_REALTIME, &tmo); + tmo.tv_sec += 3; + err = pthread_timedjoin_np(worker_thread_id, &ret, &tmo); + if( err ) { + log_err("worker thread did not exit"); + } + else { + log_debug("worker thread terminated"); + worker_thread_id = 0; + } + } + + if( worker_thread_id ) { + /* Orderly exit is not safe, just die */ + _exit(EXIT_FAILURE); + } + +EXIT: + return; +} + +static void +worker_delete_eventfd(void) +{ + if( worker_req_evfd != -1 ) + close(worker_req_evfd), worker_req_evfd = -1; + + if( worker_rsp_wid ) + g_source_remove(worker_rsp_wid), worker_rsp_wid = 0; + + if( worker_rsp_evfd != -1 ) + close(worker_rsp_evfd), worker_req_evfd = -1; +} + +static bool +worker_create_eventfd(void) +{ + bool ack = false; + + /* Setup notify pipeline */ + + if( (worker_rsp_evfd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)) == -1 ) + goto EXIT; + + worker_rsp_wid = worker_add_iowatch(worker_rsp_evfd, false, G_IO_IN, + worker_notify_cb, 0); + if( !worker_rsp_wid ) + goto EXIT; + + /* Setup request pipeline */ + + if( (worker_req_evfd = eventfd(0, EFD_CLOEXEC)) == -1 ) + goto EXIT; + + ack = true; + +EXIT: + + return ack; +} + +bool +worker_init(void) +{ + bool ack = false; + + if( !worker_create_eventfd() ) + goto EXIT; + + if( !worker_start_thread() ) + goto EXIT; + + ack = true; + +EXIT: + if( !ack ) + worker_quit(); + + return ack; +} + +void +worker_quit(void) +{ + worker_stop_thread(); + worker_delete_eventfd(); +} + +void +worker_wakeup(void) +{ + worker_bailout_requested = true; + + uint64_t cnt = 1; + if( write(worker_req_evfd, &cnt, sizeof cnt) == -1 ) { + log_err("failed to signal requested: %m"); + } +} + +static void +worker_notify(void) +{ + uint64_t cnt = 1; + if( write(worker_rsp_evfd, &cnt, sizeof cnt) == -1 ) { + log_err("failed to signal handled: %m"); + } +} diff --git a/src/usb_moded-worker.h b/src/usb_moded-worker.h new file mode 100644 index 0000000..db958ac --- /dev/null +++ b/src/usb_moded-worker.h @@ -0,0 +1,54 @@ +/** + * @file usb_moded-worker.h + * + * Copyright (C) 2013-2018 Jolla. All rights reserved. + * + * @author: Philippe De Swert + * @author: Simo Piiroinen + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Lesser GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program 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 + * General Public License for more details. + * + * You should have received a copy of the Lesser GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef USB_MODED_WORKER_H_ +# define USB_MODED_WORKER_H_ + +# include + +# include "usb_moded-dyn-config.h" + +/* ========================================================================= * + * Constants + * ========================================================================= */ + +/* ========================================================================= * + * Prototypes + * ========================================================================= */ + +/* -- worker -- */ + +bool worker_bailing_out (void); +const char *worker_get_kernel_module (void); +bool worker_set_kernel_module (const char *module); +void worker_clear_kernel_module (void); +mode_list_elem_t *worker_get_usb_mode_data (void); +void worker_set_usb_mode_data (mode_list_elem_t *data); +void worker_request_hardware_mode(const char *mode); +void worker_clear_hardware_mode (void); +void worker_switch_to_mode (const char *mode); +bool worker_init (void); +void worker_quit (void); +void worker_wakeup (void); + +#endif /* USB_MODED_WORKER_H_ */ diff --git a/src/usb_moded.c b/src/usb_moded.c index 52fdc4e..87c5080 100644 --- a/src/usb_moded.c +++ b/src/usb_moded.c @@ -34,1201 +34,245 @@ * 02110-1301 USA */ -#include -#include - -#include -#include -#include - -#include - -#ifdef SYSTEMD -# include -#endif - -#include "usb_moded.h" -#include "usb_moded-modes.h" -#include "usb_moded-dbus-private.h" -#include "usb_moded-udev.h" -#include "usb_moded-modules.h" -#include "usb_moded-log.h" -#include "usb_moded-devicelock.h" -#include "usb_moded-modesetting.h" -#include "usb_moded-modules.h" -#include "usb_moded-appsync.h" -#include "usb_moded-trigger.h" -#include "usb_moded-config.h" -#include "usb_moded-config-private.h" -#include "usb_moded-network.h" -#include "usb_moded-mac.h" -#include "usb_moded-android.h" -#include "usb_moded-configfs.h" -#include "usb_moded-systemd.h" - -#ifdef MEEGOLOCK -# include "usb_moded-dsme.h" -#endif - -/* ========================================================================= * - * Constants - * ========================================================================= */ - -/* Wakelogging is noisy, do not log it by default */ -#ifndef VERBOSE_WAKELOCKING -# define VERBOSE_WAKELOCKING 0 -#endif - -/** Default allowed cable detection delay - * - * To comply with USB standards, the delay should be - * less than 2 seconds to ensure timely enumeration. - * - * Any value <= zero means no delay. - */ -#define CABLE_CONNECTION_DELAY_DEFAULT 0 - -/** Maximum allowed cable detection delay - * - * Must be shorter than initial probing delay expected by - * dsme (currently 5 seconds) to avoid reboot loops in - * act dead mode. - * - * And shorter than USB_MODED_SUSPEND_DELAY_DEFAULT_MS to - * allow the timer to trigger also in display off scenarios. - */ - -#define CABLE_CONNECTION_DELAY_MAXIMUM 4000 - -/* ========================================================================= * - * Types - * ========================================================================= */ - -/** A struct containing all the usb_moded info needed - */ -typedef struct usb_mode -{ - /** Connection status - * - * Access only via: - * - usbmoded_set_cable_state() - * - usbmoded_get_connection_state() - */ - cable_state_t cable_state; - - /** Mount status, true for mounted -UNUSED atm- */ - bool mounted; - - /** The logical mode name - * - * Full set of valid modes can occur here - */ - char *internal_mode; - - /* The hardware mode name - * - * How the usb hardware has been configured. - * - * For example internal_mode=MODE_ASK gets - * mapped to hardware_mode=MODE_CHARGING */ - char *hardware_mode; - - /* The external mode; - * - * What was the last mode signaled over D-Bus. - */ - char *external_mode; - - /**< The module name for the specific mode */ - char *module; - - /**< Contains the mode data */ - struct mode_list_elem *data; -} usb_mode; - -/** Mapping usb mode from internal to hardware/broadcast use */ -typedef struct modemapping_t -{ - /** Any valid usb mode */ - const char *internal_mode; - - /** Mode to use for usb configuration, or NULL = internal */ - const char *hardware_mode; - - /** Mode to use for D-Bus broadcast, or NULL = internal */ - const char *external_mode; -} modemapping_t; - -/* ========================================================================= * - * Prototypes - * ========================================================================= */ - -/* -- cable -- */ -const char *cable_state_repr(cable_state_t state); - -/* -- usbmoded -- */ - -static const char *usbmoded_map_mode_to_hardware(const char *internal_mode); -static const char *usbmoded_map_mode_to_external(const char *internal_mode); - -// ---------------------------------------------------------------- -void usbmoded_rethink_usb_charging_fallback(void); - -static bool usbmoded_switch_to_charging (void); -static void usbmoded_switch_to_mode (const char *mode); -static void usbmoded_mode_switched (const char *override); - -const char *usbmoded_get_hardware_mode (void); -static void usbmoded_update_hardware_mode (void); - -const char *usbmoded_get_external_mode (void); -static void usbmoded_set_external_mode (const char *mode); -static void usbmoded_update_external_mode (void); - -const char *usbmoded_get_usb_mode (void); -void usbmoded_set_usb_mode (const char *internal_mode); -void usbmoded_select_usb_mode (void); - -void usbmoded_set_cable_state (cable_state_t cable_state); -cable_state_t usbmoded_get_cable_state (void); -bool usbmoded_get_connection_state (void); - -// ---------------------------------------------------------------- -// internal movements - -static void usbmoded_set_cable_connection_delay (int delay_ms); - -static bool usbmoded_mode_in_list (const char *mode, char *const *modes); -int usbmoded_valid_mode (const char *mode); -gchar *usbmoded_get_mode_list (mode_list_type_t type); - -const char *usbmoded_get_usb_module (void); -bool usbmoded_set_usb_module (const char *module); - -struct mode_list_elem *usbmoded_get_usb_mode_data (void); -void usbmoded_set_usb_mode_data (struct mode_list_elem *data); - -void usbmoded_send_supported_modes_signal (void); -void usbmoded_send_available_modes_signal (void); -void usbmoded_send_hidden_modes_signal (void); -void usbmoded_send_whitelisted_modes_signal(void); - -static void usbmoded_write_to_sysfs_file (const char *path, const char *text); -void usbmoded_acquire_wakelock (const char *wakelock_name); -void usbmoded_release_wakelock (const char *wakelock_name); - -static gboolean usbmoded_allow_suspend_timer_cb (gpointer aptr); -void usbmoded_allow_suspend (void); -void usbmoded_delay_suspend (void); - -bool usbmoded_can_export (void); -bool usbmoded_init_done_p (void); -void usbmoded_set_init_done (bool reached); -void usbmoded_probe_init_done (void); - -void usbmoded_exit_mainloop (int exitcode); -static void usbmoded_handle_signal (int signum); - -static void usbmoded_init (void); -static void usbmoded_cleanup (void); - -int usbmoded_system_ (const char *file, int line, const char *func, const char *command); -FILE *usbmoded_popen_ (const char *file, int line, const char *func, const char *command, const char *type); -void usbmoded_usleep_ (const char *file, int line, const char *func, useconds_t usec); - -static void usbmoded_usage (void); - -/* -- sigpipe -- */ - -static gboolean sigpipe_read_signal_cb (GIOChannel *channel, GIOCondition condition, gpointer data); -static void sigpipe_trap_signal_cb (int sig); -static bool sigpipe_crate_pipe (void); -static void sigpipe_trap_signals (void); -static bool sigpipe_init (void); - -/* ========================================================================= * - * Data - * ========================================================================= */ - -static int usb_moded_exitcode = EXIT_FAILURE; -static GMainLoop *usb_moded_mainloop = NULL; - -bool usbmoded_rescue_mode = false; -static bool diag_mode = false; -static bool hw_fallback = false; -#ifdef SYSTEMD -static bool systemd_notify = false; -#endif - -/** Currently allowed cable detection delay - */ -int usbmoded_cable_connection_delay = CABLE_CONNECTION_DELAY_DEFAULT; - -static struct usb_mode current_mode = { - .cable_state = CABLE_STATE_UNKNOWN, - .mounted = false, - .internal_mode = NULL, - .hardware_mode = NULL, - .external_mode = NULL, - .module = NULL, - .data = NULL, -}; - -static GList *modelist = 0; - -/** Path to init-done flag file */ -static const char init_done_flagfile[] = "/run/systemd/boot-status/init-done"; - -/** cached init-done-reached state */ -static bool init_done_reached = false; - -/** Flag for: USB_MODED_WAKELOCK_STATE_CHANGE has been acquired */ -static bool blocking_suspend = false; - -/** Timer for releasing USB_MODED_WAKELOCK_STATE_CHANGE */ -static guint allow_suspend_timer_id = 0; - -/** Pipe fd for transferring signals to mainloop context */ -static int sigpipe_fd = -1; - -static const modemapping_t modemapping[] = -{ - { - .internal_mode = MODE_UNDEFINED, - .hardware_mode = MODE_CHARGING, - .external_mode = 0, - }, - { - .internal_mode = MODE_ASK, - .hardware_mode = MODE_CHARGING, - .external_mode = 0, - }, - { - .internal_mode = MODE_MASS_STORAGE, - .hardware_mode = 0, - .external_mode = 0, - }, - { - .internal_mode = MODE_DEVELOPER, - .hardware_mode = 0, - .external_mode = 0, - }, - { - .internal_mode = MODE_MTP, - .hardware_mode = 0, - .external_mode = 0, - }, - { - .internal_mode = MODE_HOST, - .hardware_mode = 0, - .external_mode = 0, - }, - { - .internal_mode = MODE_CONNECTION_SHARING, - .hardware_mode = 0, - .external_mode = 0, - }, - { - .internal_mode = MODE_DIAG, - .hardware_mode = 0, - .external_mode = 0, - }, - { - .internal_mode = MODE_ADB, - .hardware_mode = 0, - .external_mode = 0, - }, - { - .internal_mode = MODE_PC_SUITE, - .hardware_mode = 0, - .external_mode = 0, - }, - { - .internal_mode = MODE_CHARGING, - .hardware_mode = MODE_CHARGING, - .external_mode = 0, - }, - { - .internal_mode = MODE_CHARGING_FALLBACK, - .hardware_mode = MODE_CHARGING, - .external_mode = MODE_ASK, - }, - { - .internal_mode = MODE_CHARGER, - .hardware_mode = MODE_CHARGING, - .external_mode = 0, - }, - // sentinel - { - .internal_mode = 0, - .hardware_mode = 0, - .external_mode = 0, - } -}; - -/* ========================================================================= * - * Functions - * ========================================================================= */ - -static bool usbmoded_mode_is_mtp_mode(const char *mode) -{ - return mode && !strcmp(mode, "mtp_mode"); -} - -static bool usbmoded_is_mtpd_running(void) -{ - /* ep0 becomes available when /dev/mtp is mounted. - * - * ep1, ep2, ep3 exist while mtp daemon is running, - * has ep0 opened and has written config data to it. - */ - static const char * const lut[] = { - "/dev/mtp/ep0", - "/dev/mtp/ep1", - "/dev/mtp/ep2", - "/dev/mtp/ep3", - 0 - }; - - bool ack = true; - - for( size_t i = 0; lut[i]; ++i ) { - if( access(lut[i], F_OK) == -1 ) { - ack = false; - break; - } - } - - return ack; -} - -static bool -usbmoded_stop_mtpd(void) -{ - bool ack = !usbmoded_is_mtpd_running(); - - if( ack ) { - log_debug("mtp daemon is not running"); - goto EXIT; - } - - int rc = usbmoded_system("systemctl-user stop buteo-mtp.service"); - if( rc != 0 ) { - log_warning("failed to stop mtp daemon; exit code = %d", rc); - goto EXIT; - } - - for( int attempts = 3; ; ) { - if( (ack = !usbmoded_is_mtpd_running()) ) { - log_debug("mtp daemon has stopped"); - break; - } - - if( --attempts <= 0) { - log_warning("failed to stop mtp daemon; giving up"); - break; - } - - log_debug("waiting for mtp daemon to stop"); - usbmoded_msleep(2000); - } -EXIT: - - return ack; -} - -static bool -usbmoded_start_mtpd(void) -{ - bool ack = usbmoded_is_mtpd_running(); - - if( ack ) { - log_debug("mtp daemon is not running"); - goto EXIT; - } - - int rc = usbmoded_system("systemctl-user start buteo-mtp.service"); - if( rc != 0 ) { - log_warning("failed to start mtp daemon; exit code = %d", rc); - goto EXIT; - } - - for( int attempts = 15; ; ) { - if( (ack = usbmoded_is_mtpd_running()) ) { - log_debug("mtp daemon has started"); - break; - } - - if( --attempts <= 0) { - log_warning("failed to start mtp daemon; giving up"); - break; - } - - log_debug("waiting for mtp daemon to start"); - usbmoded_msleep(2000); - } -EXIT: - - return ack; -} - -const char *cable_state_repr(cable_state_t state) -{ - static const char * const lut[CABLE_STATE_NUMOF] = { - [CABLE_STATE_UNKNOWN] = "unknown", - [CABLE_STATE_DISCONNECTED] = "disconnected", - [CABLE_STATE_CHARGER_CONNECTED] = "charger_connected", - [CABLE_STATE_PC_CONNECTED] = "pc_connected", - }; - return lut[state]; -} - -static const char * -usbmoded_map_mode_to_hardware(const char *internal_mode) -{ - const char *hardware_mode = 0; - - for( size_t i = 0; modemapping[i].internal_mode; ++i ) { - if( strcmp(modemapping[i].internal_mode, internal_mode) ) - continue; - hardware_mode = modemapping[i].hardware_mode; - break; - } - return hardware_mode ?: internal_mode; -} - -static const char * -usbmoded_map_mode_to_external(const char *internal_mode) -{ - const char *external_mode = 0; - - for( size_t i = 0; modemapping[i].internal_mode; ++i ) { - if( strcmp(modemapping[i].internal_mode, internal_mode) ) - continue; - external_mode = modemapping[i].external_mode; - break; - } - return external_mode ?: internal_mode; -} - -/** Check if we can/should leave charging fallback mode - * - * Called when device lock status, or device status (dsme) - * changes. - */ -void -usbmoded_rethink_usb_charging_fallback(void) -{ - /* Cable must be connected to a pc */ - if( usbmoded_get_cable_state() != CABLE_STATE_PC_CONNECTED ) - goto EXIT; - - /* Switching can happen only from MODE_UNDEFINED - * or MODE_CHARGING_FALLBACK */ - const char *usb_mode = usbmoded_get_usb_mode(); - - if( strcmp(usb_mode, MODE_UNDEFINED) && - strcmp(usb_mode, MODE_CHARGING_FALLBACK) ) - goto EXIT; - - if( !usbmoded_can_export() ) { - log_notice("exporting data not allowed; stay in %s", usb_mode); - goto EXIT; - } - - log_debug("attempt to leave %s", usb_mode); - usbmoded_select_usb_mode(); - -EXIT: - return; -} - -static bool usbmoded_switch_to_charging(void) -{ - bool ack = true; - - if( android_set_charging_mode() ) - goto SUCCESS; - - if( configfs_set_charging_mode() ) - goto SUCCESS; - - if( modules_in_use() ) { - if( usbmoded_set_usb_module(MODULE_MASS_STORAGE) ) - goto SUCCESS; - usbmoded_set_usb_module(MODULE_NONE); - } - - log_err("switch to charging mode failed"); - - ack = false; -SUCCESS: - return ack; -} - -static void usbmoded_switch_to_mode(const char *mode) -{ - const char *override = 0; - - /* set return to 1 to be sure to error out if no matching mode is found either */ - - log_debug("Cleaning up previous mode"); - - if( !usbmoded_mode_is_mtp_mode(mode) ) - usbmoded_stop_mtpd(); - - if( usbmoded_get_usb_mode_data() ) { - modesetting_leave_dynamic_mode(); - usbmoded_set_usb_mode_data(NULL); - } - - log_debug("Setting %s\n", mode); - - /* Mode mapping should mean we only see MODE_CHARGING here, but just - * in case redirect fixed charging related things to charging ... */ - - if( !strcmp(mode, MODE_CHARGING) || - !strcmp(mode, MODE_CHARGING_FALLBACK) || - !strcmp(mode, MODE_CHARGER) || - !strcmp(mode, MODE_UNDEFINED) || - !strcmp(mode, MODE_ASK)) { - goto CHARGE; - } - - if( !usbmoded_can_export() ) { - log_warning("Policy does not allow mode: %s", mode); - goto FAILED; - } - - /* go through all the dynamic modes if the modelist exists*/ - for( GList *iter = modelist; iter; iter = g_list_next(iter) ) - { - struct mode_list_elem *data = iter->data; - if( strcmp(mode, data->mode_name) ) - continue; - - log_debug("Matching mode %s found.\n", mode); - - /* set data before calling any of the dynamic mode functions - * as they will use the usbmoded_get_usb_mode_data function */ - usbmoded_set_usb_mode_data(data); - - if( usbmoded_mode_is_mtp_mode(mode) ) { - if( !usbmoded_start_mtpd() ) - goto FAILED; - } - - if( !usbmoded_set_usb_module(data->mode_module) ) - goto FAILED; - - if( !modesetting_enter_dynamic_mode() ) - goto FAILED; - - goto SUCCESS; - } - - log_warning("Matching mode %s was not found.", mode); - -FAILED: - override = MODE_CHARGING; - log_warning("mode setting failed, try %s", override); - usbmoded_set_usb_mode_data(NULL); - -CHARGE: - if( usbmoded_switch_to_charging() ) - goto SUCCESS; - - log_crit("failed to activate charging, all bets are off"); - - /* FIXME: double check this error path */ - - /* If we get here then usb_module loading failed, - * no mode matched, and charging setup failed too. - */ - - override = MODE_UNDEFINED; - log_warning("mode setting failed, fallback to %s", override); - usbmoded_set_usb_module(MODULE_NONE); - -SUCCESS: - /* TODO: WORKER -> MAIN THREAD BARRIER */ - usbmoded_mode_switched(override); - - return; -} - -const char *usbmoded_get_hardware_mode(void) -{ - return current_mode.hardware_mode ?: MODE_UNDEFINED; -} - -static void usbmoded_update_hardware_mode(void) -{ - const char *internal_mode = usbmoded_get_usb_mode(); - const char *hardware_mode = usbmoded_map_mode_to_hardware(internal_mode); - - gchar *previous = current_mode.hardware_mode; - if( !g_strcmp0(previous, hardware_mode) ) { - usbmoded_mode_switched(0); - goto EXIT; - } - - log_debug("hardware_mode: %s -> %s", - previous, hardware_mode); - - current_mode.hardware_mode = g_strdup(hardware_mode); - g_free(previous); - - // DO THE MODESWITCH - - /* TODO: MAIN THREAD -> WORKERBARRIER */ - usbmoded_switch_to_mode(current_mode.hardware_mode); - -EXIT: - return; -} - -const char *usbmoded_get_external_mode(void) -{ - return current_mode.external_mode ?: MODE_UNDEFINED; -} - -static void usbmoded_set_external_mode(const char *mode) -{ - gchar *previous = current_mode.external_mode; - if( !g_strcmp0(previous, mode) ) - goto EXIT; - - log_debug("external_mode: %s -> %s", - previous, mode); - - current_mode.external_mode = g_strdup(mode); - g_free(previous); - - // DO THE DBUS BROADCAST - - if( !strcmp(current_mode.external_mode, MODE_ASK) ) { - /* send signal, mode will be set when the dialog service calls - * the set_mode method call. */ - umdbus_send_state_signal(USB_CONNECTED_DIALOG_SHOW); - } - - umdbus_send_state_signal(current_mode.external_mode); - -EXIT: - return; -} - -static void usbmoded_update_external_mode(void) -{ - const char *internal_mode = usbmoded_get_usb_mode(); - const char *external_mode = usbmoded_map_mode_to_external(internal_mode); - - usbmoded_set_external_mode(external_mode); -} - -/** get the usb mode - * - * @return the currently set mode - * - */ -const char * usbmoded_get_usb_mode(void) -{ - return current_mode.internal_mode; -} - -/** set the usb mode - * - * @param mode The requested USB mode - */ -void usbmoded_set_usb_mode(const char *mode) -{ - gchar *previous = current_mode.internal_mode; - if( !g_strcmp0(previous, mode) ) - goto EXIT; - - log_debug("internal_mode: %s -> %s", - previous, mode); - - current_mode.internal_mode = g_strdup(mode); - g_free(previous); - - /* Invalidate current mode for the duration of mode transition */ - usbmoded_set_external_mode(MODE_BUSY); - - // PROPAGATE DOWN TO GADGET CONFIG - usbmoded_update_hardware_mode(); - -EXIT: - return; -} - -static void usbmoded_mode_switched(const char *override) -{ - if( override ) { - /* Requested usb mode could not be activated at - * gadget control level. Update state info, but - * do not retrigger lower levels - */ - - log_debug("hardware_mode: %s -> %s (OVERRIDE)", - current_mode.hardware_mode, - override); - - g_free(current_mode.hardware_mode), - current_mode.hardware_mode = g_strdup(override); - - log_debug("internal_mode: %s -> %s (OVERRIDE)", - current_mode.internal_mode, - override); - - g_free(current_mode.internal_mode), - current_mode.internal_mode = g_strdup(override); - } - - // PROPAGATE UP DBUS - usbmoded_update_external_mode(); - - return; -} - -/** set the chosen usb state - * - * gauge what mode to enter and then call usbmoded_set_usb_mode() - * - */ -void usbmoded_select_usb_mode(void) -{ - char *mode_to_set = 0; - - if( usbmoded_rescue_mode ) { - log_debug("Entering rescue mode!\n"); - usbmoded_set_usb_mode(MODE_DEVELOPER); - goto EXIT; - } - - if( diag_mode ) { - log_debug("Entering diagnostic mode!\n"); - if( modelist ) { - /* XXX 1st entry is just assumed to be diag mode??? */ - GList *iter = modelist; - struct mode_list_elem *data = iter->data; - usbmoded_set_usb_mode(data->mode_name); - } - goto EXIT; - } - - mode_to_set = config_get_mode_setting(); - - /* If there is only one allowed mode, use it without - * going through ask-mode */ - if( !strcmp(MODE_ASK, mode_to_set) ) { - // FIXME free() vs g_free() conflict - gchar *available = usbmoded_get_mode_list(AVAILABLE_MODES_LIST); - if( *available && !strchr(available, ',') ) { - free(mode_to_set), mode_to_set = available, available = 0; - } - g_free(available); - } - - if( mode_to_set && usbmoded_can_export() ) { - usbmoded_set_usb_mode(mode_to_set); - } - else { - /* config is corrupted or we do not have a mode configured, fallback to charging - * We also fall back here in case the device is locked and we do not - * export the system contents. Or if we are in acting dead mode. - */ - usbmoded_set_usb_mode(MODE_CHARGING_FALLBACK); - } -EXIT: - free(mode_to_set); -} - -/** set the usb connection status - * - * @param cable_state CABLE_STATE_DISCONNECTED, ... - */ -void usbmoded_set_cable_state(cable_state_t cable_state) -{ - cable_state_t prev = current_mode.cable_state; - current_mode.cable_state = cable_state; - - if( current_mode.cable_state == prev ) - goto EXIT; - - log_debug("current_mode.cable_state: %s -> %s", - cable_state_repr(prev), - cable_state_repr(current_mode.cable_state)); - - switch( current_mode.cable_state ) { - default: - case CABLE_STATE_DISCONNECTED: - usbmoded_set_usb_mode(MODE_UNDEFINED); - break; - case CABLE_STATE_CHARGER_CONNECTED: - usbmoded_set_usb_mode(MODE_CHARGER); - break; - case CABLE_STATE_PC_CONNECTED: - usbmoded_select_usb_mode(); - break; - } - -EXIT: - return; -} - -/** get the usb connection status - * - * @return CABLE_STATE_DISCONNECTED, ... - */ -cable_state_t usbmoded_get_cable_state(void) -{ - return current_mode.cable_state; -} - -/** Get if the cable (pc or charger) is connected or not - * - * @ return true if connected, false if disconnected - */ -bool usbmoded_get_connection_state(void) -{ - bool connected = false; - switch( usbmoded_get_cable_state() ) { - case CABLE_STATE_CHARGER_CONNECTED: - case CABLE_STATE_PC_CONNECTED: - connected = true; - break; - default: - break; - } - return connected; -} - -/** Helper for setting allowed cable detection delay - * - * Used for implementing --max-cable-delay= option. - */ -static void usbmoded_set_cable_connection_delay(int delay_ms) -{ - if( delay_ms < CABLE_CONNECTION_DELAY_MAXIMUM ) - usbmoded_cable_connection_delay = delay_ms; - else { - usbmoded_cable_connection_delay = CABLE_CONNECTION_DELAY_MAXIMUM; - log_warning("using maximum connection delay: %d ms", - usbmoded_cable_connection_delay); - } -} - -/* check if a mode is in a list */ -static bool usbmoded_mode_in_list(const char *mode, char * const *modes) -{ - int i; - - if (!modes) - return false; - - for(i = 0; modes[i] != NULL; i++) - { - if(!strcmp(modes[i], mode)) - return true; - } - return false; -} - -/** check if a given usb_mode exists - * - * @param mode The mode to look for - * @return 0 if mode exists, 1 if it does not exist - * - */ -int usbmoded_valid_mode(const char *mode) -{ - int valid = 1; - /* MODE_ASK, MODE_CHARGER and MODE_CHARGING_FALLBACK are not modes that are settable seen their special 'internal' status - * so we only check the modes that are announed outside. Only exception is the built in MODE_CHARGING */ - if(!strcmp(MODE_CHARGING, mode)) - valid = 0; - else - { - char *whitelist; - gchar **whitelist_split = NULL; - - whitelist = config_get_mode_whitelist(); - if (whitelist) - { - whitelist_split = g_strsplit(whitelist, ",", 0); - g_free(whitelist); - } +#include "usb_moded.h" - /* check dynamic modes */ - if(modelist) - { - GList *iter; - - for( iter = modelist; iter; iter = g_list_next(iter) ) - { - struct mode_list_elem *data = iter->data; - if(!strcmp(mode, data->mode_name)) - { - if (!whitelist_split || usbmoded_mode_in_list(data->mode_name, whitelist_split)) - valid = 0; - break; - } - } - - g_strfreev(whitelist_split); - } - } - return valid; +#include "usb_moded-android.h" +#include "usb_moded-appsync.h" +#include "usb_moded-config-private.h" +#include "usb_moded-configfs.h" +#include "usb_moded-control.h" +#include "usb_moded-dbus-private.h" +#include "usb_moded-devicelock.h" +#include "usb_moded-log.h" +#include "usb_moded-mac.h" +#include "usb_moded-modesetting.h" +#include "usb_moded-modules.h" +#include "usb_moded-network.h" +#include "usb_moded-sigpipe.h" +#include "usb_moded-systemd.h" +#include "usb_moded-trigger.h" +#include "usb_moded-udev.h" +#include "usb_moded-worker.h" -} +#ifdef MEEGOLOCK +# include "usb_moded-dsme.h" +#endif -/** make a list of all available usb modes - * - * @param type The type of list to return. Supported or available. - * @return a comma-separated list of modes (MODE_ASK not included as it is not a real mode) - * - */ -gchar *usbmoded_get_mode_list(mode_list_type_t type) -{ - GString *modelist_str; +#include +#include +#include +#include +#include - modelist_str = g_string_new(NULL); +#ifdef SYSTEMD +# include +#endif - if(!diag_mode) - { - /* check dynamic modes */ - if(modelist) - { - GList *iter; - char *hidden_modes_list, *whitelist; - gchar **hidden_mode_split = NULL, **whitelist_split = NULL; - - hidden_modes_list = config_get_hidden_modes(); - if(hidden_modes_list) - { - hidden_mode_split = g_strsplit(hidden_modes_list, ",", 0); - g_free(hidden_modes_list); - } - - if (type == AVAILABLE_MODES_LIST) - { - whitelist = config_get_mode_whitelist(); - if (whitelist) - { - whitelist_split = g_strsplit(whitelist, ",", 0); - g_free(whitelist); - } - } - - for( iter = modelist; iter; iter = g_list_next(iter) ) - { - struct mode_list_elem *data = iter->data; - - /* skip items in the hidden list */ - if (usbmoded_mode_in_list(data->mode_name, hidden_mode_split)) - continue; - - /* if there is a whitelist skip items not in the list */ - if (whitelist_split && !usbmoded_mode_in_list(data->mode_name, whitelist_split)) - continue; - - modelist_str = g_string_append(modelist_str, data->mode_name); - modelist_str = g_string_append(modelist_str, ", "); - } - - g_strfreev(hidden_mode_split); - g_strfreev(whitelist_split); - } +/* ========================================================================= * + * Constants + * ========================================================================= */ - /* end with charging mode */ - g_string_append(modelist_str, MODE_CHARGING); - return g_string_free(modelist_str, false); - } - else - { - /* diag mode. there is only one active mode */ - g_string_append(modelist_str, MODE_DIAG); - return g_string_free(modelist_str, false); - } -} +/* Wakelogging is noisy, do not log it by default */ +#ifndef VERBOSE_WAKELOCKING +# define VERBOSE_WAKELOCKING 0 +#endif -/** get the supposedly loaded module +/** Default allowed cable detection delay * - * @return The name of the loaded module + * To comply with USB standards, the delay should be + * less than 2 seconds to ensure timely enumeration. * + * Any value <= zero means no delay. */ -const char * usbmoded_get_usb_module(void) -{ - return current_mode.module ?: MODULE_NONE; -} +#define CABLE_CONNECTION_DELAY_DEFAULT 0 -/** set the loaded module +/** Maximum allowed cable detection delay * - * @param module The module name for the requested mode + * Must be shorter than initial probing delay expected by + * dsme (currently 5 seconds) to avoid reboot loops in + * act dead mode. * + * And shorter than USB_MODED_SUSPEND_DELAY_DEFAULT_MS to + * allow the timer to trigger also in display off scenarios. */ -bool usbmoded_set_usb_module(const char *module) -{ - bool ack = false; - if( !module ) - module = MODULE_NONE; +#define CABLE_CONNECTION_DELAY_MAXIMUM 4000 - const char *current = usbmoded_get_usb_module(); +/* ========================================================================= * + * Prototypes + * ========================================================================= */ - log_debug("current module: %s -> %s", current, module); +/* -- usbmoded -- */ - if( !g_strcmp0(current, module) ) - goto SUCCESS; +GList *usbmoded_get_modelist (void); +void usbmoded_load_modelist (void); +void usbmoded_free_modelist (void); +bool usbmoded_get_rescue_mode (void); +void usbmoded_set_rescue_mode (bool rescue_mode); +bool usbmoded_get_diag_mode (void); +void usbmoded_set_diag_mode (bool diag_mode); +void usbmoded_set_cable_connection_delay(int delay_ms); +int usbmoded_get_cable_connection_delay(void); +static gboolean usbmoded_allow_suspend_timer_cb (gpointer aptr); +void usbmoded_allow_suspend (void); +void usbmoded_delay_suspend (void); +bool usbmoded_init_done_p (void); +void usbmoded_set_init_done (bool reached); +void usbmoded_probe_init_done (void); +bool usbmoded_can_export (void); +void usbmoded_exit_mainloop (int exitcode); +void usbmoded_handle_signal (int signum); +static bool usbmoded_init (void); +static void usbmoded_cleanup (void); +static void usbmoded_usage (void); +static void usbmoded_parse_options (int argc, char *argv[]); - if( modules_unload_module(current) != 0 ) - goto EXIT; +/* ========================================================================= * + * Data + * ========================================================================= */ - free(current_mode.module), current_mode.module = 0; +static int usbmoded_exitcode = EXIT_FAILURE; +static GMainLoop *usbmoded_mainloop = NULL; - if( modules_load_module(module) != 0 ) - goto EXIT; +static bool usbmoded_hw_fallback = false; +#ifdef SYSTEMD +static bool usbmoded_systemd_notify = false; +#endif - if( g_strcmp0(module, MODULE_NONE) ) - current_mode.module = strdup(module); +/* ========================================================================= * + * Functions + * ========================================================================= */ -SUCCESS: - ack = true; -EXIT: - return ack; -} +/* ------------------------------------------------------------------------- * + * MODELIST + * ------------------------------------------------------------------------- */ -/** get the usb mode data - * - * @return a pointer to the usb mode data - * - */ -struct mode_list_elem * usbmoded_get_usb_mode_data(void) +static GList *usbmoded_modelist = 0; + +GList * +usbmoded_get_modelist(void) { - return current_mode.data; + return usbmoded_modelist; } -/** set the mode_list_elem data - * - * @param data mode_list_element pointer - * - */ -void usbmoded_set_usb_mode_data(struct mode_list_elem *data) +void +usbmoded_load_modelist(void) { - current_mode.data = data; + if( !usbmoded_modelist ) { + log_notice("load modelist"); + usbmoded_modelist = dynconfig_read_mode_list(usbmoded_get_diag_mode()); + } } -/** Send supported modes signal - */ -void usbmoded_send_supported_modes_signal(void) +void +usbmoded_free_modelist(void) { - gchar *mode_list = usbmoded_get_mode_list(SUPPORTED_MODES_LIST); - umdbus_send_supported_modes_signal(mode_list); - g_free(mode_list); + if( usbmoded_modelist ) { + log_notice("free modelist"); + dynconfig_free_mode_list(usbmoded_modelist), + usbmoded_modelist = 0; + } } -/** Send available modes signal +/* ------------------------------------------------------------------------- * + * RESCUE_MODE + * ------------------------------------------------------------------------- */ + +/** Rescue mode flag + * + * When enabled, usb-moded allows developer_mode etc when device is + * booted up with cable connected without requiring device unlock. + * Which can be useful if UI for some reason does not come up. */ -void usbmoded_send_available_modes_signal(void) +static bool usbmoded_rescue_mode = false; + +bool usbmoded_get_rescue_mode(void) { - gchar *mode_list = usbmoded_get_mode_list(AVAILABLE_MODES_LIST); - umdbus_send_available_modes_signal(mode_list); - g_free(mode_list); + return usbmoded_rescue_mode; } -/** Send hidden modes signal - */ -void usbmoded_send_hidden_modes_signal(void) +void usbmoded_set_rescue_mode(bool rescue_mode) { - gchar *mode_list = config_get_hidden_modes(); - if(mode_list) { - // TODO: cleared list not signaled? - umdbus_send_hidden_modes_signal(mode_list); - g_free(mode_list); + if( usbmoded_rescue_mode != rescue_mode ) { + log_info("rescue_mode: %d -> %d", usbmoded_rescue_mode, rescue_mode); + usbmoded_rescue_mode = rescue_mode; } } -/** Send whitelisted modes signal +/* ------------------------------------------------------------------------- * + * DIAG_MODE + * ------------------------------------------------------------------------- */ + +/** Diagnostic mode active + * + * In diag mode usb-moded uses separate mode configuration which + * should have exactly one mode defined / available. */ -void usbmoded_send_whitelisted_modes_signal(void) +static bool usbmoded_diag_mode = false; + +bool usbmoded_get_diag_mode(void) { - gchar *mode_list = config_get_mode_whitelist(); - if(mode_list) { - // TODO: cleared list not signaled? - umdbus_send_whitelisted_modes_signal(mode_list); - g_free(mode_list); + return usbmoded_diag_mode; +} + +void usbmoded_set_diag_mode(bool diag_mode) +{ + if( usbmoded_diag_mode != diag_mode ) { + log_info("diag_mode: %d -> %d", usbmoded_diag_mode, diag_mode); + usbmoded_diag_mode = diag_mode; } } -/** Write string to already existing sysfs file +/* ------------------------------------------------------------------------- * + * CABLE_CONNECT_DELAY + * ------------------------------------------------------------------------- */ + +/** PC connection delay * - * Note: Attempts to write to nonexisting files are silently ignored. + * Slow cable insert / similar physical issues can lead to a charger + * getting initially recognized as a pc connection. This defines how + * long we should wait and see if pc connection gets corrected to a + * charger kind. + */ +static int usbmoded_cable_connection_delay = CABLE_CONNECTION_DELAY_DEFAULT; + +/** Helper for setting allowed cable detection delay * - * @param path Where to write - * @param text What to write + * Used for implementing --max-cable-delay= option. */ -static void usbmoded_write_to_sysfs_file(const char *path, const char *text) +void +usbmoded_set_cable_connection_delay(int delay_ms) { - int fd = -1; - - if (!path || !text) - goto EXIT; - - if ((fd = open(path, O_WRONLY)) == -1) { - if (errno != ENOENT) { - log_warning("%s: open for writing failed: %m", path); - } - goto EXIT; - } + if( delay_ms > CABLE_CONNECTION_DELAY_MAXIMUM ) + delay_ms = CABLE_CONNECTION_DELAY_MAXIMUM; + if( delay_ms < 0 ) + delay_ms = 0; - if (write(fd, text, strlen(text)) == -1) { - log_warning("%s: write failed : %m", path); - goto EXIT; + if( usbmoded_cable_connection_delay != delay_ms ) { + log_info("cable_connection_delay: %d -> %d", + usbmoded_cable_connection_delay, + delay_ms); + usbmoded_cable_connection_delay = delay_ms; } -EXIT: - if (fd != -1) - close(fd); } -/** Acquire wakelock via sysfs - * - * Wakelock must be released via usbmoded_release_wakelock(). - * - * Automatically terminating wakelock is used, so that we - * do not block suspend indefinately in case usb_moded - * gets stuck or crashes. - * - * Note: The name should be unique within the system. - * - * @param wakelock_name Wake lock to be acquired +/** Helper for getting allowed cable detection delay */ -void usbmoded_acquire_wakelock(const char *wakelock_name) +int +usbmoded_get_cable_connection_delay(void) { - char buff[256]; - snprintf(buff, sizeof buff, "%s %lld", - wakelock_name, - USB_MODED_SUSPEND_DELAY_MAXIMUM_MS * 1000000LL); - usbmoded_write_to_sysfs_file("/sys/power/wake_lock", buff); - -#if VERBOSE_WAKELOCKING - log_debug("usbmoded_acquire_wakelock %s", wakelock_name); -#endif + return usbmoded_cable_connection_delay; } -/** Release wakelock via sysfs - * - * @param wakelock_name Wake lock to be released - */ -void usbmoded_release_wakelock(const char *wakelock_name) -{ -#if VERBOSE_WAKELOCKING - log_debug("usbmoded_release_wakelock %s", wakelock_name); -#endif +/* ------------------------------------------------------------------------- * + * SUSPEND_BLOCKING + * ------------------------------------------------------------------------- */ - usbmoded_write_to_sysfs_file("/sys/power/wake_unlock", wakelock_name); -} +/** Flag for: USB_MODED_WAKELOCK_STATE_CHANGE has been acquired */ +static bool usbmoded_blocking_suspend = false; + +/** Timer for releasing USB_MODED_WAKELOCK_STATE_CHANGE */ +static guint usbmoded_allow_suspend_timer_id = 0; /** Timer callback for releasing wakelock acquired via usbmoded_delay_suspend() * @@ -1238,7 +282,7 @@ static gboolean usbmoded_allow_suspend_timer_cb(gpointer aptr) { (void)aptr; - allow_suspend_timer_id = 0; + usbmoded_allow_suspend_timer_id = 0; usbmoded_allow_suspend(); @@ -1252,14 +296,14 @@ static gboolean usbmoded_allow_suspend_timer_cb(gpointer aptr) */ void usbmoded_allow_suspend(void) { - if( allow_suspend_timer_id ) { - g_source_remove(allow_suspend_timer_id), - allow_suspend_timer_id = 0; + if( usbmoded_allow_suspend_timer_id ) { + g_source_remove(usbmoded_allow_suspend_timer_id), + usbmoded_allow_suspend_timer_id = 0; } - if( blocking_suspend ) { - blocking_suspend = false; - usbmoded_release_wakelock(USB_MODED_WAKELOCK_STATE_CHANGE); + if( usbmoded_blocking_suspend ) { + usbmoded_blocking_suspend = false; + common_release_wakelock(USB_MODED_WAKELOCK_STATE_CHANGE); } } @@ -1277,18 +321,22 @@ void usbmoded_delay_suspend(void) { /* Use of automatically terminating wakelocks also means we need * to renew the wakelock when extending the suspend delay. */ - usbmoded_acquire_wakelock(USB_MODED_WAKELOCK_STATE_CHANGE); + common_acquire_wakelock(USB_MODED_WAKELOCK_STATE_CHANGE); - blocking_suspend = true; + usbmoded_blocking_suspend = true; - if( allow_suspend_timer_id ) - g_source_remove(allow_suspend_timer_id); + if( usbmoded_allow_suspend_timer_id ) + g_source_remove(usbmoded_allow_suspend_timer_id); - allow_suspend_timer_id = + usbmoded_allow_suspend_timer_id = g_timeout_add(USB_MODED_SUSPEND_DELAY_DEFAULT_MS, usbmoded_allow_suspend_timer_cb, 0); } +/* ------------------------------------------------------------------------- * + * CAN_EXPORT + * ------------------------------------------------------------------------- */ + /** Check if exposing device data is currently allowed * * @return true exposing data is ok, or false otherwise @@ -1304,60 +352,74 @@ bool usbmoded_can_export(void) devicelock_have_export_permission()); /* Having bootup rescue mode active is an exception */ - if( usbmoded_rescue_mode ) + if( usbmoded_get_rescue_mode() ) can_export = true; #endif return can_export; } +/* ------------------------------------------------------------------------- * + * INIT_DONE + * ------------------------------------------------------------------------- */ + +/** Path to init-done flag file */ +static const char usbmoded_init_done_flagfile[] = "/run/systemd/boot-status/init-done"; + +/** cached init-done-reached state */ +static bool usbmoded_init_done_reached = false; + /** Check if system has already been successfully booted up * * @return true if init-done has been reached, or false otherwise */ bool usbmoded_init_done_p(void) { - return init_done_reached; + return usbmoded_init_done_reached; } /** Update cached init-done-reached state */ void usbmoded_set_init_done(bool reached) { - if( init_done_reached != reached ) { - init_done_reached = reached; + if( usbmoded_init_done_reached != reached ) { + usbmoded_init_done_reached = reached; log_warning("init_done -> %s", - init_done_reached ? "reached" : "not reached"); + usbmoded_init_done_reached ? "reached" : "not reached"); } } /** Check whether init-done flag file exists */ void usbmoded_probe_init_done(void) { - usbmoded_set_init_done(access(init_done_flagfile, F_OK) == 0); + usbmoded_set_init_done(access(usbmoded_init_done_flagfile, F_OK) == 0); } +/* ------------------------------------------------------------------------- * + * MAINLOOP + * ------------------------------------------------------------------------- */ + /** Request orderly exit from mainloop */ void usbmoded_exit_mainloop(int exitcode) { /* In case multiple exit request get done, retain the * highest exit code used. */ - if( usb_moded_exitcode < exitcode ) - usb_moded_exitcode = exitcode; + if( usbmoded_exitcode < exitcode ) + usbmoded_exitcode = exitcode; /* If there is no mainloop to exit, terminate immediately */ - if( !usb_moded_mainloop ) + if( !usbmoded_mainloop ) { log_warning("exit requested outside mainloop; exit(%d) now", - usb_moded_exitcode); - exit(usb_moded_exitcode); + usbmoded_exitcode); + exit(usbmoded_exitcode); } log_debug("stopping usb-moded mainloop"); - g_main_loop_quit(usb_moded_mainloop); + g_main_loop_quit(usbmoded_mainloop); } -static void usbmoded_handle_signal(int signum) +void usbmoded_handle_signal(int signum) { log_debug("handle signal: %s\n", strsignal(signum)); @@ -1369,12 +431,11 @@ static void usbmoded_handle_signal(int signum) else if( signum == SIGHUP ) { /* free and read in modelist again */ - dynconfig_free_mode_list(modelist); - - modelist = dynconfig_read_mode_list(diag_mode); + usbmoded_free_modelist(); + usbmoded_load_modelist(); - usbmoded_send_supported_modes_signal(); - usbmoded_send_available_modes_signal(); + common_send_supported_modes_signal(); + common_send_available_modes_signal(); // FIXME invalidate current mode } @@ -1384,29 +445,72 @@ static void usbmoded_handle_signal(int signum) } } -/* set default values for usb_moded */ -static void usbmoded_init(void) +/* Prepare usb-moded for running the mainloop */ +static bool usbmoded_init(void) { - current_mode.cable_state = CABLE_STATE_UNKNOWN; - current_mode.mounted = false; - current_mode.internal_mode = strdup(MODE_UNDEFINED); - current_mode.hardware_mode = NULL; - current_mode.external_mode = NULL; - current_mode.module = NULL; + bool ack = false; + + /* Check if we are in mid-bootup */ + usbmoded_probe_init_done(); + + if( !worker_init() ) { + log_crit("worker thread init failed"); + goto EXIT; + } + + if( !sigpipe_init() ) { + log_crit("signal handler init failed"); + goto EXIT; + } + + if( usbmoded_get_rescue_mode() && usbmoded_init_done_p() ) { + usbmoded_set_rescue_mode(false); + log_warning("init done passed; rescue mode ignored"); + } + + /* Connect to SystemBus */ + if( !umdbus_init_connection() ) { + log_crit("dbus systembus connection failed"); + goto EXIT; + } + + /* Start DBus trackers that do async initialization + * so that initial method calls are on the way while + * we do initialization actions that might block. */ + + /* DSME listener maintains in-user-mode state and is relevant + * only when MEEGOLOCK configure option has been chosen. */ +#ifdef MEEGOLOCK + if( !dsme_listener_start() ) { + log_crit("dsme tracking could not be started"); + goto EXIT; + } +#endif + + /* Devicelock listener maintains devicelock state and is relevant + * only when MEEGOLOCK configure option has been chosen. */ +#ifdef MEEGOLOCK + if( !devicelock_start_listener() ) { + log_crit("devicelock tracking could not be started"); + goto EXIT; + } +#endif + + /* Set daemon config/state data to sane state */ + modesetting_init(); /* check config, merge or create if outdated */ - if(config_merge_conf_file() != 0) - { - log_err("Cannot create or find a valid configuration. Exiting.\n"); - exit(1); + if( config_merge_conf_file() != 0 ) { + log_crit("Cannot create or find a valid configuration"); + goto EXIT; } #ifdef APP_SYNC - appsync_read_list(diag_mode); + appsync_read_list(usbmoded_get_diag_mode()); #endif /* always read dyn modes even if appsync is not used */ - modelist = dynconfig_read_mode_list(diag_mode); + usbmoded_load_modelist(); if(config_check_trigger()) trigger_init(); @@ -1429,7 +533,7 @@ static void usbmoded_init(void) if( android_init_values() ) break; - /* Must probe /pollsince we're not yet running mainloop */ + /* Must probe / poll since we're not yet running mainloop */ usbmoded_probe_init_done(); if( usbmoded_init_done_p() || --i <= 0 ) { @@ -1438,338 +542,216 @@ static void usbmoded_init(void) break; } - usbmoded_msleep(1000); + common_msleep(1000); } - /* TODO: add more start-up clean-up and init here if needed */ -} - -/** Release resources allocated by usbmoded_init() - */ -static void usbmoded_cleanup(void) -{ - /* Undo modules_init() */ - modules_quit(); - - /* Undo trigger_init() */ - trigger_stop(); - - /* Undo dynconfig_read_mode_list() */ - dynconfig_free_mode_list(modelist); - -#ifdef APP_SYNC - /* Undo appsync_read_list() */ - appsync_free_appsync_list(); -#endif - - /* Release dynamic memory */ - free(current_mode.module), - current_mode.module = 0; - - free(current_mode.internal_mode), - current_mode.internal_mode = 0; - - free(current_mode.hardware_mode), - current_mode.hardware_mode = 0; - - free(current_mode.external_mode), - current_mode.external_mode = 0; -} - -/** Wrapper to give visibility to blocking system() calls usb-moded is making - */ -int -usbmoded_system_(const char *file, int line, const char *func, - const char *command) -{ - log_debug("EXEC %s; from %s:%d: %s()", - command, file, line, func); - - int rc = system(command); - - if( rc != 0 ) - log_warning("EXEC %s; exit code is %d", command, rc); - - return rc; -} - -/** Wrapper to give visibility subprocesses usb-moded is invoking via popen() - */ -FILE * -usbmoded_popen_(const char *file, int line, const char *func, - const char *command, const char *type) -{ - log_debug("EXEC %s; from %s:%d: %s()", - command, file, line, func); - - return popen(command, type); -} - -/** Wrapper to give visibility to blocking sleeps usb-moded is making - */ -void -usbmoded_usleep_(const char *file, int line, const char *func, - useconds_t usec) -{ - struct timespec ts = { - .tv_sec = (usec / 1000000), - .tv_nsec = (usec % 1000000) * 1000 - }; - - long ms = (ts.tv_nsec + 1000000 - 1) / 1000000; - - if( !ms ) { - log_debug("SLEEP %ld seconds; from %s:%d: %s()", - (long)ts.tv_sec, file, line, func); - } - else if( ts.tv_sec ) { - log_debug("SLEEP %ld.%03ld seconds; from %s:%d: %s()", - (long)ts.tv_sec, ms, file, line, func); - } - else { - log_debug("SLEEP %ld milliseconds; from %s:%d: %s()", - ms, file, line, func); + /* Allow making systemd control ipc */ + if( !systemd_control_start() ) { + log_crit("systemd control could not be started"); + goto EXIT; } - do { } while( nanosleep(&ts, &ts) == -1 && errno != EINTR ); -} - -/** Glib io watch callback for reading signals from signal pipe - * - * @param channel glib io channel - * @param condition wakeup reason - * @param data user data (unused) - * - * @return TRUE to keep the iowatch, or FALSE to disable it - */ -static gboolean -sigpipe_read_signal_cb(GIOChannel *channel, - GIOCondition condition, - gpointer data) -{ - gboolean keep_watch = FALSE; - - int fd, rc, sig; - - (void)data; + /* If usb-moded happens to crash, it could leave appsync processes + * running. To make sure things are in the order expected by usb-moded + * force stopping of appsync processes during usb-moded startup. + * + * The exception is: When usb-moded starts as a part of bootup. Then + * we can be relatively sure that usb-moded has not been running yet + * and therefore no appsync processes have been started and we can + * skip the blocking ipc required to stop the appsync systemd units. */ +#ifdef APP_SYNC + if( usbmoded_init_done_p() ) { + log_warning("usb-moded started after init-done; " + "forcing appsync stop"); + appsync_stop(true); + } +#endif - /* Should never happen, but we must disable the io watch - * if the pipe fd still goes into unexpected state ... */ - if( condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL) ) + /* Claim D-Bus service name before proceeding with things that + * could result in dbus signal broadcasts from usb-moded interface. + */ + if( !umdbus_init_service() ) { + log_crit("usb-moded dbus service init failed"); goto EXIT; + } - if( (fd = g_io_channel_unix_get_fd(channel)) == -1 ) + /* Initialize udev listener. Can cause mode changes. + * + * Failing here is allowed if '--fallback' commandline option is used. + */ + if( !umudev_init() && !usbmoded_hw_fallback ) { + log_crit("hwal init failed"); goto EXIT; + } - /* If the actual read fails, terminate with core dump */ - rc = TEMP_FAILURE_RETRY(read(fd, &sig, sizeof sig)); - if( rc != (int)sizeof sig ) - abort(); - - /* handle the signal */ - usbmoded_handle_signal(sig); - - keep_watch = TRUE; - -EXIT: - if( !keep_watch ) - log_crit("disabled signal handler io watch\n"); - - return keep_watch; -} - -/** Async signal handler for writing signals to signal pipe - * - * @param sig the signal number to pass to mainloop via pipe - */ -static void -sigpipe_trap_signal_cb(int sig) -{ - /* NOTE: This function *MUST* be kept async-signal-safe! */ - - static volatile int exit_tries = 0; - - int rc; - - /* Restore signal handler */ - signal(sig, sigpipe_trap_signal_cb); + /* Broadcast supported / hidden modes */ + // TODO: should this happen before umudev_init()? + common_send_supported_modes_signal(); + common_send_available_modes_signal(); + common_send_hidden_modes_signal(); + common_send_whitelisted_modes_signal(); - switch( sig ) - { - case SIGINT: - case SIGQUIT: - case SIGTERM: - /* If we receive multiple signals that should have - * caused the process to exit, assume that mainloop - * is stuck and terminate with core dump. */ - if( ++exit_tries >= 2 ) - abort(); - break; - - default: - break; + /* Act on '--fallback' commandline option */ + if( usbmoded_hw_fallback ) { + log_warning("Forcing USB state to connected always. ASK mode non functional!"); + /* Since there will be no disconnect signals coming from hw the state should not change */ + control_set_cable_state(CABLE_STATE_PC_CONNECTED); } - /* Transfer the signal to mainloop via pipe ... */ - rc = TEMP_FAILURE_RETRY(write(sigpipe_fd, &sig, sizeof sig)); + ack = true; - /* ... or terminate with core dump in case of failures */ - if( rc != (int)sizeof sig ) - abort(); +EXIT: + return ack; } -/** Create a pipe and io watch for handling signal from glib mainloop - * - * @return true on success, or false in case of errors +/** Release resources allocated by usbmoded_init() */ -static bool -sigpipe_crate_pipe(void) +static void usbmoded_cleanup(void) { - bool res = false; - GIOChannel *chn = 0; - int pfd[2] = { -1, -1 }; + /* Stop the worker thread first to avoid confusion about shared + * resources we are just about to release. */ + worker_quit(); - if( pipe2(pfd, O_CLOEXEC) == -1 ) - goto EXIT; + /* Detach from SystemBus. Components that hold reference to the + * shared bus connection can still perform cleanup tasks, but new + * references can't be obtained anymore and usb-moded method call + * processing no longer occurs. */ + umdbus_cleanup(); - if( (chn = g_io_channel_unix_new(pfd[0])) == 0 ) - goto EXIT; + /* Stop appsync processes that have been started by usb-moded */ +#ifdef APP_SYNC + appsync_stop(false); +#endif - if( !g_io_add_watch(chn, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, - sigpipe_read_signal_cb, 0) ) - goto EXIT; + /* Deny making systemd control ipc */ + systemd_control_stop(); - g_io_channel_set_close_on_unref(chn, true), pfd[0] = -1; - sigpipe_fd = pfd[1], pfd[1] = -1; + /* Stop tracking devicelock status */ +#ifdef MEEGOLOCK + devicelock_stop_listener(); +#endif - res = true; + /* Stop tracking device state */ +#ifdef MEEGOLOCK + dsme_listener_stop(); +#endif -EXIT: - if( chn ) g_io_channel_unref(chn); - if( pfd[0] != -1 ) close(pfd[0]); - if( pfd[1] != -1 ) close(pfd[1]); + /* Stop udev listener */ + umudev_quit(); - return res; -} + /* Undo modules_init() */ + modules_quit(); -/** Install async signal handlers - */ -static void -sigpipe_trap_signals(void) -{ - static const int sig[] = - { - SIGINT, - SIGQUIT, - SIGTERM, - SIGHUP, - -1 - }; - - for( size_t i = 0; sig[i] != -1; ++i ) - { - signal(sig[i], sigpipe_trap_signal_cb); - } -} + /* Undo trigger_init() */ + trigger_stop(); -/** Initialize signal trapping - * - * @return true on success, or false in case of errors - */ -static bool -sigpipe_init(void) -{ - bool success = false; + /* Undo usbmoded_load_modelist() */ + usbmoded_free_modelist(); - if( !sigpipe_crate_pipe() ) - goto EXIT; +#ifdef APP_SYNC + /* Undo appsync_read_list() */ + appsync_free_appsync_list(); +#endif - sigpipe_trap_signals(); + /* Release dynamic memory */ + worker_clear_kernel_module(); + worker_clear_hardware_mode(); + control_clear_cable_state(); + control_clear_internal_mode(); + control_clear_external_mode(); - success = true; + modesetting_quit(); -EXIT: - return success; + /* Detach from SessionBus connection used for APP_SYNC_DBUS. + * + * Can be handled separately from SystemBus side wind down. */ +#ifdef APP_SYNC +# ifdef APP_SYNC_DBUS + dbusappsync_cleanup(); +# endif +#endif } /* ========================================================================= * * MAIN ENTRY * ========================================================================= */ +static const char usbmoded_usage_info[] = +"Usage: usb_moded [OPTION]...\n" +"USB mode daemon\n" +"\n" +" -a, --android_usb_broken\n" +" keep gadget active on broken android kernels\n" +" -i, --android_usb_broken_udev_events\n" +" ignore incorrect disconnect events after mode setting\n" +" -f, --fallback \n" +" assume always connected\n" +" -s, --force-syslog \n" +" log to syslog\n" +" -T, --force-stderr \n" +" log to stderr\n" +" -l, --log-line-info\n" +" log to stderr and show origin of logging\n" +" -D, --debug \n" +" turn on debug printing\n" +" -d, --diag \n" +" turn on diag mode\n" +" -h, --help \n" +" display this help and exit\n" +" -r, --rescue \n" +" rescue mode\n" +#ifdef SYSTEMD +" -n, --systemd \n" +" notify systemd when started up\n" +#endif +" -v, --version \n" +" output version information and exit\n" +" -m, --max-cable-delay=\n" +" maximum delay before accepting cable connection\n" +" -b, --android-bootup-function=\n" +" Setup given function during bootup. Might be required\n" +" on some devices to make enumeration work on the 1st\n" +" cable connect.\n" +"\n"; + +static const struct option const usbmoded_long_options[] = +{ + { "android_usb_broken", no_argument, 0, 'a' }, + { "android_usb_broken_udev_events", no_argument, 0, 'i' }, + { "fallback", no_argument, 0, 'd' }, + { "force-syslog", no_argument, 0, 's' }, + { "force-stderr", no_argument, 0, 'T' }, + { "log-line-info", no_argument, 0, 'l' }, + { "debug", no_argument, 0, 'D' }, + { "diag", no_argument, 0, 'd' }, + { "help", no_argument, 0, 'h' }, + { "rescue", no_argument, 0, 'r' }, + { "systemd", no_argument, 0, 'n' }, + { "version", no_argument, 0, 'v' }, + { "max-cable-delay", required_argument, 0, 'm' }, + { "android-bootup-function", required_argument, 0, 'b' }, + { 0, 0, 0, 0 } +}; + +static const char usbmoded_short_options[] = "aifsTlDdhrnvm:b:"; + /* Display usbmoded_usage information */ static void usbmoded_usage(void) { - fprintf(stdout, - "Usage: usb_moded [OPTION]...\n" - "USB mode daemon\n" - "\n" - " -a, --android_usb_broken\n" - " keep gadget active on broken android kernels\n" - " -i, --android_usb_broken_udev_events\n" - " ignore incorrect disconnect events after mode setting\n" - " -f, --fallback \n" - " assume always connected\n" - " -s, --force-syslog \n" - " log to syslog\n" - " -T, --force-stderr \n" - " log to stderr\n" - " -l, --log-line-info\n" - " log to stderr and show origin of logging\n" - " -D, --debug \n" - " turn on debug printing\n" - " -d, --diag \n" - " turn on diag mode\n" - " -h, --help \n" - " display this help and exit\n" - " -r, --rescue \n" - " rescue mode\n" -#ifdef SYSTEMD - " -n, --systemd \n" - " notify systemd when started up\n" -#endif - " -v, --version \n" - " output version information and exit\n" - " -m, --max-cable-delay=\n" - " maximum delay before accepting cable connection\n" - " -b, --android-bootup-function=\n" - " Setup given function during bootup. Might be required\n" - " on some devices to make enumeration work on the 1st\n" - " cable connect.\n" - "\n"); + fprintf(stdout, "%s", usbmoded_usage_info); } -int main(int argc, char* argv[]) +static void usbmoded_parse_options(int argc, char* argv[]) { - int opt = 0, opt_idx = 0; - - struct option const options[] = { - { "android_usb_broken", no_argument, 0, 'a' }, - { "android_usb_broken_udev_events", no_argument, 0, 'i' }, - { "fallback", no_argument, 0, 'd' }, - { "force-syslog", no_argument, 0, 's' }, - { "force-stderr", no_argument, 0, 'T' }, - { "log-line-info", no_argument, 0, 'l' }, - { "debug", no_argument, 0, 'D' }, - { "diag", no_argument, 0, 'd' }, - { "help", no_argument, 0, 'h' }, - { "rescue", no_argument, 0, 'r' }, - { "systemd", no_argument, 0, 'n' }, - { "version", no_argument, 0, 'v' }, - { "max-cable-delay", required_argument, 0, 'm' }, - { "android-bootup-function", required_argument, 0, 'b' }, - { 0, 0, 0, 0 } - }; - - log_init(); - log_set_name(basename(*argv)); - - /* - - - - - - - - - - - - - - - - - - - * - * OPTIONS - * - - - - - - - - - - - - - - - - - - - */ - /* Parse the command-line options */ - while ((opt = getopt_long(argc, argv, "aifsTlDdhrnvm:b:", options, &opt_idx)) != -1) - { + for( ;; ) { + int opt = getopt_long(argc, argv, + usbmoded_short_options, + usbmoded_long_options, + 0); + if( opt == -1 ) + break; + switch (opt) { case 'a': @@ -1779,7 +761,7 @@ int main(int argc, char* argv[]) log_warning("Deprecated option: --android_usb_broken_udev_events"); break; case 'f': - hw_fallback = true; + usbmoded_hw_fallback = true; break; case 's': log_set_type(LOG_TO_SYSLOG); @@ -1799,24 +781,24 @@ int main(int argc, char* argv[]) break; case 'd': - diag_mode = true; + usbmoded_set_diag_mode(true); break; case 'h': usbmoded_usage(); - exit(0); + exit(EXIT_SUCCESS); case 'r': - usbmoded_rescue_mode = true; + usbmoded_set_rescue_mode(true); break; #ifdef SYSTEMD case 'n': - systemd_notify = true; + usbmoded_systemd_notify = true; break; #endif case 'v': printf("USB mode daemon version: %s\n", VERSION); - exit(0); + exit(EXIT_SUCCESS); case 'm': usbmoded_set_cable_connection_delay(strtol(optarg, 0, 0)); @@ -1828,141 +810,55 @@ int main(int argc, char* argv[]) default: usbmoded_usage(); - exit(0); - } - } - - fprintf(stderr, "usb_moded %s starting\n", VERSION); - fflush(stderr); - - /* - - - - - - - - - - - - - - - - - - - * - * INITIALIZE - * - - - - - - - - - - - - - - - - - - - */ - - /* silence usbmoded_system() calls */ - if( log_get_type() != LOG_TO_STDERR && log_get_level() != LOG_DEBUG ) - { - if( !freopen("/dev/null", "a", stdout) ) { - log_err("can't redirect stdout: %m"); - } - if( !freopen("/dev/null", "a", stderr) ) { - log_err("can't redirect stderr: %m"); + exit(EXIT_FAILURE); } } +} +int main(int argc, char* argv[]) +{ + /* Library init calls that should be made before + * using library functionality. + */ #if !GLIB_CHECK_VERSION(2, 36, 0) g_type_init(); #endif #if !GLIB_CHECK_VERSION(2, 31, 0) g_thread_init(NULL); #endif - - /* Check if we are in mid-bootup */ - usbmoded_probe_init_done(); - - /* Must be the 1st libdbus call that is made */ dbus_threads_init_default(); - /* signal handling */ - if( !sigpipe_init() ) - { - log_crit("signal handler init failed\n"); - goto EXIT; - } - - if (usbmoded_rescue_mode && usbmoded_init_done_p()) - { - usbmoded_rescue_mode = false; - log_warning("init done passed; rescue mode ignored"); - } - - /* Connect to SystemBus */ - if( !umdbus_init_connection() ) - { - log_crit("dbus systembus connection failed\n"); - goto EXIT; - } - - /* Start DBus trackers that do async initialization - * so that initial method calls are on the way while - * we do initialization actions that might block. */ + /* - - - - - - - - - - - - - - - - - - - * + * OPTIONS + * - - - - - - - - - - - - - - - - - - - */ - /* DSME listener maintains in-user-mode state and is relevant - * only when MEEGOLOCK configure option has been chosen. */ -#ifdef MEEGOLOCK - if( !dsme_listener_start() ) { - log_crit("dsme tracking could not be started"); - goto EXIT; - } -#endif - /* Devicelock listener maintains devicelock state and is relevant - * only when MEEGOLOCK configure option has been chosen. */ -#ifdef MEEGOLOCK - if( !devicelock_start_listener() ) { - log_crit("devicelock tracking could not be started"); - goto EXIT; - } -#endif + /* Set logging defaults */ + log_init(); + log_set_name(basename(*argv)); - /* Set daemon config/state data to sane state */ - modesetting_init(); - usbmoded_init(); + /* Parse command line options */ + usbmoded_parse_options(argc, argv); - /* Allos making systemd control ipc */ - if( !systemd_control_start() ) { - log_crit("systemd control could not be started"); - goto EXIT; - } + fprintf(stderr, "usb_moded %s starting\n", VERSION); + fflush(stderr); - /* If usb-moded happens to crash, it could leave appsync processes - * running. To make sure things are in the order expected by usb-moded - * force stopping of appsync processes during usb-moded startup. - * - * The exception is: When usb-moded starts as a part of bootup. Then - * we can be relatively sure that usb-moded has not been running yet - * and therefore no appsync processes have been started and we can - * skip the blocking ipc required to stop the appsync systemd units. */ -#ifdef APP_SYNC - if( usbmoded_init_done_p() ) + /* Silence common_system() calls */ + if( log_get_type() != LOG_TO_STDERR && log_get_level() != LOG_DEBUG ) { - log_warning("usb-moded started after init-done; " - "forcing appsync stop"); - appsync_stop(true); + if( !freopen("/dev/null", "a", stdout) ) { + log_err("can't redirect stdout: %m"); + } + if( !freopen("/dev/null", "a", stderr) ) { + log_err("can't redirect stderr: %m"); + } } -#endif - /* Claim D-Bus service name before proceeding with things that - * could result in dbus signals from usb-moded interfaces to - * be broadcast */ - if( !umdbus_init_service() ) - { - log_crit("usb-moded dbus service init failed\n"); - goto EXIT; - } + /* - - - - - - - - - - - - - - - - - - - * + * INITIALIZE + * - - - - - - - - - - - - - - - - - - - */ - /* Initialize udev listener. Can cause mode changes. - * - * Failing here is allowed if '--fallback' commandline option is used. */ - if( !umudev_init() && !hw_fallback ) - { - log_crit("hwal init failed\n"); + if( !usbmoded_init() ) goto EXIT; - } - - /* Broadcast supported / hidden modes */ - // TODO: should this happen before umudev_init()? - usbmoded_send_supported_modes_signal(); - usbmoded_send_available_modes_signal(); - usbmoded_send_hidden_modes_signal(); - usbmoded_send_whitelisted_modes_signal(); - - /* Act on '--fallback' commandline option */ - if(hw_fallback) - { - log_warning("Forcing USB state to connected always. ASK mode non functional!\n"); - /* Since there will be no disconnect signals coming from hw the state should not change */ - usbmoded_set_cable_state(CABLE_STATE_PC_CONNECTED); - } /* - - - - - - - - - - - - - - - - - - - * * EXECUTE @@ -1970,72 +866,43 @@ int main(int argc, char* argv[]) /* Tell systemd that we have started up */ #ifdef SYSTEMD - if( systemd_notify ) - { - log_debug("notifying systemd\n"); + if( usbmoded_systemd_notify ) { + log_debug("notifying systemd"); sd_notify(0, "READY=1"); } #endif /* init succesful, run main loop */ - usb_moded_exitcode = EXIT_SUCCESS; - usb_moded_mainloop = g_main_loop_new(NULL, FALSE); + usbmoded_exitcode = EXIT_SUCCESS; + usbmoded_mainloop = g_main_loop_new(NULL, FALSE); log_debug("enter usb-moded mainloop"); - g_main_loop_run(usb_moded_mainloop); + g_main_loop_run(usbmoded_mainloop); log_debug("leave usb-moded mainloop"); - g_main_loop_unref(usb_moded_mainloop), - usb_moded_mainloop = 0; + g_main_loop_unref(usbmoded_mainloop), + usbmoded_mainloop = 0; /* - - - - - - - - - - - - - - - - - - - * * CLEANUP * - - - - - - - - - - - - - - - - - - - */ EXIT: - /* Detach from SystemBus. Components that hold reference to the - * shared bus connection can still perform cleanup tasks, but new - * references can't be obtained anymore and usb-moded method call - * processing no longer occurs. */ - umdbus_cleanup(); - - /* Stop appsync processes that have been started by usb-moded */ -#ifdef APP_SYNC - appsync_stop(false); -#endif - - /* Deny making systemd control ipc */ - systemd_control_stop(); - - /* Stop tracking devicelock status */ -#ifdef MEEGOLOCK - devicelock_stop_listener(); -#endif - /* Stop tracking device state */ -#ifdef MEEGOLOCK - dsme_listener_stop(); -#endif - - /* Stop udev listener */ - umudev_quit(); - - /* Release dynamically allocated config/state data */ usbmoded_cleanup(); - modesetting_quit(); - /* Detach from SessionBus connection used for APP_SYNC_DBUS. - * - * Can be handled separately from SystemBus side wind down. */ -#ifdef APP_SYNC -# ifdef APP_SYNC_DBUS - dbusappsync_cleanup(); -# endif + /* Memory leak debugging - instruct libdbus to flush resources. */ +#if 0 + dbus_shutdown(); #endif + /* - - - - - - - - - - - - - - - - - - - * + * EXIT + * - - - - - - - - - - - - - - - - - - - */ + /* Must be done just before exit to make sure no more wakelocks * are taken and left behind on exit path */ usbmoded_allow_suspend(); log_debug("usb-moded return from main, with exit code %d", - usb_moded_exitcode); - return usb_moded_exitcode; + usbmoded_exitcode); + return usbmoded_exitcode; } diff --git a/src/usb_moded.h b/src/usb_moded.h index dcb9e28..6ab0094 100644 --- a/src/usb_moded.h +++ b/src/usb_moded.h @@ -27,26 +27,15 @@ # define USB_MODED_H_ # ifdef STATIC_CONFIG -# include "../config-static.h" +# include "../config-static.h" // NOTRIM # else -# include "../config.h" +# include "../config.h" // NOTRIM # endif -# include # include -# include # include -# include -# include -# include -# include -# include - -# include -# include - -# include "usb_moded-dyn-config.h" +# include /* ========================================================================= * * Constants @@ -67,97 +56,28 @@ # define USB_MODED_SUSPEND_DELAY_MAXIMUM_MS \ (USB_MODED_SUSPEND_DELAY_DEFAULT_MS * 2) -/* ========================================================================= * - * Types - * ========================================================================= */ - -typedef enum { - CABLE_STATE_UNKNOWN, - CABLE_STATE_DISCONNECTED, - CABLE_STATE_CHARGER_CONNECTED, - CABLE_STATE_PC_CONNECTED, - CABLE_STATE_NUMOF -} cable_state_t; - -/** Mode list types - */ -typedef enum mode_list_type_t { - /** All configured modes */ - SUPPORTED_MODES_LIST, - /** Configured modes that can be activated */ - AVAILABLE_MODES_LIST -} mode_list_type_t; - -/* ========================================================================= * - * Data - * ========================================================================= */ - -/** PC connection delay (FIXME: is defunct now) - * - * Slow cable insert / similar physical issues can lead to a charger - * getting initially recognized as a pc connection. This defines how - * long we should wait and see if pc connection gets corrected to a - * charger kind. - */ -extern int usbmoded_cable_connection_delay; - -/** Rescue mode flag - * - * When enabled, usb-moded allows developer_mode etc when device is - * booted up with cable connected without requiring device unlock. - * Which can be useful if UI for some reason does not come up. - */ -extern bool usbmoded_rescue_mode; - /* ========================================================================= * * Functions * ========================================================================= */ -/* -- cable -- */ - -const char *cable_state_repr(cable_state_t state); - /* -- usbmoded -- */ -void usbmoded_rethink_usb_charging_fallback(void); -const char *usbmoded_get_external_mode (void); -const char *usbmoded_get_usb_mode (void); -void usbmoded_set_usb_mode (const char *internal_mode); -void usbmoded_select_usb_mode (void); -void usbmoded_set_cable_state (cable_state_t cable_state); -cable_state_t usbmoded_get_cable_state (void); -bool usbmoded_get_connection_state (void); -int usbmoded_valid_mode (const char *mode); -gchar *usbmoded_get_mode_list (mode_list_type_t type); -const char *usbmoded_get_usb_module (void); -bool usbmoded_set_usb_module (const char *module); -struct mode_list_elem *usbmoded_get_usb_mode_data (void); -void usbmoded_set_usb_mode_data (struct mode_list_elem *data); -void usbmoded_send_supported_modes_signal (void); -void usbmoded_send_available_modes_signal (void); -void usbmoded_send_hidden_modes_signal (void); -void usbmoded_send_whitelisted_modes_signal(void); -void usbmoded_acquire_wakelock (const char *wakelock_name); -void usbmoded_release_wakelock (const char *wakelock_name); -void usbmoded_allow_suspend (void); -void usbmoded_delay_suspend (void); -bool usbmoded_can_export (void); -bool usbmoded_init_done_p (void); -void usbmoded_set_init_done (bool reached); -void usbmoded_probe_init_done (void); -void usbmoded_exit_mainloop (int exitcode); -int usbmoded_system_ (const char *file, int line, const char *func, const char *command); -FILE *usbmoded_popen_ (const char *file, int line, const char *func, const char *command, const char *type); -void usbmoded_usleep_ (const char *file, int line, const char *func, useconds_t usec); - -/* ========================================================================= * - * Macros - * ========================================================================= */ - -# define usbmoded_system(command) usbmoded_system_(__FILE__,__LINE__,__FUNCTION__,(command)) -# define usbmoded_popen(command, type) usbmoded_popen_(__FILE__,__LINE__,__FUNCTION__,(command),(type)) -# define usbmoded_usleep(usec) usbmoded_usleep_(__FILE__,__LINE__,__FUNCTION__,(usec)) -# define usbmoded_msleep(msec) usbmoded_usleep_(__FILE__,__LINE__,__FUNCTION__,(msec)*1000) -# define usbmoded_sleep(sec) usbmoded_usleep_(__FILE__,__LINE__,__FUNCTION__,(sec)*1000000) +GList *usbmoded_get_modelist (void); +void usbmoded_load_modelist (void); +void usbmoded_free_modelist (void); +bool usbmoded_get_rescue_mode (void); +void usbmoded_set_rescue_mode (bool rescue_mode); +bool usbmoded_get_diag_mode (void); +void usbmoded_set_diag_mode (bool diag_mode); +void usbmoded_set_cable_connection_delay(int delay_ms); +int usbmoded_get_cable_connection_delay(void); +void usbmoded_allow_suspend (void); +void usbmoded_delay_suspend (void); +bool usbmoded_init_done_p (void); +void usbmoded_set_init_done (bool reached); +void usbmoded_probe_init_done (void); +bool usbmoded_can_export (void); +void usbmoded_exit_mainloop (int exitcode); +void usbmoded_handle_signal (int signum); #endif /* USB_MODED_H_ */ diff --git a/utils/udev-search.c b/utils/udev-search.c index 8fca6a6..4fe5d71 100644 --- a/utils/udev-search.c +++ b/utils/udev-search.c @@ -30,12 +30,8 @@ #include #include -#include -#include #include -#include - #include /* ========================================================================= * @@ -87,7 +83,7 @@ static int check_device_is_usb_power_supply(const char *syspath) printf("type property found\n"); } - return(score); + return score; } int main (int argc, char **argv) @@ -101,12 +97,12 @@ int main (int argc, char **argv) const char *udev_name; int ret = 0, score = 0; - typedef struct power_device { + typedef struct power_device_t { const char *syspath; int score; - } power_device; + } power_device_t; - struct power_device power_dev; + power_device_t power_dev; power_dev.score = 0;