mirror of
https://github.com/systemd/systemd.git
synced 2025-03-21 02:50:18 +03:00
Merge gregkh@ehlo.org:/home/kay/public_html/pub/scm/linux/hotplug/udev-kay
This commit is contained in:
commit
972d318a31
73
Makefile
73
Makefile
@ -44,11 +44,13 @@ V=false
|
||||
ROOT = udev
|
||||
DAEMON = udevd
|
||||
SENDER = udevsend
|
||||
INITSENDER = udevinitsend
|
||||
RECORDER = udeveventrecorder
|
||||
CONTROL = udevcontrol
|
||||
INFO = udevinfo
|
||||
TESTER = udevtest
|
||||
STARTER = udevstart
|
||||
VERSION = 058
|
||||
INSTALL_DIR = /usr/local/bin
|
||||
RELEASE_NAME = $(ROOT)-$(VERSION)
|
||||
LOCAL_CFG_DIR = etc/udev
|
||||
DESTDIR =
|
||||
@ -61,10 +63,7 @@ etcdir = ${prefix}/etc
|
||||
sbindir = ${exec_prefix}/sbin
|
||||
usrbindir = ${exec_prefix}/usr/bin
|
||||
mandir = ${prefix}/usr/share/man
|
||||
hotplugdir = ${etcdir}/hotplug.d/default
|
||||
configdir = ${etcdir}/udev
|
||||
initdir = ${etcdir}/init.d
|
||||
dev_ddir = ${etcdir}/dev.d
|
||||
srcdir = .
|
||||
|
||||
INSTALL = /usr/bin/install -c
|
||||
@ -142,7 +141,6 @@ UDEV_OBJS = \
|
||||
udev_remove.o \
|
||||
udev_sysfs.o \
|
||||
udev_db.o \
|
||||
udev_multiplex.o \
|
||||
udev_rules.o \
|
||||
udev_rules_parse.o \
|
||||
udev_libc_wrapper.o
|
||||
@ -178,7 +176,6 @@ ifeq ($(strip $(USE_KLIBC)),true)
|
||||
KLCC = $(KLIBC_INSTALL)/bin/klcc
|
||||
CC = $(KLCC)
|
||||
LD = $(KLCC)
|
||||
LDFLAGS += -static
|
||||
else
|
||||
CFLAGS += -Wshadow -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations
|
||||
endif
|
||||
@ -205,7 +202,7 @@ endif
|
||||
# config files automatically generated
|
||||
GEN_CONFIGS = $(LOCAL_CFG_DIR)/udev.conf
|
||||
|
||||
all: $(ROOT) $(SENDER) $(DAEMON) $(INFO) $(TESTER) $(STARTER) $(GEN_CONFIGS) $(KLCC)
|
||||
all: $(ROOT) $(SENDER) $(INITSENDER) $(RECORDER) $(CONTROL) $(DAEMON) $(INFO) $(TESTER) $(STARTER) $(GEN_CONFIGS) $(KLCC)
|
||||
@extras="$(EXTRAS)" ; for target in $$extras ; do \
|
||||
echo $$target ; \
|
||||
$(MAKE) prefix=$(prefix) \
|
||||
@ -250,8 +247,8 @@ udev_version.h:
|
||||
@echo \#define UDEV_CONFIG_DIR \"$(configdir)\" >> $@
|
||||
@echo \#define UDEV_CONFIG_FILE \"$(configdir)/udev.conf\" >> $@
|
||||
@echo \#define UDEV_RULES_FILE \"$(configdir)/rules.d\" >> $@
|
||||
@echo \#define UDEV_BIN \"$(DESTDIR)$(sbindir)/udev\" >> $@
|
||||
@echo \#define UDEVD_BIN \"$(DESTDIR)$(sbindir)/udevd\" >> $@
|
||||
@echo \#define UDEV_BIN \"$(sbindir)/udev\" >> $@
|
||||
@echo \#define UDEVD_BIN \"$(sbindir)/udevd\" >> $@
|
||||
|
||||
# Rules on how to create the generated config files
|
||||
$(LOCAL_CFG_DIR)/udev.conf:
|
||||
@ -263,15 +260,18 @@ GEN_MANPAGESIN = udev.8.in
|
||||
$(GEN_MANPAGES): $(GEN_MANPAGESIN)
|
||||
sed -e "s:@udevdir@:$(udevdir):" < $@.in > $@
|
||||
|
||||
$(UDEV_OBJS): $(GEN_HEADERS) $(HOST_PROGS) $(KLCC)
|
||||
$(SYSFS_OBJS): $(HOST_PROGS) $(KLCC)
|
||||
$(OBJS): $(GEN_HEADERS) $(HOST_PROGS) $(KLCC)
|
||||
$(ROOT).o: $(GEN_HEADERS) $(HOST_PROGS) $(KLCC)
|
||||
$(TESTER).o: $(GEN_HEADERS) $(HOST_PROGS) $(KLCC)
|
||||
$(INFO).o: $(GEN_HEADERS) $(HOST_PROGS) $(KLCC)
|
||||
$(DAEMON).o: $(GEN_HEADERS) $(HOST_PROGS) $(KLCC)
|
||||
$(SENDER).o: $(GEN_HEADERS) $(HOST_PROGS) $(KLCC)
|
||||
$(STARTER).o: $(GEN_HEADERS) $(HOST_PROGS) $(KLCC)
|
||||
$(UDEV_OBJS): $(HEADERS) $(GEN_HEADERS) $(HOST_PROGS) $(KLCC)
|
||||
$(SYSFS_OBJS): $(HEADERS) $(HOST_PROGS) $(KLCC)
|
||||
$(OBJS): $(HEADERS) $(GEN_HEADERS) $(HOST_PROGS) $(KLCC)
|
||||
$(ROOT).o: $(HEADERS) $(GEN_HEADERS) $(HOST_PROGS) $(KLCC)
|
||||
$(TESTER).o: $(HEADERS) $(GEN_HEADERS) $(HOST_PROGS) $(KLCC)
|
||||
$(INFO).o: $(HEADERS) $(GEN_HEADERS) $(HOST_PROGS) $(KLCC)
|
||||
$(DAEMON).o: $(HEADERS) $(GEN_HEADERS) $(HOST_PROGS) $(KLCC)
|
||||
$(SENDER).o: $(HEADERS) $(GEN_HEADERS) $(HOST_PROGS) $(KLCC)
|
||||
$(INITSENDER).o: $(GEN_HEADERS) $(HOST_PROGS) $(KLCC)
|
||||
$(RECORDER).o: $(GEN_HEADERS) $(HOST_PROGS) $(KLCC)
|
||||
$(CONTROL).o: $(HEADERS) $( $(HEADERS)GEN_HEADERS) $(HOST_PROGS) $(KLCC)
|
||||
$(STARTER).o: $(HEADERS) $(GEN_HEADERS) $(HOST_PROGS) $(KLCC)
|
||||
|
||||
$(ROOT): $(KLCC) $(ROOT).o $(OBJS) $(HEADERS) $(GEN_MANPAGES)
|
||||
$(QUIET) $(LD) $(LDFLAGS) -o $@ $(ROOT).o $(OBJS) $(LIB_OBJS)
|
||||
@ -293,6 +293,18 @@ $(SENDER): $(KLCC) $(SENDER).o $(OBJS) udevd.h
|
||||
$(QUIET) $(LD) $(LDFLAGS) -o $@ $(SENDER).o $(OBJS) $(LIB_OBJS)
|
||||
$(QUIET) $(STRIPCMD) $@
|
||||
|
||||
$(INITSENDER): $(KLCC) $(INITSENDER).o $(OBJS) udevd.h
|
||||
$(QUIET) $(LD) $(LDFLAGS) -o $@ $(INITSENDER).o $(OBJS) $(LIB_OBJS)
|
||||
$(QUIET) $(STRIPCMD) $@
|
||||
|
||||
$(RECORDER): $(KLCC) $(RECORDER).o $(OBJS) udevd.h
|
||||
$(QUIET) $(LD) $(LDFLAGS) -o $@ $(RECORDER).o $(OBJS) $(LIB_OBJS)
|
||||
$(QUIET) $(STRIPCMD) $@
|
||||
|
||||
$(CONTROL): $(KLCC) $(CONTROL).o $(OBJS) udevd.h
|
||||
$(QUIET) $(LD) $(LDFLAGS) -o $@ $(CONTROL).o $(OBJS) $(LIB_OBJS)
|
||||
$(QUIET) $(STRIPCMD) $@
|
||||
|
||||
$(STARTER): $(KLCC) $(STARTER).o $(OBJS)
|
||||
$(QUIET) $(LD) $(LDFLAGS) -o $@ $(STARTER).o $(OBJS) $(LIB_OBJS)
|
||||
$(QUIET) $(STRIPCMD) $@
|
||||
@ -304,7 +316,7 @@ clean:
|
||||
-find . \( -not -type d \) -and \( -name '*~' -o -name '*.[oas]' \) -type f -print \
|
||||
| xargs rm -f
|
||||
-rm -f core $(ROOT) $(GEN_HEADERS) $(GEN_CONFIGS) $(GEN_MANPAGES) $(INFO) $(DAEMON) \
|
||||
$(SENDER) $(TESTER) $(STARTER)
|
||||
$(SENDER) $(INITSENDER) $(RECORDER) $(CONTROL) $(TESTER) $(STARTER)
|
||||
-rm -f ccdv
|
||||
$(MAKE) -C klibc SUBDIRS=klibc clean
|
||||
@extras="$(EXTRAS)" ; for target in $$extras ; do \
|
||||
@ -332,16 +344,6 @@ install-config:
|
||||
$(INSTALL_DATA) $(LOCAL_CFG_DIR)/udev.rules $(DESTDIR)$(configdir)/rules.d/50-udev.rules; \
|
||||
fi
|
||||
|
||||
install-dev.d:
|
||||
$(INSTALL) -d $(DESTDIR)$(dev_ddir)/default
|
||||
$(INSTALL_PROGRAM) -D etc/dev.d/net/hotplug.dev $(DESTDIR)$(dev_ddir)/net/hotplug.dev
|
||||
|
||||
uninstall-dev.d:
|
||||
- rm $(dev_ddir)/net/hotplug.dev
|
||||
- rmdir $(dev_ddir)/net
|
||||
- rmdir $(dev_ddir)/default
|
||||
- rmdir $(dev_ddir)
|
||||
|
||||
install-man:
|
||||
$(INSTALL_DATA) -D udev.8 $(DESTDIR)$(mandir)/man8/udev.8
|
||||
$(INSTALL_DATA) -D udevinfo.8 $(DESTDIR)$(mandir)/man8/udevinfo.8
|
||||
@ -358,18 +360,18 @@ uninstall-man:
|
||||
- rm $(mandir)/man8/udevd.8
|
||||
- rm $(mandir)/man8/udevsend.8
|
||||
|
||||
install: install-config install-man install-dev.d all
|
||||
install: install-config install-man all
|
||||
$(INSTALL) -d $(DESTDIR)$(udevdir)
|
||||
$(INSTALL) -d $(DESTDIR)$(hotplugdir)
|
||||
$(INSTALL_PROGRAM) -D $(ROOT) $(DESTDIR)$(sbindir)/$(ROOT)
|
||||
$(INSTALL_PROGRAM) -D $(DAEMON) $(DESTDIR)$(sbindir)/$(DAEMON)
|
||||
$(INSTALL_PROGRAM) -D $(SENDER) $(DESTDIR)$(sbindir)/$(SENDER)
|
||||
$(INSTALL_PROGRAM) -D $(CONTROL) $(DESTDIR)$(sbindir)/$(CONTROL)
|
||||
$(INSTALL_PROGRAM) -D $(INFO) $(DESTDIR)$(usrbindir)/$(INFO)
|
||||
$(INSTALL_PROGRAM) -D $(TESTER) $(DESTDIR)$(usrbindir)/$(TESTER)
|
||||
$(INSTALL_PROGRAM) -D $(STARTER) $(DESTDIR)$(sbindir)/$(STARTER)
|
||||
- ln -f -s $(sbindir)/$(SENDER) $(DESTDIR)$(hotplugdir)/10-udev.hotplug
|
||||
ifndef DESTDIR
|
||||
- killall $(DAEMON)
|
||||
- $(sbindir)/$(DAEMON) --daemon
|
||||
- rm -rf $(udevdb)
|
||||
endif
|
||||
@extras="$(EXTRAS)" ; for target in $$extras ; do \
|
||||
@ -378,8 +380,7 @@ endif
|
||||
-C $$target $@ ; \
|
||||
done ; \
|
||||
|
||||
uninstall: uninstall-man uninstall-dev.d
|
||||
- rm $(hotplugdir)/10-udev.hotplug
|
||||
uninstall: uninstall-man
|
||||
- rm $(configdir)/rules.d/50-udev.rules
|
||||
- rm $(configdir)/udev.conf
|
||||
- rmdir $(configdir)/rules.d
|
||||
@ -387,10 +388,12 @@ uninstall: uninstall-man uninstall-dev.d
|
||||
- rm $(sbindir)/$(ROOT)
|
||||
- rm $(sbindir)/$(DAEMON)
|
||||
- rm $(sbindir)/$(SENDER)
|
||||
- rm $(sbindir)/$(INITSENDER)
|
||||
- rm $(sbindir)/$(RECORDER)
|
||||
- rm $(sbindir)/$(CONTROL)
|
||||
- rm $(sbindir)/$(STARTER)
|
||||
- rm $(usrbindir)/$(INFO)
|
||||
- rm $(usrbindir)/$(TESTER)
|
||||
- rmdir $(hotplugdir)
|
||||
- rm -rf $(udevdb)
|
||||
- rmdir $(udevdir)
|
||||
- killall $(DAEMON)
|
||||
|
3
README
3
README
@ -10,8 +10,7 @@ To use:
|
||||
|
||||
- Your 2.6 kernel must have had CONFIG_HOTPLUG enabled when it was built.
|
||||
|
||||
- Make sure sysfs is mounted. udev will figure out where sysfs is mounted, but
|
||||
the traditional place for it is at /sys. You can mount it by hand by running:
|
||||
- Make sure sysfs is mounted at /sys. You can mount it by running:
|
||||
mount -t sysfs none /sys
|
||||
|
||||
- Make sure you have the latest version of the linux-hotplug scripts. They are
|
||||
|
@ -1,5 +1,4 @@
|
||||
# udev.conf
|
||||
#
|
||||
|
||||
# Where in the filesystem to place the device nodes
|
||||
udev_root="@udevdir@"
|
||||
|
@ -5,43 +5,42 @@
|
||||
#
|
||||
|
||||
# if this is a ide cdrom, name it the default name, and create a symlink to cdrom
|
||||
BUS="ide", KERNEL="*[!0-9]", PROGRAM="/bin/cat /proc/ide/%k/media", RESULT="cdrom", NAME="%k", SYMLINK="cdrom"
|
||||
|
||||
# create a symlink named after the device map name
|
||||
# note devmap_name comes with extras/multipath
|
||||
KERNEL="dm-[0-9]*", PROGRAM="/sbin/devmap_name %M %m", NAME="%k", SYMLINK="%c"
|
||||
BUS=="ide", KERNEL=="*[!0-9]", PROGRAM="/bin/cat /proc/ide/%k/media", RESULT="cdrom", NAME="%k", SYMLINK+="cdrom"
|
||||
|
||||
# DRI devices always go into a subdirectory (as per the LSB spec)
|
||||
KERNEL="card*", NAME="dri/card%n"
|
||||
KERNEL=="card*", NAME="dri/card%n"
|
||||
|
||||
# alsa devices
|
||||
KERNEL="controlC[0-9]*", NAME="snd/%k"
|
||||
KERNEL="hw[CD0-9]*", NAME="snd/%k"
|
||||
KERNEL="pcm[CD0-9cp]*", NAME="snd/%k"
|
||||
KERNEL="midiC[D0-9]*", NAME="snd/%k"
|
||||
KERNEL="timer", NAME="snd/%k"
|
||||
KERNEL="seq", NAME="snd/%k"
|
||||
KERNEL=="controlC[0-9]*", NAME="snd/%k"
|
||||
KERNEL=="hw[CD0-9]*", NAME="snd/%k"
|
||||
KERNEL=="pcm[CD0-9cp]*", NAME="snd/%k"
|
||||
KERNEL=="midiC[D0-9]*", NAME="snd/%k"
|
||||
KERNEL=="timer", NAME="snd/%k"
|
||||
KERNEL=="seq", NAME="snd/%k"
|
||||
|
||||
# input devices
|
||||
KERNEL="mice", NAME="input/%k"
|
||||
KERNEL="mouse*", NAME="input/%k"
|
||||
KERNEL="event*", NAME="input/%k"
|
||||
KERNEL="js*", NAME="input/%k"
|
||||
KERNEL="ts*", NAME="input/%k"
|
||||
KERNEL=="mice", NAME="input/%k"
|
||||
KERNEL=="mouse*", NAME="input/%k"
|
||||
KERNEL=="event*", NAME="input/%k"
|
||||
KERNEL=="js*", NAME="input/%k"
|
||||
KERNEL=="ts*", NAME="input/%k"
|
||||
|
||||
# USB devices
|
||||
KERNEL="hiddev*", NAME="usb/%k"
|
||||
KERNEL="auer*", NAME="usb/%k"
|
||||
KERNEL="legousbtower*", NAME="usb/%k"
|
||||
KERNEL="dabusb*", NAME="usb/%k"
|
||||
BUS="usb", KERNEL="lp[0-9]*", NAME="usb/%k"
|
||||
KERNEL=="hiddev*", NAME="usb/%k"
|
||||
KERNEL=="auer*", NAME="usb/%k"
|
||||
KERNEL=="legousbtower*", NAME="usb/%k"
|
||||
KERNEL=="dabusb*", NAME="usb/%k"
|
||||
BUS=="usb", KERNEL=="lp[0-9]*", NAME="usb/%k"
|
||||
|
||||
# CAPI devices
|
||||
KERNEL="capi", NAME="capi20", SYMLINK="isdn/capi20"
|
||||
KERNEL="capi*", NAME="capi/%n"
|
||||
KERNEL=="capi", NAME="capi20", SYMLINK+="isdn/capi20"
|
||||
KERNEL=="capi*", NAME="capi/%n"
|
||||
|
||||
# Network devices
|
||||
KERNEL="tun", NAME="net/%k"
|
||||
KERNEL=="tun", NAME="net/%k"
|
||||
|
||||
# raw devices
|
||||
KERNEL="raw[0-9]*", NAME="raw/%k"
|
||||
KERNEL=="raw[0-9]*", NAME="raw/%k"
|
||||
|
||||
# emulate dev.d/
|
||||
RUN="/sbin/udev_run_devd"
|
||||
|
@ -9,64 +9,55 @@
|
||||
#
|
||||
|
||||
# Looking for scsi bus id 42:0:0:1
|
||||
BUS="scsi", PROGRAM="/bin/echo -n test-%b", RESULT="test-42:0:0:1", NAME="%c"
|
||||
BUS=="scsi", PROGRAM="/bin/echo -n test-%b", RESULT=="test-42:0:0:1", NAME="%c"
|
||||
|
||||
# A usb camera.
|
||||
BUS="usb", SYSFS{vendor}="FUJIFILM", SYSFS{model}="M100", NAME="camera%n"
|
||||
BUS=="usb", SYSFS{vendor}=="FUJIFILM", SYSFS{model}=="M100", NAME="camera%n"
|
||||
|
||||
# USB Epson printer to be called lp_epson
|
||||
BUS="usb", SYSFS_serial="HXOLL0012202323480", NAME="lp_epson"
|
||||
BUS=="usb", SYSFS_serial=="HXOLL0012202323480", NAME="lp_epson"
|
||||
|
||||
# USB HP printer to be called lp_hp
|
||||
BUS="usb", SYSFS{serial}="W09090207101241330", NAME="lp_hp"
|
||||
BUS=="usb", SYSFS{serial}=="W09090207101241330", NAME="lp_hp"
|
||||
|
||||
# sound card with PCI bus id 00:0b.0 to be the first sound card
|
||||
BUS="pci", ID="00:0b.0", NAME="dsp"
|
||||
BUS=="pci", ID=="00:0b.0", NAME="dsp"
|
||||
|
||||
# sound card with PCI bus id 00:07.1 to be the second sound card
|
||||
BUS="pci", ID="00:07.1", NAME="dsp1"
|
||||
|
||||
# USB mouse plugged into the third port of the first hub to be called mouse0
|
||||
BUS="usb", PLACE="1.3", NAME="mouse0"
|
||||
|
||||
# USB tablet plugged into the third port of the second hub to be called mouse1
|
||||
BUS="usb", PLACE="2.3", NAME="mouse1"
|
||||
BUS="usb", PLACE="2.4", NAME="mouse2"
|
||||
BUS=="pci", ID=="00:07.1", NAME="dsp1"
|
||||
|
||||
# ttyUSB1 should always be called visor
|
||||
KERNEL="ttyUSB1", NAME="visor"
|
||||
KERNEL="ttyUSB0", NAME="pl2303"
|
||||
KERNEL=="ttyUSB1", NAME="visor"
|
||||
KERNEL=="ttyUSB0", NAME="pl2303"
|
||||
|
||||
# a devfs like way to name some tty devices
|
||||
KERNEL="ttyS*", NAME="tts/%n"
|
||||
KERNEL="tty*", NAME="vc/%n"
|
||||
KERNEL=="ttyS*", NAME="tts/%n"
|
||||
KERNEL=="tty*", NAME="vc/%n"
|
||||
|
||||
# if this is a ide cdrom, name it the default name, and create a symlink to cdrom
|
||||
BUS="ide", KERNEL="*[!0-9]", PROGRAM="/bin/cat /proc/ide/%k/media", RESULT="cdrom", NAME="%k", SYMLINK="cdrom"
|
||||
|
||||
# create a symlink named after the device map name
|
||||
# note devmap_name comes with extras/multipath
|
||||
KERNEL="dm-[0-9]*", PROGRAM="/sbin/devmap_name %M %m", NAME="%k", SYMLINK="%c"
|
||||
BUS=="ide", KERNEL=="*[!0-9]", PROGRAM="/bin/cat /proc/ide/%k/media", RESULT=="cdrom", NAME="%k", SYMLINK+="cdrom"
|
||||
|
||||
# DRI devices always go into a subdirectory (as per the LSB spec)
|
||||
KERNEL="card*", NAME="dri/card%n"
|
||||
KERNEL=="card*", NAME="dri/card%n"
|
||||
|
||||
# create all 15 partitions of a USB flash card reader
|
||||
# note the trailing spaces in the attribute, use udevinfo(8) to examine your device
|
||||
BUS="scsi", SYSFS{model}="CF/MD ", NAME{all_partitions}="compactflash"
|
||||
BUS=="scsi", SYSFS{model}=="CF/MD", NAME{all_partitions}="compactflash"
|
||||
|
||||
# alsa devices
|
||||
KERNEL="controlC[0-9]*", NAME="snd/%k"
|
||||
KERNEL="hw[CD0-9]*", NAME="snd/%k"
|
||||
KERNEL="pcm[CD0-9cp]*", NAME="snd/%k"
|
||||
KERNEL="midi[CD0-9]*", NAME="snd/%k"
|
||||
KERNEL="timer", NAME="snd/%k"
|
||||
KERNEL="seq", NAME="snd/%k"
|
||||
KERNEL=="controlC[0-9]*", NAME="snd/%k"
|
||||
KERNEL=="hw[CD0-9]*", NAME="snd/%k"
|
||||
KERNEL=="pcm[CD0-9cp]*", NAME="snd/%k"
|
||||
KERNEL=="midi[CD0-9]*", NAME="snd/%k"
|
||||
KERNEL=="timer", NAME="snd/%k"
|
||||
KERNEL=="seq", NAME="snd/%k"
|
||||
|
||||
# input devices
|
||||
KERNEL="mice", NAME="input/%k"
|
||||
KERNEL="mouse*", NAME="input/%k"
|
||||
KERNEL="event*", NAME="input/%k"
|
||||
KERNEL="js*", NAME="input/%k"
|
||||
KERNEL="ts*", NAME="input/%k"
|
||||
KERNEL=="mice", NAME="input/%k"
|
||||
KERNEL=="mouse*", NAME="input/%k"
|
||||
KERNEL=="event*", NAME="input/%k"
|
||||
KERNEL=="js*", NAME="input/%k"
|
||||
KERNEL=="ts*", NAME="input/%k"
|
||||
|
||||
# emulate dev.d/
|
||||
RUN="/sbin/udev_run_devd"
|
||||
|
||||
|
55
extras/run_directory/Makefile
Normal file
55
extras/run_directory/Makefile
Normal file
@ -0,0 +1,55 @@
|
||||
# Makefile for udev_volume_id
|
||||
#
|
||||
# Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; version 2 of the License.
|
||||
#
|
||||
|
||||
DEVD = udev_run_devd
|
||||
HOTPLUGD = udev_run_hotplugd
|
||||
|
||||
all: $(DEVD) $(HOTPLUGD)
|
||||
|
||||
prefix =
|
||||
exec_prefix = ${prefix}
|
||||
etcdir = ${prefix}/etc
|
||||
sbindir = ${exec_prefix}/sbin
|
||||
usrbindir = ${exec_prefix}/usr/bin
|
||||
usrsbindir = ${exec_prefix}/usr/sbin
|
||||
mandir = ${prefix}/usr/share/man
|
||||
devddir = ${etcdir}/dev.d/default
|
||||
configdir = ${etcdir}/udev/
|
||||
initdir = ${etcdir}/init.d/
|
||||
srcdir = .
|
||||
|
||||
INSTALL = /usr/bin/install -c
|
||||
INSTALL_PROGRAM = ${INSTALL}
|
||||
INSTALL_DATA = ${INSTALL} -m 644
|
||||
INSTALL_SCRIPT = ${INSTALL_PROGRAM}
|
||||
|
||||
override CFLAGS+=-D_FILE_OFFSET_BITS=64
|
||||
|
||||
OBJS = ../../udev.a ../../libsysfs/sysfs.a
|
||||
|
||||
.c.o:
|
||||
$(QUIET) $(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
$(DEVD): $(HEADERS) $(DEVD).o run_directory.o
|
||||
$(QUIET) $(LD) $(LDFLAGS) -o $(DEVD) $(DEVD).o run_directory.o $(OBJS)
|
||||
|
||||
$(HOTPLUGD): $(HEADERS) $(HOTPLUGD).o run_directory.o
|
||||
$(QUIET) $(LD) $(LDFLAGS) -o $(HOTPLUGD) $(HOTPLUGD).o run_directory.o $(OBJS)
|
||||
|
||||
clean:
|
||||
rm -f $(DEVD) $(HOTPLUGD) run_directory.o
|
||||
|
||||
spotless: clean
|
||||
|
||||
install: all
|
||||
$(INSTALL_PROGRAM) $(DEVD) $(DESTDIR)$(sbindir)/$(DEVD)
|
||||
$(INSTALL_PROGRAM) $(HOTPLUGD) $(DESTDIR)$(sbindir)/$(HOTPLUGD)
|
||||
|
||||
uninstall:
|
||||
- rm $(DESTDIR)$(sbindir)/$(DEVD)
|
79
extras/run_directory/run_directory.c
Normal file
79
extras/run_directory/run_directory.c
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* udev_run_directory.c - directory multiplexer
|
||||
*
|
||||
* Copyright (C) 2005 Kay Sievers <kay@vrfy.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation version 2 of the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "../../udev_utils.h"
|
||||
#include "../../list.h"
|
||||
#include "../../logging.h"
|
||||
|
||||
int run_directory(const char *dir, const char *suffix, const char *subsystem);
|
||||
|
||||
static int run_program(const char *filename, const char *subsystem)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
dbg("running %s", filename);
|
||||
pid = fork();
|
||||
switch (pid) {
|
||||
case 0:
|
||||
/* child */
|
||||
execl(filename, filename, subsystem, NULL);
|
||||
dbg("exec of child failed");
|
||||
_exit(1);
|
||||
case -1:
|
||||
dbg("fork of child failed");
|
||||
break;
|
||||
return -1;
|
||||
default:
|
||||
waitpid(pid, NULL, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int run_directory(const char *dir, const char *suffix, const char *subsystem)
|
||||
{
|
||||
char dirname[NAME_SIZE];
|
||||
struct name_entry *name_loop, *name_tmp;
|
||||
LIST_HEAD(name_list);
|
||||
|
||||
if (subsystem) {
|
||||
snprintf(dirname, sizeof(dirname), "%s/%s", dir, subsystem);
|
||||
dirname[sizeof(dirname)-1] = '\0';
|
||||
dbg("looking at '%s'", dirname);
|
||||
add_matching_files(&name_list, dirname, suffix);
|
||||
}
|
||||
|
||||
snprintf(dirname, sizeof(dirname), "%s/default", dir);
|
||||
dirname[sizeof(dirname)-1] = '\0';
|
||||
dbg("looking at '%s'", dirname);
|
||||
add_matching_files(&name_list, dirname, suffix);
|
||||
|
||||
list_for_each_entry_safe(name_loop, name_tmp, &name_list, node) {
|
||||
run_program(name_loop->name, subsystem);
|
||||
list_del(&name_loop->node);
|
||||
}
|
||||
|
||||
logging_close();
|
||||
return 0;
|
||||
}
|
78
extras/run_directory/udev_run_devd.c
Normal file
78
extras/run_directory/udev_run_devd.c
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* udev_run_devd.c - directory multiplexer
|
||||
*
|
||||
* Copyright (C) 2005 Kay Sievers <kay@vrfy.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation version 2 of the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "../../udev_utils.h"
|
||||
#include "../../list.h"
|
||||
#include "../../logging.h"
|
||||
|
||||
extern int run_directory(const char *dir, const char *suffix, const char *subsystem);
|
||||
|
||||
#ifdef USE_LOG
|
||||
void log_message (int priority, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
static int udev_log = -1;
|
||||
|
||||
if (udev_log == -1) {
|
||||
const char *value;
|
||||
|
||||
value = getenv("UDEV_LOG");
|
||||
if (value)
|
||||
udev_log = log_priority(value);
|
||||
else
|
||||
udev_log = LOG_ERR;
|
||||
}
|
||||
|
||||
if (priority > udev_log)
|
||||
return;
|
||||
|
||||
va_start(args, format);
|
||||
vsyslog(priority, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[], char *envp[])
|
||||
{
|
||||
const char *subsystem;
|
||||
int fd;
|
||||
|
||||
if (getenv("DEVNAME") == NULL)
|
||||
exit(0);
|
||||
|
||||
subsystem = argv[1];
|
||||
logging_init("udev_run_devd");
|
||||
|
||||
fd = open("/dev/null", O_RDWR);
|
||||
if (fd >= 0) {
|
||||
dup2(fd, STDOUT_FILENO);
|
||||
dup2(fd, STDIN_FILENO);
|
||||
dup2(fd, STDERR_FILENO);
|
||||
close(fd);
|
||||
}
|
||||
dbg("running dev.d directory");
|
||||
|
||||
run_directory("/etc/dev.d", ".dev", subsystem);
|
||||
exit(0);
|
||||
}
|
76
extras/run_directory/udev_run_hotplugd.c
Normal file
76
extras/run_directory/udev_run_hotplugd.c
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* udev_run_hotplugd.c - directory multiplexer
|
||||
*
|
||||
* Copyright (C) 2005 Kay Sievers <kay@vrfy.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation version 2 of the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "../../udev_utils.h"
|
||||
#include "../../list.h"
|
||||
#include "../../logging.h"
|
||||
|
||||
extern int run_directory(const char *dir, const char *suffix, const char *subsystem);
|
||||
|
||||
#ifdef USE_LOG
|
||||
void log_message (int priority, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
static int udev_log = -1;
|
||||
|
||||
if (udev_log == -1) {
|
||||
const char *value;
|
||||
|
||||
value = getenv("UDEV_LOG");
|
||||
if (value)
|
||||
udev_log = log_priority(value);
|
||||
else
|
||||
udev_log = LOG_ERR;
|
||||
}
|
||||
|
||||
if (priority > udev_log)
|
||||
return;
|
||||
|
||||
va_start(args, format);
|
||||
vsyslog(priority, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[], char *envp[])
|
||||
{
|
||||
const char *subsystem;
|
||||
int fd;
|
||||
|
||||
subsystem = argv[1];
|
||||
logging_init("udev_run_hotplugd");
|
||||
|
||||
fd = open("/dev/null", O_RDWR);
|
||||
if (fd >= 0) {
|
||||
dup2(fd, STDOUT_FILENO);
|
||||
dup2(fd, STDIN_FILENO);
|
||||
dup2(fd, STDERR_FILENO);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
dbg("running dev.d directory");
|
||||
|
||||
run_directory("/etc/hotplug.d", ".hotplug", subsystem);
|
||||
exit(0);
|
||||
}
|
@ -33,7 +33,7 @@ override CFLAGS+=-D_FILE_OFFSET_BITS=64
|
||||
VOLUME_ID_BASE=volume_id
|
||||
include $(VOLUME_ID_BASE)/Makefile.inc
|
||||
|
||||
OBJS = udev_volume_id.o $(VOLUME_ID_OBJS) $(SYSFS)
|
||||
OBJS = udev_volume_id.o $(VOLUME_ID_OBJS) ../../udev.a
|
||||
HEADERS = $(VOLUME_ID_HEADERS)
|
||||
|
||||
$(OBJS): $(HEADERS)
|
||||
|
@ -40,12 +40,26 @@
|
||||
#define BLKGETSIZE64 _IOR(0x12,114,size_t)
|
||||
|
||||
#ifdef USE_LOG
|
||||
void log_message(int level, const char *format, ...)
|
||||
void log_message(int priority, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
static int udev_log = -1;
|
||||
|
||||
if (udev_log == -1) {
|
||||
const char *value;
|
||||
|
||||
value = getenv("UDEV_LOG");
|
||||
if (value)
|
||||
udev_log = log_priority(value);
|
||||
else
|
||||
udev_log = LOG_ERR;
|
||||
}
|
||||
|
||||
if (priority > udev_log)
|
||||
return;
|
||||
|
||||
va_start(args, format);
|
||||
vsyslog(level, format, args);
|
||||
vsyslog(priority, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
#endif
|
||||
|
@ -69,4 +69,9 @@ local-install: $(CROSS)klcc
|
||||
$(INSTALL_DATA) klcc.1 $(INSTALLROOT)$(mandir)/man1/$(KCROSS)klcc.1
|
||||
$(INSTALL_EXEC) $(KCROSS)klcc $(INSTALLROOT)$(bindir)
|
||||
|
||||
# This does all the prep work needed to turn a freshly exported git repository
|
||||
# into a release tarball tree
|
||||
release: klibc.spec
|
||||
rm -f maketar.sh
|
||||
|
||||
-include MCONFIG
|
||||
|
1
klibc/include/net/route.h
Normal file
1
klibc/include/net/route.h
Normal file
@ -0,0 +1 @@
|
||||
#include <linux/route.h>
|
1
klibc/include/netpacket/packet.h
Normal file
1
klibc/include/netpacket/packet.h
Normal file
@ -0,0 +1 @@
|
||||
#include <linux/if_packet.h>
|
@ -82,10 +82,6 @@ __extern int sigaction(int, const struct sigaction *, struct sigaction *);
|
||||
__extern int sigprocmask(int, const sigset_t *, sigset_t *);
|
||||
__extern int sigpending(sigset_t *);
|
||||
__extern int sigsuspend(const sigset_t *);
|
||||
__extern int rt_sigaction(int, const struct sigaction *, struct sigaction *, size_t);
|
||||
__extern int rt_sigprocmask(int, const sigset_t *, sigset_t *, size_t);
|
||||
__extern int rt_sigpending(sigset_t *, size_t);
|
||||
__extern int rt_sigsuspend(const sigset_t *, size_t);
|
||||
__extern int raise(int);
|
||||
__extern int kill(pid_t, int);
|
||||
|
||||
|
43
klibc/klcc.1
43
klibc/klcc.1
@ -1,4 +1,4 @@
|
||||
.\" $Id: klcc.1,v 1.2 2005/03/02 02:24:17 hpa Exp $
|
||||
.\" $Id: klcc.1,v 1.3 2005/04/19 23:27:46 hpa Exp $
|
||||
.\" -----------------------------------------------------------------------
|
||||
.\"
|
||||
.\" Copyright 2005 H. Peter Anvin - All Rights Reserved
|
||||
@ -39,7 +39,9 @@ klcc \- compile a program against klibc
|
||||
.B klcc
|
||||
is a wrapper around
|
||||
.BR gcc (1)
|
||||
to compile a program against the
|
||||
and
|
||||
.BR ld (1)
|
||||
which compiles and links a program against the
|
||||
.B klibc
|
||||
tiny C library. It supports most
|
||||
.B gcc
|
||||
@ -63,7 +65,12 @@ or
|
||||
option to use the default optimization level; this will generally
|
||||
result in the smallest binaries. You may want to use
|
||||
.B \-s
|
||||
when linking, however.
|
||||
when linking, however. Use
|
||||
.B \-O0
|
||||
to compile without any optimization whatsoever; this may not work depending
|
||||
on the version of
|
||||
.B gcc
|
||||
used.
|
||||
.PP
|
||||
Use the
|
||||
.B \-shared
|
||||
@ -72,10 +79,38 @@ or
|
||||
option to compile for and link against shared or static klibc. Note
|
||||
that shared klibc only supports running against the exact same klibc
|
||||
binary as the binary was linked with.
|
||||
.PP
|
||||
In addition to standard
|
||||
.B gcc
|
||||
options,
|
||||
.B klcc
|
||||
supports options of the form \fB\-print-klibc-\fP\fIoption\fP,
|
||||
which prints the corresponding klibc configuration option.
|
||||
.SH AUTHOR
|
||||
Written by H. Peter Anvin <hpa@zytor.com>.
|
||||
.SH COPYRIGHT
|
||||
Copyright \(co 2005 H. Peter Anvin.
|
||||
Copyright \(co 2005 H. Peter Anvin \- All Rights Reserved
|
||||
.PP
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom
|
||||
the Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
.PP
|
||||
The above copyright notice and this permission notice shall
|
||||
be included in all copies or substantial portions of the Software.
|
||||
.PP
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
.SH "SEE ALSO"
|
||||
.BR gcc (1)
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
# -*- perl -*-
|
||||
|
||||
use IPC::Open3;
|
||||
|
||||
# Standard includes
|
||||
@includes = ("-I${prefix}/${KCROSS}include/arch/${ARCH}",
|
||||
"-I${prefix}/${KCROSS}include/bits${BITSIZE}",
|
||||
@ -57,7 +59,7 @@ sub files_with_lang($$) {
|
||||
|
||||
# Skip object files
|
||||
if ( $need ne 'obj' ) {
|
||||
unless ( $xopt eq $need ) {
|
||||
unless ( $xopt eq $need || $need eq 'stdin') {
|
||||
push(@as, '-x', $need);
|
||||
$xopt = $need;
|
||||
}
|
||||
@ -79,7 +81,11 @@ sub syserr($) {
|
||||
# Run a program; printing out the command line if $verbose is set
|
||||
sub mysystem(@) {
|
||||
print STDERR join(' ', @_), "\n" if ( $verbose );
|
||||
return system(@_);
|
||||
my $cmd = shift;
|
||||
open(INPUT, "<&STDIN"); # dup STDIN filehandle to INPUT
|
||||
my $childpid = open3("<&INPUT", ">&STDOUT", ">&STDERR", $cmd, @_);
|
||||
waitpid ($childpid, 0);
|
||||
return $?;
|
||||
}
|
||||
|
||||
#
|
||||
@ -117,6 +123,11 @@ while ( defined($a = shift(@ARGV)) ) {
|
||||
# Not an option. Must be a filename then.
|
||||
push(@files, $a);
|
||||
$flang{$a} = $lang || filename2lang($a);
|
||||
} elsif ( $a eq '-' ) {
|
||||
# gcc gets its input from stdin
|
||||
push(@files, $a);
|
||||
# prevent setting -x
|
||||
$flang{$a} = 'stdin'
|
||||
} elsif ( $a =~ /^-print-klibc-(.*)$/ ) {
|
||||
# This test must precede -print
|
||||
if ( defined($conf{$1}) ) {
|
||||
|
149
klibc/klibc/Kbuild
Normal file
149
klibc/klibc/Kbuild
Normal file
@ -0,0 +1,149 @@
|
||||
#
|
||||
# Kbuild file for klibc
|
||||
#
|
||||
|
||||
libc-y := vsnprintf.o snprintf.o vsprintf.o sprintf.o \
|
||||
asprintf.o vasprintf.o \
|
||||
vsscanf.o sscanf.o ctypes.o \
|
||||
strntoumax.o strntoimax.o \
|
||||
atoi.o atol.o atoll.o \
|
||||
strtol.o strtoll.o strtoul.o strtoull.o \
|
||||
strtoimax.o strtoumax.o \
|
||||
globals.o exitc.o atexit.o onexit.o \
|
||||
execl.o execle.o execv.o execvpe.o execvp.o execlp.o execlpe.o \
|
||||
fork.o wait.o wait3.o waitpid.o system.o setpgrp.o getpgrp.o \
|
||||
daemon.o \
|
||||
printf.o vprintf.o fprintf.o vfprintf.o perror.o \
|
||||
statfs.o fstatfs.o umount.o \
|
||||
open.o fopen.o fread.o fread2.o fgetc.o fgets.o \
|
||||
fwrite.o fwrite2.o fputc.o fputs.o puts.o putchar.o \
|
||||
sleep.o usleep.o strtotimespec.o strtotimeval.o \
|
||||
raise.o abort.o assert.o alarm.o pause.o \
|
||||
__signal.o sysv_signal.o bsd_signal.o siglist.o siglongjmp.o \
|
||||
sigaction.o sigpending.o sigprocmask.o sigsuspend.o \
|
||||
brk.o sbrk.o malloc.o realloc.o calloc.o mmap.o \
|
||||
memcpy.o memcmp.o memset.o memccpy.o memmem.o memswap.o \
|
||||
memmove.o memchr.o memrchr.o \
|
||||
strcasecmp.o strncasecmp.o strndup.o strerror.o \
|
||||
strcat.o strchr.o strcmp.o strcpy.o strdup.o strlen.o strnlen.o \
|
||||
strncat.o strlcpy.o strlcat.o \
|
||||
strstr.o strncmp.o strncpy.o strrchr.o \
|
||||
strxspn.o strspn.o strcspn.o strpbrk.o strsep.o strtok.o \
|
||||
gethostname.o getdomainname.o getcwd.o \
|
||||
seteuid.o setegid.o \
|
||||
getenv.o setenv.o putenv.o __put_env.o unsetenv.o \
|
||||
getopt.o readdir.o \
|
||||
syslog.o closelog.o pty.o getpt.o isatty.o reboot.o \
|
||||
time.o utime.o llseek.o nice.o getpriority.o \
|
||||
qsort.o \
|
||||
lrand48.o jrand48.o mrand48.o nrand48.o srand48.o seed48.o \
|
||||
inet/inet_ntoa.o inet/inet_aton.o inet/inet_addr.o \
|
||||
inet/inet_ntop.o inet/inet_pton.o inet/bindresvport.o \
|
||||
send.o recv.o
|
||||
|
||||
libc-$(CONFIG_KLIBC_ERRLIST) += errlist.o
|
||||
|
||||
libc-$(CONFIG_KLIBC_ZLIB) += \
|
||||
zlib/adler32.o zlib/compress.o zlib/crc32.o zlib/gzio.o \
|
||||
zlib/uncompr.o zlib/deflate.o zlib/trees.o zlib/zutil.o \
|
||||
zlib/inflate.o zlib/infback.o zlib/inftrees.o zlib/inffast.o
|
||||
|
||||
#####
|
||||
# Add any architecture-specific rules
|
||||
include $(obj)/arch/$(ARCH)/Makefile.inc
|
||||
|
||||
#####
|
||||
# Shared definitions
|
||||
LIB := libc.a
|
||||
SOLIB := libc.so
|
||||
SOHASH := klibc.so
|
||||
CRT0 := arch/$(ARCH)/crt0.o
|
||||
INTERP_O := interp.o
|
||||
|
||||
always := $(CRT0) $(LIB) $(SOLIB) $(SOHASH) $(INTERP_O)
|
||||
LIB := $(call objectify,$(LIB))
|
||||
SOLIB := $(call objectify,$(SOLIB))
|
||||
SOHASH := $(call objectify,$(SOHASH))
|
||||
CRT0 := $(call objectify,$(CRT0))
|
||||
INTERP_O := $(call objectify,$(INTERP_O))
|
||||
|
||||
targets := arch/$(ARCH)/crt0.o
|
||||
targets += $(libc-y) $(ARCHOBJS)
|
||||
|
||||
# Generate syscall stubs
|
||||
subdir-y += syscalls
|
||||
# Generate socket calls stubs
|
||||
subdir-y += socketcalls
|
||||
|
||||
# Tell make to descend before building libs
|
||||
$(obj)/syscalls/syscalls.o: $(obj)/syscalls
|
||||
$(obj)/socketcalls/socketcalls.o: $(obj)/socketcalls
|
||||
|
||||
#####
|
||||
# Readable errormessages extracted from src..
|
||||
targets += errlist.c
|
||||
quiet_cmd_errlist = GEN $@
|
||||
cmd_errlist = $(PERL) $< $(LINUXINCLUDE) -errlist > $@ || rm -f $@
|
||||
|
||||
$(obj)/errlist.c: $(srctree)/$(src)/makeerrlist.pl
|
||||
$(call cmd,errlist)
|
||||
|
||||
# full list of dependencies for klibc
|
||||
libc-deps = $(call objectify, $(libc-y) $(ARCHOBJS)) \
|
||||
$(call objectify, syscalls/syscalls.o socketcalls/socketcalls.o)
|
||||
|
||||
######
|
||||
# Build static library: libc.a
|
||||
targets += libc.a __static_init.o
|
||||
quiet_cmd_libc = USERAR $@
|
||||
cmd_libc = rm -f $@; \
|
||||
$(USERAR) cq $@ $(filter-out FORCE,$^); \
|
||||
$(USERRANLIB) $@
|
||||
|
||||
$(LIB): $(call objectify,__static_init.o) $(libc-deps) FORCE
|
||||
$(call if_changed,libc)
|
||||
|
||||
######
|
||||
# Build shared library
|
||||
targets += libc.so __shared_init.o
|
||||
|
||||
quiet_cmd_libcso = LD $@
|
||||
cmd_libcso = $(USERLD) $(USERLDFLAGS) $(USERSHAREDFLAGS) \
|
||||
-o $@ $(filter-out FORCE,$^) $(USERLIBGCC)
|
||||
|
||||
$(SOLIB): $(CRT0) $(call objectify,__shared_init.o) $(libc-deps) FORCE
|
||||
$(call if_changed,libcso)
|
||||
|
||||
|
||||
#####
|
||||
# Build sha1 hash values
|
||||
targets += klibc.so libc.so.hash
|
||||
hostprogs-y := sha1hash
|
||||
|
||||
quiet_cmd_solibhash = HASH $@
|
||||
cmd_solibhash = $(USERNM) $< | egrep '^[0-9a-fA-F]+ [ADRTW] ' | \
|
||||
sort | $(obj)/sha1hash > $@
|
||||
$(SOLIB).hash: $(SOLIB) $(obj)/sha1hash FORCE
|
||||
$(call if_changed,solibhash)
|
||||
|
||||
quiet_cmd_sohash = GEN $@
|
||||
cmd_sohash = cat $< > $@; \
|
||||
$(USERSTRIP) $(USERSTRIPFLAGS) $@; \
|
||||
rm -f $(obj)/klibc-??????????????????????.so; \
|
||||
ln -f $@ $(obj)/klibc-`cat $(SOLIB).hash`.so
|
||||
$(SOHASH): $(SOLIB) $(SOLIB).hash
|
||||
$(call cmd,sohash)
|
||||
|
||||
|
||||
#####
|
||||
# build interp.o
|
||||
targets += interp.o
|
||||
|
||||
quiet_cmd_interp = BUILD $@
|
||||
cmd_interp = $(USERCC) $(usercflags) -D__ASSEMBLY__ \
|
||||
-DLIBDIR=\"$(SHLIBDIR)\" \
|
||||
-DSOHASH=\"`cat $(SOLIB).hash`\" \
|
||||
-c -o $@ $<
|
||||
|
||||
$(INTERP_O): $(obj)/interp.S $(SOLIB).hash
|
||||
$(call if_changed,interp)
|
@ -145,17 +145,29 @@ ssize_t pwrite64,pwrite::pwrite(int, void *, size_t, off_t)
|
||||
;
|
||||
; Signal operations
|
||||
;
|
||||
int kill(pid_t, int)
|
||||
; We really should get rid of the non-rt_* of these, but that takes
|
||||
; sanitizing <signal.h> for all architectures, sigh...
|
||||
<?> int sigaction(int, const struct sigaction *, struct sigaction *)
|
||||
<?> int sigsuspend(const sigset_t *)
|
||||
<?> int sigpending(sigset_t *)
|
||||
<?> int sigprocmask(int, const sigset_t *, sigset_t *)
|
||||
int rt_sigaction(int, const struct sigaction *, struct sigaction *, size_t)
|
||||
int rt_sigsuspend(const sigset_t *, size_t)
|
||||
int rt_sigpending(sigset_t *, size_t)
|
||||
int rt_sigprocmask(int, const sigset_t *, sigset_t *, size_t)
|
||||
; sanitizing <signal.h> for all architectures, sigh.
|
||||
#ifdef __NR_sigaction
|
||||
int sigaction::__sigaction(int, const struct sigaction *, struct sigaction *)
|
||||
#else
|
||||
int rt_sigaction::__rt_sigaction(int, const struct sigaction *, struct sigaction *, size_t)
|
||||
#endif
|
||||
#ifdef __NR_sigsuspend
|
||||
int sigsuspend(const sigset_t *)
|
||||
#else
|
||||
int rt_sigsuspend::__rt_sigsuspend(const sigset_t *, size_t)
|
||||
#endif
|
||||
#ifdef __NR_sigpending
|
||||
int sigpending(sigset_t *)
|
||||
#else
|
||||
int rt_sigpending::__rt_sigpending(sigset_t *, size_t)
|
||||
#endif
|
||||
#ifdef __NR_sigprocmask
|
||||
int sigprocmask(int, const sigset_t *, sigset_t *)
|
||||
#else
|
||||
int rt_sigprocmask::__rt_sigprocmask(int, const sigset_t *, sigset_t *, size_t)
|
||||
#endif
|
||||
int kill(pid_t, int)
|
||||
<?> unsigned int alarm(unsigned int)
|
||||
int getitimer(int, struct itimerval *)
|
||||
int setitimer(int, const struct itimerval *, struct itimerval *)
|
||||
|
@ -13,6 +13,7 @@ ARCHOBJS = \
|
||||
arch/$(ARCH)/setjmp.o \
|
||||
arch/$(ARCH)/syscall.o \
|
||||
arch/$(ARCH)/open.o \
|
||||
arch/$(ARCH)/sigreturn.o \
|
||||
arch/$(ARCH)/libgcc/__ashldi3.o \
|
||||
arch/$(ARCH)/libgcc/__ashrdi3.o \
|
||||
arch/$(ARCH)/libgcc/__lshrdi3.o \
|
||||
|
15
klibc/klibc/arch/i386/sigreturn.S
Normal file
15
klibc/klibc/arch/i386/sigreturn.S
Normal file
@ -0,0 +1,15 @@
|
||||
#
|
||||
# arch/i386/sigreturn.S
|
||||
#
|
||||
|
||||
#include <asm/unistd.h>
|
||||
|
||||
.text
|
||||
.align 4
|
||||
.globl __sigreturn
|
||||
.type __sigreturn,@function
|
||||
__sigreturn:
|
||||
pop %eax # Have no idea why this is needed...
|
||||
movl $__NR_sigreturn,%eax
|
||||
int $0x80
|
||||
.size __sigreturn,.-__sigreturn
|
@ -15,8 +15,13 @@
|
||||
# debugging using gdb.
|
||||
#
|
||||
ARCHREQFLAGS = -m64
|
||||
ifeq ($(DEBUG),y)
|
||||
OPTFLAGS = -Os -fomit-frame-pointer \
|
||||
-falign-functions=0 -falign-jumps=0 -falign-loops=0
|
||||
else
|
||||
OPTFLAGS = -Os -fno-asynchronous-unwind-tables -fomit-frame-pointer \
|
||||
-falign-functions=0 -falign-jumps=0 -falign-loops=0
|
||||
endif
|
||||
BITSIZE = 64
|
||||
LDFLAGS = -m elf_x86_64
|
||||
|
||||
|
@ -10,7 +10,8 @@
|
||||
ARCHOBJS = \
|
||||
arch/$(ARCH)/exits.o \
|
||||
arch/$(ARCH)/setjmp.o \
|
||||
arch/$(ARCH)/syscall.o
|
||||
arch/$(ARCH)/syscall.o \
|
||||
arch/$(ARCH)/sigreturn.o
|
||||
|
||||
ARCHSOOBJS = $(patsubst %.o,%.lo,$(ARCHOBJS))
|
||||
|
||||
|
15
klibc/klibc/arch/x86_64/sigreturn.S
Normal file
15
klibc/klibc/arch/x86_64/sigreturn.S
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* arch/x86_64/sigreturn.S
|
||||
*/
|
||||
|
||||
#include <asm/unistd.h>
|
||||
|
||||
.text
|
||||
.align 4
|
||||
.globl __sigreturn
|
||||
.type __sigreturn,@function
|
||||
__sigreturn:
|
||||
movl $__NR_rt_sigreturn,%eax
|
||||
syscall
|
||||
|
||||
.size __sigreturn,.-__sigreturn
|
@ -15,14 +15,14 @@ __syscall_common:
|
||||
syscall
|
||||
|
||||
cmpq $-4095,%rax
|
||||
jb 1f
|
||||
jnb 1f
|
||||
ret
|
||||
|
||||
# Error return, must set errno
|
||||
1:
|
||||
negl %eax
|
||||
movl %eax,errno(%rip) # errno is type int, so 32 bits
|
||||
orq $-1,%rax # orq $-1 smaller than movq $-1
|
||||
|
||||
1:
|
||||
ret
|
||||
|
||||
.size __syscall_common,.-__syscall_common
|
||||
|
@ -20,6 +20,7 @@ char *fgets(char *s, int n, FILE *f)
|
||||
return NULL;
|
||||
}
|
||||
*p++ = ch;
|
||||
n--;
|
||||
if ( ch == '\n' )
|
||||
break;
|
||||
}
|
||||
|
@ -5,11 +5,40 @@
|
||||
#include <signal.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#ifndef __NR_sigaction
|
||||
__extern void __sigreturn(void);
|
||||
__extern int __sigaction(int, const struct sigaction *, struct sigaction *);
|
||||
__extern int __rt_sigaction(int, const struct sigaction *, struct sigaction *, size_t);
|
||||
|
||||
int sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
|
||||
{
|
||||
return rt_sigaction(sig, act, oact, sizeof(sigset_t));
|
||||
}
|
||||
int rv;
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
/* x86-64, and the Fedora i386 kernel, are broken without SA_RESTORER */
|
||||
struct sigaction sa;
|
||||
|
||||
if ( act && !(act->sa_flags & SA_RESTORER) ) {
|
||||
sa = *act;
|
||||
act = &sa;
|
||||
|
||||
/* The kernel can't be trusted to have a valid default restorer */
|
||||
sa.sa_flags |= SA_RESTORER;
|
||||
sa.sa_restorer = &__sigreturn;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __NR_sigaction
|
||||
rv = __sigaction(sig, act, oact);
|
||||
#else
|
||||
rv = __rt_sigaction(sig, act, oact, sizeof(sigset_t));
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
if ( oact && (oact->sa_restorer == &__sigreturn) ) {
|
||||
oact->sa_flags &= ~SA_RESTORER;
|
||||
}
|
||||
#endif
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
@ -7,9 +7,11 @@
|
||||
|
||||
#ifndef __NR_sigpending
|
||||
|
||||
__extern __rt_sigpending(sigset_t *, size_t);
|
||||
|
||||
int sigpending(sigset_t *set)
|
||||
{
|
||||
return rt_sigpending(set, sizeof(sigset_t));
|
||||
return __rt_sigpending(set, sizeof(sigset_t));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -7,9 +7,11 @@
|
||||
|
||||
#ifndef __NR_sigprocmask
|
||||
|
||||
__extern __rt_sigprocmask(int, const sigset_t *, sigset_t *, size_t);
|
||||
|
||||
int sigprocmask(int how, const sigset_t *set, sigset_t *oset)
|
||||
{
|
||||
return rt_sigprocmask(how, set, oset, sizeof(sigset_t));
|
||||
return __rt_sigprocmask(how, set, oset, sizeof(sigset_t));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -7,9 +7,11 @@
|
||||
|
||||
#ifndef __NR_sigsuspend
|
||||
|
||||
__extern int __rt_sigsuspend(const sigset_t *, size_t);
|
||||
|
||||
int sigsuspend(const sigset_t *mask)
|
||||
{
|
||||
return rt_sigsuspend(mask, sizeof *mask);
|
||||
return __rt_sigsuspend(mask, sizeof *mask);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -33,12 +33,13 @@ uintmax_t strntoumax(const char *nptr, char **endptr, int base, size_t n)
|
||||
}
|
||||
|
||||
/* Single optional + or - */
|
||||
if ( n && *nptr == '-' ) {
|
||||
minus = 1;
|
||||
nptr++;
|
||||
n--;
|
||||
} else if ( n && *nptr == '+' ) {
|
||||
nptr++;
|
||||
if ( n ) {
|
||||
char c = *nptr;
|
||||
if ( c == '-' || c == '+' ) {
|
||||
minus = (c == '-');
|
||||
nptr++;
|
||||
n--;
|
||||
}
|
||||
}
|
||||
|
||||
if ( base == 0 ) {
|
||||
|
0
klibc/makeklcc.pl
Normal file → Executable file
0
klibc/makeklcc.pl
Normal file → Executable file
@ -1 +1 @@
|
||||
1.0.7
|
||||
1.0.14
|
||||
|
2
test/simple-build-check.sh
Normal file → Executable file
2
test/simple-build-check.sh
Normal file → Executable file
@ -1,6 +1,6 @@
|
||||
#/bin/sh
|
||||
|
||||
EXTRAS="extras/chassis_id extras/scsi_id extras/volume_id"
|
||||
EXTRAS="extras/chassis_id extras/scsi_id extras/volume_id extras/run_directory"
|
||||
|
||||
[ -z "$KERNEL_DIR" ] && KERNEL_DIR=/lib/modules/`uname -r`/build
|
||||
echo KERNEL_DIR: "$KERNEL_DIR"
|
||||
|
@ -241,7 +241,7 @@ BUS=="scsi", ID=="0:0:0:0", NAME="first_disk%n"
|
||||
EOF
|
||||
},
|
||||
{
|
||||
desc => "test NAME substitution chars",
|
||||
desc => "test substitution chars",
|
||||
subsys => "block",
|
||||
devpath => "/block/sda/sda3",
|
||||
exp_name => "Major:8:minor:3:kernelnumber:3:bus:0:0:0:0" ,
|
||||
@ -250,7 +250,7 @@ BUS=="scsi", ID=="0:0:0:0", NAME="Major:%M:minor:%m:kernelnumber:%n:bus:%b"
|
||||
EOF
|
||||
},
|
||||
{
|
||||
desc => "test NAME substitution chars (with length limit)",
|
||||
desc => "test substitution chars (with length limit)",
|
||||
subsys => "block",
|
||||
devpath => "/block/sda/sda3",
|
||||
exp_name => "M8-m3-n3-b0:0-sIBM" ,
|
||||
@ -360,6 +360,51 @@ EOF
|
||||
exp_name => "my-foo8" ,
|
||||
rules => <<EOF
|
||||
BUS=="scsi", PROGRAM=="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL=="sda3", NAME="my-%c{6}"
|
||||
EOF
|
||||
},
|
||||
{
|
||||
desc => "test substitution by variable name",
|
||||
subsys => "block",
|
||||
devpath => "/block/sda/sda3",
|
||||
exp_name => "Major:8-minor:3-kernelnumber:3-bus:0:0:0:0" ,
|
||||
rules => <<EOF
|
||||
BUS=="scsi", ID=="0:0:0:0", NAME="Major:\$major-minor:\$minor-kernelnumber:\$number-bus:\$id"
|
||||
EOF
|
||||
},
|
||||
{
|
||||
desc => "test substitution by variable name 2",
|
||||
subsys => "block",
|
||||
devpath => "/block/sda/sda3",
|
||||
exp_name => "Major:8-minor:3-kernelnumber:3-bus:0:0:0:0" ,
|
||||
rules => <<EOF
|
||||
BUS=="scsi", ID=="0:0:0:0", DEVPATH="*/sda/*", NAME="Major:\$major-minor:%m-kernelnumber:\$number-bus:%b"
|
||||
EOF
|
||||
},
|
||||
{
|
||||
desc => "test substitution by variable name 3",
|
||||
subsys => "block",
|
||||
devpath => "/block/sda/sda3",
|
||||
exp_name => "830:0:0:03" ,
|
||||
rules => <<EOF
|
||||
BUS=="scsi", ID=="0:0:0:0", DEVPATH="*/sda/*", NAME="%M%m%b%n"
|
||||
EOF
|
||||
},
|
||||
{
|
||||
desc => "test substitution by variable name 4",
|
||||
subsys => "block",
|
||||
devpath => "/block/sda/sda3",
|
||||
exp_name => "833" ,
|
||||
rules => <<EOF
|
||||
BUS=="scsi", ID=="0:0:0:0", DEVPATH="*/sda/*", NAME="\$major\$minor\$number"
|
||||
EOF
|
||||
},
|
||||
{
|
||||
desc => "test substitution by variable name 5",
|
||||
subsys => "block",
|
||||
devpath => "/block/sda/sda3",
|
||||
exp_name => "8330:0:0:0" ,
|
||||
rules => <<EOF
|
||||
BUS=="scsi", ID=="0:0:0:0", DEVPATH="*/sda/*", NAME="\$major%m%n\$id"
|
||||
EOF
|
||||
},
|
||||
{
|
||||
@ -783,9 +828,9 @@ EOF
|
||||
exp_name => "symlink-only2",
|
||||
exp_target => "link",
|
||||
rules => <<EOF
|
||||
BUS=="scsi", KERNEL=="sda", SYMLINK="symlink-only1"
|
||||
BUS=="scsi", KERNEL=="sda", SYMLINK="symlink-only2"
|
||||
BUS=="scsi", KERNEL=="sda", NAME="link", SYMLINK="symlink0"
|
||||
BUS=="scsi", KERNEL=="sda", SYMLINK+="symlink-only1"
|
||||
BUS=="scsi", KERNEL=="sda", SYMLINK+="symlink-only2"
|
||||
BUS=="scsi", KERNEL=="sda", NAME="link", SYMLINK+="symlink0"
|
||||
EOF
|
||||
},
|
||||
{
|
||||
@ -797,7 +842,7 @@ EOF
|
||||
exp_add_error => "yes",
|
||||
exp_rem_error => "yes",
|
||||
rules => <<EOF
|
||||
BUS=="scsi", KERNEL=="sda", NAME="link", SYMLINK="."
|
||||
BUS=="scsi", KERNEL=="sda", NAME="link", SYMLINK+="."
|
||||
EOF
|
||||
},
|
||||
{
|
||||
@ -809,7 +854,7 @@ EOF
|
||||
exp_rem_error => "yes",
|
||||
option => "clean",
|
||||
rules => <<EOF
|
||||
KERNEL=="tty0", NAME="link", SYMLINK="link"
|
||||
KERNEL=="tty0", NAME="link", SYMLINK+="link"
|
||||
EOF
|
||||
},
|
||||
{
|
||||
@ -819,7 +864,7 @@ EOF
|
||||
exp_name => "symlink0",
|
||||
exp_target => "ttyUSB0",
|
||||
rules => <<EOF
|
||||
KERNEL=="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK="symlink%n"
|
||||
KERNEL=="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK+="symlink%n"
|
||||
EOF
|
||||
},
|
||||
{
|
||||
@ -829,7 +874,7 @@ EOF
|
||||
exp_name => "symlink-ttyUSB0",
|
||||
exp_target => "ttyUSB0",
|
||||
rules => <<EOF
|
||||
KERNEL=="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK="symlink-%k"
|
||||
KERNEL=="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK+="symlink-%k"
|
||||
EOF
|
||||
},
|
||||
{
|
||||
@ -839,7 +884,7 @@ EOF
|
||||
exp_name => "major-188:0",
|
||||
exp_target => "ttyUSB0",
|
||||
rules => <<EOF
|
||||
KERNEL=="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK="major-%M:%m"
|
||||
KERNEL=="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK+="major-%M:%m"
|
||||
EOF
|
||||
},
|
||||
{
|
||||
@ -849,7 +894,7 @@ EOF
|
||||
exp_name => "symlink-0:0:0:0",
|
||||
exp_target => "node",
|
||||
rules => <<EOF
|
||||
BUS=="scsi", KERNEL=="sda", NAME="node", SYMLINK="symlink-%b"
|
||||
BUS=="scsi", KERNEL=="sda", NAME="node", SYMLINK+="symlink-%b"
|
||||
EOF
|
||||
},
|
||||
{
|
||||
@ -859,7 +904,7 @@ EOF
|
||||
exp_name => "test",
|
||||
exp_target => "ttyUSB0",
|
||||
rules => <<EOF
|
||||
KERNEL=="ttyUSB[0-9]*", PROGRAM=="/bin/echo test" NAME="ttyUSB%n", SYMLINK="%c"
|
||||
KERNEL=="ttyUSB[0-9]*", PROGRAM=="/bin/echo test" NAME="ttyUSB%n", SYMLINK+="%c"
|
||||
EOF
|
||||
},
|
||||
{
|
||||
@ -869,7 +914,7 @@ EOF
|
||||
exp_name => "test",
|
||||
exp_target => "ttyUSB0",
|
||||
rules => <<EOF
|
||||
KERNEL=="ttyUSB[0-9]*", PROGRAM=="/bin/echo symlink test this" NAME="ttyUSB%n", SYMLINK="%c{2}"
|
||||
KERNEL=="ttyUSB[0-9]*", PROGRAM=="/bin/echo symlink test this" NAME="ttyUSB%n", SYMLINK+="%c{2}"
|
||||
EOF
|
||||
},
|
||||
{
|
||||
@ -879,7 +924,7 @@ EOF
|
||||
exp_name => "this",
|
||||
exp_target => "ttyUSB0",
|
||||
rules => <<EOF
|
||||
KERNEL=="ttyUSB[0-9]*", PROGRAM=="/bin/echo symlink test this" NAME="ttyUSB%n", SYMLINK="%c{2+}"
|
||||
KERNEL=="ttyUSB[0-9]*", PROGRAM=="/bin/echo symlink test this" NAME="ttyUSB%n", SYMLINK+="%c{2+}"
|
||||
EOF
|
||||
},
|
||||
{
|
||||
@ -889,8 +934,8 @@ EOF
|
||||
exp_name => "test",
|
||||
exp_target => "link",
|
||||
rules => <<EOF
|
||||
BUS=="scsi", KERNEL=="sda", PROGRAM=="/bin/echo link test this" SYMLINK="%c{2+}"
|
||||
BUS=="scsi", KERNEL=="sda", NAME="link", SYMLINK="symlink0"
|
||||
BUS=="scsi", KERNEL=="sda", PROGRAM=="/bin/echo link test this" SYMLINK+="%c{2+}"
|
||||
BUS=="scsi", KERNEL=="sda", NAME="link", SYMLINK+="symlink0"
|
||||
EOF
|
||||
},
|
||||
{
|
||||
@ -900,7 +945,7 @@ EOF
|
||||
exp_name => "188:0",
|
||||
exp_target => "ttyUSB0",
|
||||
rules => <<EOF
|
||||
KERNEL=="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK="%s{dev}"
|
||||
KERNEL=="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK+="%s{dev}"
|
||||
EOF
|
||||
},
|
||||
{
|
||||
@ -910,7 +955,7 @@ EOF
|
||||
exp_name => "188",
|
||||
exp_target => "ttyUSB0",
|
||||
rules => <<EOF
|
||||
KERNEL=="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK="%3s{dev}"
|
||||
KERNEL=="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK+="%3s{dev}"
|
||||
EOF
|
||||
},
|
||||
{
|
||||
@ -920,7 +965,7 @@ EOF
|
||||
exp_name => "percent%sign",
|
||||
exp_target => "ttyUSB0",
|
||||
rules => <<EOF
|
||||
KERNEL=="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK="percent%%sign"
|
||||
KERNEL=="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK+="percent%%sign"
|
||||
EOF
|
||||
},
|
||||
{
|
||||
@ -930,7 +975,7 @@ EOF
|
||||
exp_name => "%ttyUSB0_name",
|
||||
exp_target => "ttyUSB0",
|
||||
rules => <<EOF
|
||||
KERNEL=="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK="%%%k_name"
|
||||
KERNEL=="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK+="%%%k_name"
|
||||
EOF
|
||||
},
|
||||
{
|
||||
@ -940,7 +985,7 @@ EOF
|
||||
exp_name => "link1",
|
||||
exp_target => "node",
|
||||
rules => <<EOF
|
||||
BUS=="scsi", PROGRAM=="/bin/echo -n node link1 link2", RESULT=="node *", NAME="%c{1}", SYMLINK="%c{2} %c{3}"
|
||||
BUS=="scsi", PROGRAM=="/bin/echo -n node link1 link2", RESULT=="node *", NAME="%c{1}", SYMLINK+="%c{2} %c{3}"
|
||||
EOF
|
||||
},
|
||||
{
|
||||
@ -950,7 +995,7 @@ EOF
|
||||
exp_name => "link4",
|
||||
exp_target => "node",
|
||||
rules => <<EOF
|
||||
BUS=="scsi", PROGRAM=="/bin/echo -n node link1 link2 link3 link4", RESULT=="node *", NAME="%c{1}", SYMLINK="%c{2+}"
|
||||
BUS=="scsi", PROGRAM=="/bin/echo -n node link1 link2 link3 link4", RESULT=="node *", NAME="%c{1}", SYMLINK+="%c{2+}"
|
||||
EOF
|
||||
},
|
||||
{
|
||||
@ -1147,7 +1192,7 @@ EOF
|
||||
devpath => "/block/sda/sda1",
|
||||
exp_name => "last",
|
||||
rules => <<EOF
|
||||
BUS=="scsi", KERNEL=="sda1", SYMLINK="last", OPTIONS="last_rule"
|
||||
BUS=="scsi", KERNEL=="sda1", SYMLINK+="last", OPTIONS="last_rule"
|
||||
BUS=="scsi", KERNEL=="sda1", NAME="very-last"
|
||||
EOF
|
||||
},
|
||||
@ -1290,7 +1335,7 @@ EOF
|
||||
exp_rem_error => "yes",
|
||||
option => "clean",
|
||||
rules => <<EOF
|
||||
KERNEL=="sda", NAME="ok", RUN+="/bin/sh -c 'ln -s `basename \$DEVNAME` %r/testsymlink'"
|
||||
KERNEL=="sda", NAME="ok", RUN+="/bin/sh -c 'ln -s `basename \$\$DEVNAME` %r/testsymlink'"
|
||||
KERNEL=="sda", NAME="not-ok"
|
||||
EOF
|
||||
},
|
||||
@ -1304,6 +1349,43 @@ EOF
|
||||
KERNEL=="sda", NAME="ok2", RUN+="/bin/ln -s ok2 %r/testsymlink2"
|
||||
KERNEL=="sda", ACTION=="remove", RUN+="/bin/rm -f %r/testsymlink2"
|
||||
KERNEL=="sda", NAME="not-ok2"
|
||||
EOF
|
||||
},
|
||||
{
|
||||
desc => "final assignment",
|
||||
subsys => "block",
|
||||
devpath => "/block/sda",
|
||||
exp_name => "ok",
|
||||
exp_perms => "root:nobody:0640",
|
||||
rules => <<EOF
|
||||
KERNEL=="sda", GROUP:="nobody"
|
||||
KERNEL=="sda", GROUP="not-ok", MODE="0640", NAME="ok"
|
||||
EOF
|
||||
},
|
||||
{
|
||||
desc => "final assignment",
|
||||
subsys => "block",
|
||||
devpath => "/block/sda",
|
||||
exp_name => "ok",
|
||||
exp_perms => "root:nobody:0640",
|
||||
rules => <<EOF
|
||||
KERNEL=="sda", GROUP:="nobody"
|
||||
SUBSYSTEM=="block", MODE:="640"
|
||||
KERNEL=="sda", GROUP="not-ok", MODE="0666", NAME="ok"
|
||||
EOF
|
||||
},
|
||||
{
|
||||
desc => "reset list to current value",
|
||||
subsys => "tty",
|
||||
devpath => "/class/tty/ttyUSB0",
|
||||
exp_name => "three",
|
||||
not_exp_name => "two",
|
||||
exp_target => "node",
|
||||
rules => <<EOF
|
||||
KERNEL=="ttyUSB[0-9]*", SYMLINK+="one"
|
||||
KERNEL=="ttyUSB[0-9]*", SYMLINK+="two"
|
||||
KERNEL=="ttyUSB[0-9]*", SYMLINK="three"
|
||||
KERNEL=="ttyUSB[0-9]*", NAME="node"
|
||||
EOF
|
||||
},
|
||||
);
|
||||
@ -1443,6 +1525,13 @@ sub run_test {
|
||||
my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size,
|
||||
$atime, $mtime, $ctime, $blksize, $blocks) = stat("$PWD/$udev_root$rules->{exp_name}");
|
||||
|
||||
if (defined($rules->{not_exp_name})) {
|
||||
if ((-e "$PWD/$udev_root$rules->{not_exp_name}") ||
|
||||
(-l "$PWD/$udev_root$rules->{not_exp_name}")) {
|
||||
print "nonexistent: error \'$rules->{not_exp_name}\' not expected to be there\n";
|
||||
$error++
|
||||
}
|
||||
}
|
||||
if (defined($rules->{exp_perms})) {
|
||||
permissions_test($rules, $uid, $gid, $mode);
|
||||
}
|
||||
|
61
udev.8.in
61
udev.8.in
@ -104,6 +104,36 @@ Every rule consists of a list of comma separated key value fields:
|
||||
.sp
|
||||
.IR "key " ,[ "key " ,...]
|
||||
.P
|
||||
Each key has the following format:
|
||||
.sp
|
||||
.IR "name op value"
|
||||
.P
|
||||
There are distinct key operation types, depending on the type of the key, it
|
||||
does a comparison or an assignment.
|
||||
.P
|
||||
Comparison operators are:
|
||||
.TP
|
||||
.B ==
|
||||
Compare for equality.
|
||||
.TP
|
||||
.B !=
|
||||
Compare for non-equality.
|
||||
.P
|
||||
Assignment operators are:
|
||||
.TP
|
||||
.B +=
|
||||
Add the value to a key that holds a list of entries.
|
||||
.TP
|
||||
.B :=
|
||||
Assign a value to a key finally; disallow any later changes, which
|
||||
is useful to prevent changes by any later rules.
|
||||
.TP
|
||||
.B =
|
||||
Asign a value to a key. Keys that represent a list, are reset and only this
|
||||
single value is assigned. While this operator still works inplicitely as
|
||||
comparison on keys that can't get a value assigned, its usage as an comparison
|
||||
operator is deprecated.
|
||||
.P
|
||||
The following key names can be used to match against device properties:
|
||||
.TP
|
||||
.B BUS
|
||||
@ -158,7 +188,8 @@ The following keys can get values assigned:
|
||||
.TP
|
||||
.B NAME
|
||||
The name of the node to be created, or the name, the network interface
|
||||
should be renamed to.
|
||||
should be renamed to. Only one rule can set the a name, all later rules
|
||||
with a NAME key will be ignored.
|
||||
.TP
|
||||
.B SYMLINK
|
||||
The name of a symlink targeting the node. Every matching rule can add
|
||||
@ -305,11 +336,9 @@ following the '[' is a '!', any characters not enclosed are matched.
|
||||
.P
|
||||
After device node creation, removal, or network device renaming,
|
||||
.B udev
|
||||
executes the programs located in the directory tree under
|
||||
.IR /etc/dev.d/ .
|
||||
The name of a program must have the suffix
|
||||
.I .dev
|
||||
to be recognized.
|
||||
executes the programs specified by the
|
||||
.B RUN
|
||||
key.
|
||||
.br
|
||||
In addition to the kernel provided hotplug environment variables,
|
||||
.B UDEV_LOG
|
||||
@ -318,15 +347,7 @@ is set and contains the numerical priority value, if udev is configured to use
|
||||
Executed programs may want to follow that setting.
|
||||
.B DEVNAME
|
||||
is exported to make the name of the created node, or the name the network
|
||||
device is renamed to, available to the executed program. The programs in every
|
||||
directory are sorted in lexical order, while the directories are searched in
|
||||
the following order:
|
||||
.sp
|
||||
.nf
|
||||
/etc/dev.d/$(DEVNAME)/*.dev
|
||||
/etc/dev.d/$(SUBSYSTEM)/*.dev
|
||||
/etc/dev.d/default/*.dev
|
||||
.fi
|
||||
device is renamed to, available to the executed programs.
|
||||
.SH "ENVIRONMENT"
|
||||
.P
|
||||
The following variables are read from the environment:
|
||||
@ -352,20 +373,10 @@ Overrides the log priority specified in the config file.
|
||||
.TP
|
||||
.B UDEV_RUN
|
||||
If set to "0", it disables the execution of programs added by rules.
|
||||
.TP
|
||||
.B UDEV_NO_DEVD
|
||||
The default behavior of
|
||||
.B udev
|
||||
is to execute programs in the
|
||||
.I /etc/dev.d/
|
||||
directory after device handling. If set,
|
||||
.B udev
|
||||
will skip this step.
|
||||
.SH "FILES"
|
||||
.nf
|
||||
/sbin/udev udev program
|
||||
/etc/udev/* udev config files
|
||||
/etc/dev.d/* programs invoked by udev
|
||||
.fi
|
||||
.SH "SEE ALSO"
|
||||
.BR udevinfo (8),
|
||||
|
156
udev.c
156
udev.c
@ -54,35 +54,6 @@ void log_message(int priority, const char *format, ...)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* decide if we should manage the whole hotplug event
|
||||
* for now look if the kernel calls udevsend instead of /sbin/hotplug
|
||||
*/
|
||||
static int manage_hotplug_event(void) {
|
||||
char helper[256];
|
||||
int fd;
|
||||
int len;
|
||||
|
||||
/* don't handle hotplug.d if we are called directly */
|
||||
if (!getenv("UDEVD_EVENT"))
|
||||
return 0;
|
||||
|
||||
fd = open("/proc/sys/kernel/hotplug", O_RDONLY);
|
||||
if (fd < 0)
|
||||
return 0;
|
||||
|
||||
len = read(fd, helper, 256);
|
||||
close(fd);
|
||||
|
||||
if (len < 0)
|
||||
return 0;
|
||||
helper[len] = '\0';
|
||||
|
||||
if (strstr(helper, "udevsend"))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void asmlinkage sig_handler(int signum)
|
||||
{
|
||||
switch (signum) {
|
||||
@ -96,15 +67,12 @@ static void asmlinkage sig_handler(int signum)
|
||||
|
||||
int main(int argc, char *argv[], char *envp[])
|
||||
{
|
||||
struct sysfs_class_device *class_dev;
|
||||
struct sysfs_device *devices_dev;
|
||||
struct udevice udev;
|
||||
char path[PATH_SIZE];
|
||||
const char *error;
|
||||
const char *action;
|
||||
const char *devpath;
|
||||
const char *subsystem;
|
||||
int managed_event;
|
||||
struct sigaction act;
|
||||
int retval = -EINVAL;
|
||||
|
||||
@ -129,11 +97,6 @@ int main(int argc, char *argv[], char *envp[])
|
||||
/* trigger timeout to prevent hanging processes */
|
||||
alarm(ALARM_TIMEOUT);
|
||||
|
||||
/* let the executed programs know if we handle the whole hotplug event */
|
||||
managed_event = manage_hotplug_event();
|
||||
if (managed_event)
|
||||
setenv("MANAGED_EVENT", "1", 1);
|
||||
|
||||
action = getenv("ACTION");
|
||||
devpath = getenv("DEVPATH");
|
||||
subsystem = getenv("SUBSYSTEM");
|
||||
@ -141,14 +104,12 @@ int main(int argc, char *argv[], char *envp[])
|
||||
if (!subsystem && argc == 2)
|
||||
subsystem = argv[1];
|
||||
|
||||
udev_init_device(&udev, devpath, subsystem, action);
|
||||
|
||||
if (!action || !subsystem || !devpath) {
|
||||
err("action, subsystem or devpath missing");
|
||||
goto hotplug;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* export logging flag, as called scripts may want to do the same as udev */
|
||||
/* export log_priority , as called programs may want to do the same as udev */
|
||||
if (udev_log_priority) {
|
||||
char priority[32];
|
||||
|
||||
@ -156,99 +117,112 @@ int main(int argc, char *argv[], char *envp[])
|
||||
setenv("UDEV_LOG", priority, 1);
|
||||
}
|
||||
|
||||
udev_init_device(&udev, devpath, subsystem, action);
|
||||
udev_rules_init();
|
||||
|
||||
if (udev.type == DEV_BLOCK || udev.type == DEV_CLASS || udev.type == DEV_NET) {
|
||||
udev_rules_init();
|
||||
|
||||
/* handle device node */
|
||||
if (strcmp(action, "add") == 0) {
|
||||
/* wait for sysfs and possibly add node */
|
||||
dbg("udev add");
|
||||
|
||||
/* skip subsystems without "dev", but handle net devices */
|
||||
if (udev.type != DEV_NET && subsystem_expect_no_dev(udev.subsystem)) {
|
||||
dbg("don't care about '%s' devices", udev.subsystem);
|
||||
goto hotplug;
|
||||
}
|
||||
struct sysfs_class_device *class_dev;
|
||||
|
||||
/* wait for sysfs of /sys/class /sys/block */
|
||||
dbg("node add");
|
||||
snprintf(path, sizeof(path), "%s%s", sysfs_path, udev.devpath);
|
||||
path[sizeof(path)-1] = '\0';
|
||||
class_dev = wait_class_device_open(path);
|
||||
if (class_dev == NULL) {
|
||||
dbg("open class device failed");
|
||||
goto hotplug;
|
||||
goto run;
|
||||
}
|
||||
dbg("opened class_dev->name='%s'", class_dev->name);
|
||||
|
||||
wait_for_class_device(class_dev, &error);
|
||||
|
||||
/* name, create node, store in db */
|
||||
retval = udev_add_device(&udev, class_dev);
|
||||
/* get major/minor */
|
||||
if (udev.type == DEV_BLOCK || udev.type == DEV_CLASS)
|
||||
udev.devt = get_devt(class_dev);
|
||||
|
||||
if (udev.type == DEV_NET || udev.devt) {
|
||||
/* name device */
|
||||
udev_rules_get_name(&udev, class_dev);
|
||||
if (udev.ignore_device) {
|
||||
info("device event will be ignored");
|
||||
goto cleanup;
|
||||
}
|
||||
if (udev.name[0] == '\0') {
|
||||
info("device node creation supressed");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* create node, store in db */
|
||||
retval = udev_add_device(&udev, class_dev);
|
||||
} else {
|
||||
dbg("no dev-file found");
|
||||
udev_rules_get_run(&udev, NULL);
|
||||
if (udev.ignore_device) {
|
||||
info("device event will be ignored");
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
sysfs_close_class_device(class_dev);
|
||||
} else if (strcmp(action, "remove") == 0) {
|
||||
/* possibly remove a node */
|
||||
dbg("udev remove");
|
||||
|
||||
/* skip subsystems without "dev" */
|
||||
if (subsystem_expect_no_dev(udev.subsystem)) {
|
||||
dbg("don't care about '%s' devices", udev.subsystem);
|
||||
goto hotplug;
|
||||
}
|
||||
|
||||
udev_rules_get_run(&udev);
|
||||
dbg("node remove");
|
||||
udev_rules_get_run(&udev, NULL);
|
||||
if (udev.ignore_device) {
|
||||
dbg("device event will be ignored");
|
||||
goto hotplug;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* get node from db, remove db-entry, delete created node */
|
||||
/* get name from db, remove db-entry, delete node */
|
||||
retval = udev_remove_device(&udev);
|
||||
}
|
||||
|
||||
/* export name of device node or netif */
|
||||
if (udev.devname[0] != '\0')
|
||||
setenv("DEVNAME", udev.devname, 1);
|
||||
|
||||
if (udev_run && !list_empty(&udev.run_list)) {
|
||||
struct name_entry *name_loop;
|
||||
|
||||
dbg("executing run list");
|
||||
list_for_each_entry(name_loop, &udev.run_list, node)
|
||||
execute_command(name_loop->name, udev.subsystem);
|
||||
}
|
||||
|
||||
/* run dev.d/ scripts if we created/deleted a node or changed a netif name */
|
||||
if (udev_dev_d && udev.devname[0] != '\0')
|
||||
udev_multiplex_directory(&udev, DEVD_DIR, DEVD_SUFFIX);
|
||||
|
||||
} else if (udev.type == DEV_DEVICE) {
|
||||
if (strcmp(action, "add") == 0) {
|
||||
/* wait for sysfs */
|
||||
dbg("devices add");
|
||||
struct sysfs_device *devices_dev;
|
||||
|
||||
/* wait for sysfs of /sys/devices/ */
|
||||
dbg("devices add");
|
||||
snprintf(path, sizeof(path), "%s%s", sysfs_path, devpath);
|
||||
path[sizeof(path)-1] = '\0';
|
||||
devices_dev = wait_devices_device_open(path);
|
||||
if (!devices_dev) {
|
||||
dbg("devices device unavailable (probably remove has beaten us)");
|
||||
goto hotplug;
|
||||
goto run;
|
||||
}
|
||||
dbg("devices device opened '%s'", path);
|
||||
|
||||
wait_for_devices_device(devices_dev, &error);
|
||||
|
||||
udev_rules_get_run(&udev, devices_dev);
|
||||
sysfs_close_device(devices_dev);
|
||||
} else if (strcmp(action, "remove") == 0) {
|
||||
dbg("devices remove");
|
||||
if (udev.ignore_device) {
|
||||
info("device event will be ignored");
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dbg("unhandled");
|
||||
dbg("default handling");
|
||||
udev_rules_get_run(&udev, NULL);
|
||||
if (udev.ignore_device) {
|
||||
info("device event will be ignored");
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
hotplug:
|
||||
if (udev_hotplug_d && managed_event)
|
||||
udev_multiplex_directory(&udev, HOTPLUGD_DIR, HOTPLUG_SUFFIX);
|
||||
run:
|
||||
if (udev_run && !list_empty(&udev.run_list)) {
|
||||
struct name_entry *name_loop;
|
||||
|
||||
dbg("executing run list");
|
||||
list_for_each_entry(name_loop, &udev.run_list, node)
|
||||
execute_command(name_loop->name, udev.subsystem);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
udev_cleanup_device(&udev);
|
||||
|
||||
exit:
|
||||
logging_close();
|
||||
return retval;
|
||||
}
|
||||
|
15
udev.h
15
udev.h
@ -39,12 +39,6 @@
|
||||
#define SEQNUM_SIZE 32
|
||||
#define VALUE_SIZE 128
|
||||
|
||||
#define DEVD_DIR "/etc/dev.d"
|
||||
#define DEVD_SUFFIX ".dev"
|
||||
|
||||
#define HOTPLUGD_DIR "/etc/hotplug.d"
|
||||
#define HOTPLUG_SUFFIX ".hotplug"
|
||||
|
||||
#define DEFAULT_PARTITIONS_COUNT 15
|
||||
|
||||
enum device_type {
|
||||
@ -62,13 +56,19 @@ struct udevice {
|
||||
|
||||
enum device_type type;
|
||||
char name[PATH_SIZE];
|
||||
int name_set;
|
||||
char devname[PATH_SIZE];
|
||||
struct list_head symlink_list;
|
||||
int symlink_final;
|
||||
char owner[USER_SIZE];
|
||||
int owner_final;
|
||||
char group[USER_SIZE];
|
||||
int group_final;
|
||||
mode_t mode;
|
||||
int mode_final;
|
||||
dev_t devt;
|
||||
struct list_head run_list;
|
||||
int run_final;
|
||||
|
||||
char tmp_node[PATH_SIZE];
|
||||
int partitions;
|
||||
@ -87,7 +87,6 @@ extern int udev_add_device(struct udevice *udev, struct sysfs_class_device *clas
|
||||
extern int udev_remove_device(struct udevice *udev);
|
||||
extern void udev_init_config(void);
|
||||
extern int udev_start(void);
|
||||
extern void udev_multiplex_directory(struct udevice *udev, const char *basedir, const char *suffix);
|
||||
extern int udev_make_node(struct udevice *udev, const char *file, dev_t devt, mode_t mode, uid_t uid, gid_t gid);
|
||||
|
||||
extern char sysfs_path[PATH_SIZE];
|
||||
@ -97,7 +96,5 @@ extern char udev_config_filename[PATH_SIZE];
|
||||
extern char udev_rules_filename[PATH_SIZE];
|
||||
extern int udev_log_priority;
|
||||
extern int udev_run;
|
||||
extern int udev_dev_d;
|
||||
extern int udev_hotplug_d;
|
||||
|
||||
#endif
|
||||
|
@ -112,9 +112,6 @@ rm -rf $RPM_BUILD_ROOT
|
||||
%attr(-,root,root) /etc/hotplug.d/default/udev.hotplug
|
||||
%attr(755,root,root) /etc/init.d/udev
|
||||
%attr(0644,root,root) %{_mandir}/man8/udev*.8*
|
||||
%attr(755,root,root) %dir /etc/dev.d/
|
||||
%attr(755,root,root) %dir /etc/dev.d/net/
|
||||
%attr(0755,root,root) /etc/dev.d/net/hotplug.dev
|
||||
|
||||
%if %{scsi_id}
|
||||
%attr(755,root,root) /sbin/scsi_id
|
||||
|
49
udev_add.c
49
udev_add.c
@ -52,23 +52,6 @@ int udev_make_node(struct udevice *udev, const char *file, dev_t devt, mode_t mo
|
||||
struct stat stats;
|
||||
int retval = 0;
|
||||
|
||||
if (stat(file, &stats) != 0)
|
||||
goto create;
|
||||
|
||||
/* preserve node with already correct numbers, to not change the inode number */
|
||||
if (((stats.st_mode & S_IFMT) == S_IFBLK || (stats.st_mode & S_IFMT) == S_IFCHR) &&
|
||||
(stats.st_rdev == devt)) {
|
||||
info("preserve file '%s', cause it has correct dev_t", file);
|
||||
selinux_setfilecon(file, udev->kernel_name, stats.st_mode);
|
||||
goto perms;
|
||||
}
|
||||
|
||||
if (unlink(file) != 0)
|
||||
dbg("unlink(%s) failed with error '%s'", file, strerror(errno));
|
||||
else
|
||||
dbg("already present file '%s' unlinked", file);
|
||||
|
||||
create:
|
||||
switch (udev->type) {
|
||||
case DEV_BLOCK:
|
||||
mode |= S_IFBLK;
|
||||
@ -81,6 +64,22 @@ create:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (stat(file, &stats) != 0)
|
||||
goto create;
|
||||
|
||||
/* preserve node with already correct numbers, to not change the inode number */
|
||||
if ((stats.st_mode & S_IFMT) == (mode & S_IFMT) && (stats.st_rdev == devt)) {
|
||||
info("preserve file '%s', cause it has correct dev_t", file);
|
||||
selinux_setfilecon(file, udev->kernel_name, stats.st_mode);
|
||||
goto perms;
|
||||
}
|
||||
|
||||
if (unlink(file) != 0)
|
||||
dbg("unlink(%s) failed with error '%s'", file, strerror(errno));
|
||||
else
|
||||
dbg("already present file '%s' unlinked", file);
|
||||
|
||||
create:
|
||||
selinux_setfscreatecon(file, udev->kernel_name, mode);
|
||||
retval = mknod(file, mode, devt);
|
||||
selinux_resetfscreatecon();
|
||||
@ -268,22 +267,7 @@ int udev_add_device(struct udevice *udev, struct sysfs_class_device *class_dev)
|
||||
char *pos;
|
||||
int retval = 0;
|
||||
|
||||
if (udev->type == DEV_BLOCK || udev->type == DEV_CLASS) {
|
||||
udev->devt = get_devt(class_dev);
|
||||
if (!udev->devt) {
|
||||
dbg("no dev-file found, do nothing");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
udev_rules_get_name(udev, class_dev);
|
||||
if (udev->ignore_device) {
|
||||
dbg("device event will be ignored");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dbg("adding name='%s'", udev->name);
|
||||
|
||||
selinux_init();
|
||||
|
||||
if (udev->type == DEV_BLOCK || udev->type == DEV_CLASS) {
|
||||
@ -325,6 +309,5 @@ int udev_add_device(struct udevice *udev, struct sysfs_class_device *class_dev)
|
||||
|
||||
exit:
|
||||
selinux_exit();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
@ -45,39 +45,6 @@ char udev_config_filename[PATH_SIZE];
|
||||
char udev_rules_filename[PATH_SIZE];
|
||||
int udev_log_priority;
|
||||
int udev_run;
|
||||
int udev_dev_d;
|
||||
int udev_hotplug_d;
|
||||
|
||||
static int string_is_true(const char *str)
|
||||
{
|
||||
if (strcasecmp(str, "true") == 0)
|
||||
return 1;
|
||||
if (strcasecmp(str, "yes") == 0)
|
||||
return 1;
|
||||
if (strcasecmp(str, "1") == 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int log_priority(const char *priority)
|
||||
{
|
||||
char *endptr;
|
||||
int prio;
|
||||
|
||||
prio = strtol(priority, &endptr, 10);
|
||||
if (endptr[0] == '\0')
|
||||
return prio;
|
||||
if (strncasecmp(priority, "err", 3) == 0)
|
||||
return LOG_ERR;
|
||||
if (strcasecmp(priority, "info") == 0)
|
||||
return LOG_INFO;
|
||||
if (strcasecmp(priority, "debug") == 0)
|
||||
return LOG_DEBUG;
|
||||
if (string_is_true(priority))
|
||||
return LOG_ERR;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_key(char **line, char **key, char **value)
|
||||
{
|
||||
@ -219,8 +186,6 @@ void udev_init_config(void)
|
||||
strcpy(udev_rules_filename, UDEV_RULES_FILE);
|
||||
udev_log_priority = LOG_ERR;
|
||||
udev_run = 1;
|
||||
udev_dev_d = 1;
|
||||
udev_hotplug_d = 1;
|
||||
sysfs_get_mnt_path(sysfs_path, sizeof(sysfs_path));
|
||||
|
||||
/* disable RUN key execution */
|
||||
@ -228,14 +193,6 @@ void udev_init_config(void)
|
||||
if (env && !string_is_true(env))
|
||||
udev_run = 0;
|
||||
|
||||
env = getenv("UDEV_NO_DEVD");
|
||||
if (env && string_is_true(env))
|
||||
udev_dev_d = 0;
|
||||
|
||||
env = getenv("UDEV_NO_HOTPLUGD");
|
||||
if (env && string_is_true(env))
|
||||
udev_hotplug_d = 0;
|
||||
|
||||
env = getenv("UDEV_CONFIG_FILE");
|
||||
if (env) {
|
||||
strlcpy(udev_config_filename, env, sizeof(udev_config_filename));
|
||||
|
@ -1,92 +0,0 @@
|
||||
/*
|
||||
* udev_multiplex.c directory multiplexer
|
||||
*
|
||||
* Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation version 2 of the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This essentially emulates the following shell script logic in C:
|
||||
* DIR="/etc/dev.d"
|
||||
* export DEVNAME="whatever_dev_name_udev_just_gave"
|
||||
* for I in "${DIR}/$DEVNAME/"*.dev "${DIR}/$1/"*.dev "${DIR}/default/"*.dev ; do
|
||||
* if [ -f $I ]; then $I $1 ; fi
|
||||
* done
|
||||
* exit 1;
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "udev.h"
|
||||
#include "udev_libc_wrapper.h"
|
||||
#include "udev_utils.h"
|
||||
#include "logging.h"
|
||||
|
||||
|
||||
/*
|
||||
* runs files in these directories in order:
|
||||
* <node name given by udev>/
|
||||
* subsystem/
|
||||
* default/
|
||||
*/
|
||||
void udev_multiplex_directory(struct udevice *udev, const char *basedir, const char *suffix)
|
||||
{
|
||||
char dirname[PATH_SIZE];
|
||||
struct name_entry *name_loop, *name_tmp;
|
||||
LIST_HEAD(name_list);
|
||||
|
||||
/* chop the device name up into pieces based on '/' */
|
||||
if (udev->name[0] != '\0') {
|
||||
char devname[PATH_SIZE];
|
||||
char *temp;
|
||||
|
||||
strlcpy(devname, udev->name, sizeof(devname));
|
||||
temp = strchr(devname, '/');
|
||||
while (temp != NULL) {
|
||||
temp[0] = '\0';
|
||||
|
||||
/* don't call the subsystem directory here */
|
||||
if (strcmp(devname, udev->subsystem) != 0) {
|
||||
snprintf(dirname, sizeof(dirname), "%s/%s", basedir, devname);
|
||||
dirname[sizeof(dirname)-1] = '\0';
|
||||
add_matching_files(&name_list, dirname, suffix);
|
||||
}
|
||||
|
||||
temp[0] = '/';
|
||||
++temp;
|
||||
temp = strchr(temp, '/');
|
||||
}
|
||||
}
|
||||
|
||||
if (udev->name[0] != '\0') {
|
||||
snprintf(dirname, sizeof(dirname), "%s/%s", basedir, udev->name);
|
||||
dirname[sizeof(dirname)-1] = '\0';
|
||||
add_matching_files(&name_list, dirname, suffix);
|
||||
}
|
||||
|
||||
if (udev->subsystem[0] != '\0') {
|
||||
snprintf(dirname, sizeof(dirname), "%s/%s", basedir, udev->subsystem);
|
||||
dirname[sizeof(dirname)-1] = '\0';
|
||||
add_matching_files(&name_list, dirname, suffix);
|
||||
}
|
||||
|
||||
snprintf(dirname, sizeof(dirname), "%s/default", basedir);
|
||||
dirname[sizeof(dirname)-1] = '\0';
|
||||
add_matching_files(&name_list, dirname, suffix);
|
||||
|
||||
list_for_each_entry_safe(name_loop, name_tmp, &name_list, node) {
|
||||
execute_command(name_loop->name, udev->subsystem);
|
||||
list_del(&name_loop->node);
|
||||
}
|
||||
|
||||
}
|
@ -140,26 +140,20 @@ static int delete_node(struct udevice *udev)
|
||||
*/
|
||||
int udev_remove_device(struct udevice *udev)
|
||||
{
|
||||
const char *temp;
|
||||
|
||||
if (udev->type != DEV_BLOCK && udev->type != DEV_CLASS)
|
||||
return 0;
|
||||
|
||||
if (udev_db_get_device(udev, udev->devpath) == 0) {
|
||||
if (udev->ignore_remove) {
|
||||
dbg("remove event for '%s' requested to be ignored by rule", udev->name);
|
||||
return 0;
|
||||
}
|
||||
dbg("remove name='%s'", udev->name);
|
||||
udev_db_delete_device(udev);
|
||||
} else {
|
||||
/* fall back to kernel name */
|
||||
temp = strrchr(udev->devpath, '/');
|
||||
if (temp == NULL)
|
||||
return -ENODEV;
|
||||
strlcpy(udev->name, &temp[1], sizeof(udev->name));
|
||||
info("'%s' not found in database, falling back on default name", udev->name);
|
||||
/* remove node only if we can find it in our database */
|
||||
if (udev_db_get_device(udev, udev->devpath) != 0) {
|
||||
dbg("'%s' not found in database, ignore event", udev->name);
|
||||
return -1;
|
||||
}
|
||||
if (udev->ignore_remove) {
|
||||
dbg("remove event for '%s' requested to be ignored by rule", udev->name);
|
||||
return 0;
|
||||
}
|
||||
dbg("remove name='%s'", udev->name);
|
||||
udev_db_delete_device(udev);
|
||||
|
||||
/* use full path to the environment */
|
||||
snprintf(udev->devname, sizeof(udev->devname), "%s/%s", udev_root, udev->name);
|
||||
|
432
udev_rules.c
432
udev_rules.c
@ -172,16 +172,17 @@ static int find_sysfs_attribute(struct sysfs_class_device *class_dev, struct sys
|
||||
|
||||
dbg("look for device attribute '%s'", name);
|
||||
if (class_dev) {
|
||||
dbg("look for class attribute '%s/%s'", class_dev->path, name);
|
||||
tmpattr = sysfs_get_classdev_attr(class_dev, name);
|
||||
if (tmpattr)
|
||||
goto attr_found;
|
||||
}
|
||||
if (sysfs_device) {
|
||||
dbg("look for devices attribute '%s/%s'", sysfs_device->path, name);
|
||||
tmpattr = sysfs_get_device_attr(sysfs_device, name);
|
||||
if (tmpattr)
|
||||
goto attr_found;
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
attr_found:
|
||||
@ -197,56 +198,133 @@ static void apply_format(struct udevice *udev, char *string, size_t maxsize,
|
||||
{
|
||||
char temp[PATH_SIZE];
|
||||
char temp2[PATH_SIZE];
|
||||
char *tail, *pos, *cpos, *attr, *rest;
|
||||
char *head, *tail, *cpos, *attr, *rest;
|
||||
int len;
|
||||
int i;
|
||||
char c;
|
||||
unsigned int next_free_number;
|
||||
struct sysfs_class_device *class_dev_parent;
|
||||
enum subst_type {
|
||||
SUBST_UNKNOWN,
|
||||
SUBST_DEVPATH,
|
||||
SUBST_ID,
|
||||
SUBST_KERNEL_NUMBER,
|
||||
SUBST_KERNEL_NAME,
|
||||
SUBST_MAJOR,
|
||||
SUBST_MINOR,
|
||||
SUBST_RESULT,
|
||||
SUBST_SYSFS,
|
||||
SUBST_ENUM,
|
||||
SUBST_PARENT,
|
||||
SUBST_TEMP_NODE,
|
||||
SUBST_ROOT,
|
||||
SUBST_MODALIAS,
|
||||
};
|
||||
static const struct subst_map {
|
||||
char *name;
|
||||
char fmt;
|
||||
enum subst_type type;
|
||||
} map[] = {
|
||||
{ .name = "devpath", .fmt = 'p', .type = SUBST_DEVPATH },
|
||||
{ .name = "id", .fmt = 'b', .type = SUBST_ID },
|
||||
{ .name = "number", .fmt = 'n', .type = SUBST_KERNEL_NUMBER },
|
||||
{ .name = "kernel", .fmt = 'k', .type = SUBST_KERNEL_NAME },
|
||||
{ .name = "major", .fmt = 'M', .type = SUBST_MAJOR },
|
||||
{ .name = "minor", .fmt = 'm', .type = SUBST_MINOR },
|
||||
{ .name = "result", .fmt = 'c', .type = SUBST_RESULT },
|
||||
{ .name = "sysfs", .fmt = 's', .type = SUBST_SYSFS },
|
||||
{ .name = "enum", .fmt = 'e', .type = SUBST_ENUM },
|
||||
{ .name = "parent", .fmt = 'P', .type = SUBST_PARENT },
|
||||
{ .name = "tempnode", .fmt = 'N', .type = SUBST_TEMP_NODE },
|
||||
{ .name = "root", .fmt = 'r', .type = SUBST_ROOT },
|
||||
{ .name = "modalias", .fmt = 'A', .type = SUBST_MODALIAS },
|
||||
{}
|
||||
};
|
||||
enum subst_type type;
|
||||
const struct subst_map *subst;
|
||||
|
||||
pos = string;
|
||||
head = string;
|
||||
while (1) {
|
||||
pos = strchr(pos, '%');
|
||||
if (pos == NULL)
|
||||
break;
|
||||
|
||||
pos[0] = '\0';
|
||||
tail = pos+1;
|
||||
len = get_format_len(&tail);
|
||||
c = tail[0];
|
||||
strlcpy(temp, tail+1, sizeof(temp));
|
||||
tail = temp;
|
||||
dbg("format=%c, string='%s', tail='%s'",c , string, tail);
|
||||
len = -1;
|
||||
while (head[0] != '\0') {
|
||||
if (head[0] == '$') {
|
||||
/* substitute named variable */
|
||||
if (head[1] == '\0')
|
||||
break;
|
||||
if (head[1] == '$') {
|
||||
strlcpy(temp, head+2, sizeof(temp));
|
||||
strlcpy(head+1, temp, maxsize);
|
||||
head++;
|
||||
continue;
|
||||
}
|
||||
head[0] = '\0';
|
||||
for (subst = map; subst->name; subst++) {
|
||||
if (strncasecmp(&head[1], subst->name, strlen(subst->name)) == 0) {
|
||||
type = subst->type;
|
||||
tail = head + strlen(subst->name)+1;
|
||||
dbg("will substitute format name '%s'", subst->name);
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (head[0] == '%') {
|
||||
/* substitute format char */
|
||||
if (head[1] == '\0')
|
||||
break;
|
||||
if (head[1] == '%') {
|
||||
strlcpy(temp, head+2, sizeof(temp));
|
||||
strlcpy(head+1, temp, maxsize);
|
||||
head++;
|
||||
continue;
|
||||
}
|
||||
head[0] = '\0';
|
||||
tail = head+1;
|
||||
len = get_format_len(&tail);
|
||||
for (subst = map; subst->name; subst++) {
|
||||
if (tail[0] == subst->fmt) {
|
||||
type = subst->type;
|
||||
tail++;
|
||||
dbg("will substitute format char '%c'", subst->fmt);
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
}
|
||||
head++;
|
||||
}
|
||||
break;
|
||||
found:
|
||||
attr = get_format_attribute(&tail);
|
||||
strlcpy(temp, tail, sizeof(temp));
|
||||
dbg("format=%i, string='%s', tail='%s', class_dev=%p, sysfs_dev=%p",
|
||||
type ,string, tail, class_dev, sysfs_device);
|
||||
|
||||
switch (c) {
|
||||
case 'p':
|
||||
switch (type) {
|
||||
case SUBST_DEVPATH:
|
||||
strlcat(string, udev->devpath, maxsize);
|
||||
dbg("substitute kernel name '%s'", udev->kernel_name);
|
||||
dbg("substitute devpath '%s'", udev->devpath);
|
||||
break;
|
||||
case 'b':
|
||||
case SUBST_ID:
|
||||
strlcat(string, udev->bus_id, maxsize);
|
||||
dbg("substitute bus_id '%s'", udev->bus_id);
|
||||
break;
|
||||
case 'k':
|
||||
case SUBST_KERNEL_NAME:
|
||||
strlcat(string, udev->kernel_name, maxsize);
|
||||
dbg("substitute kernel name '%s'", udev->kernel_name);
|
||||
break;
|
||||
case 'n':
|
||||
case SUBST_KERNEL_NUMBER:
|
||||
strlcat(string, udev->kernel_number, maxsize);
|
||||
dbg("substitute kernel number '%s'", udev->kernel_number);
|
||||
break;
|
||||
case 'm':
|
||||
sprintf(temp2, "%d", minor(udev->devt));
|
||||
strlcat(string, temp2, maxsize);
|
||||
dbg("substitute minor number '%s'", temp2);
|
||||
break;
|
||||
case 'M':
|
||||
case SUBST_MAJOR:
|
||||
sprintf(temp2, "%d", major(udev->devt));
|
||||
strlcat(string, temp2, maxsize);
|
||||
dbg("substitute major number '%s'", temp2);
|
||||
break;
|
||||
case 'c':
|
||||
case SUBST_MINOR:
|
||||
sprintf(temp2, "%d", minor(udev->devt));
|
||||
strlcat(string, temp2, maxsize);
|
||||
dbg("substitute minor number '%s'", temp2);
|
||||
break;
|
||||
case SUBST_RESULT:
|
||||
if (udev->program_result[0] == '\0')
|
||||
break;
|
||||
/* get part part of the result string */
|
||||
@ -280,7 +358,7 @@ static void apply_format(struct udevice *udev, char *string, size_t maxsize,
|
||||
dbg("substitute result string '%s'", udev->program_result);
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
case SUBST_SYSFS:
|
||||
if (attr == NULL) {
|
||||
dbg("missing attribute");
|
||||
break;
|
||||
@ -307,18 +385,14 @@ static void apply_format(struct udevice *udev, char *string, size_t maxsize,
|
||||
strlcat(string, temp2, maxsize);
|
||||
dbg("substitute sysfs value '%s'", temp2);
|
||||
break;
|
||||
case '%':
|
||||
strlcat(string, "%", maxsize);
|
||||
pos++;
|
||||
break;
|
||||
case 'e':
|
||||
case SUBST_ENUM:
|
||||
next_free_number = find_free_number(udev, string);
|
||||
if (next_free_number > 0) {
|
||||
sprintf(temp2, "%d", next_free_number);
|
||||
strlcat(string, temp2, maxsize);
|
||||
}
|
||||
break;
|
||||
case 'P':
|
||||
case SUBST_PARENT:
|
||||
if (!class_dev)
|
||||
break;
|
||||
class_dev_parent = sysfs_get_classdev_parent(class_dev);
|
||||
@ -336,7 +410,7 @@ static void apply_format(struct udevice *udev, char *string, size_t maxsize,
|
||||
udev_cleanup_device(&udev_parent);
|
||||
}
|
||||
break;
|
||||
case 'N':
|
||||
case SUBST_TEMP_NODE:
|
||||
if (udev->tmp_node[0] == '\0') {
|
||||
dbg("create temporary device node for callout");
|
||||
snprintf(udev->tmp_node, sizeof(udev->tmp_node), "%s/.tmp-%u-%u",
|
||||
@ -347,19 +421,27 @@ static void apply_format(struct udevice *udev, char *string, size_t maxsize,
|
||||
strlcat(string, udev->tmp_node, maxsize);
|
||||
dbg("substitute temporary device node name '%s'", udev->tmp_node);
|
||||
break;
|
||||
case 'r':
|
||||
case SUBST_ROOT:
|
||||
strlcat(string, udev_root, maxsize);
|
||||
dbg("substitute udev_root '%s'", udev_root);
|
||||
break;
|
||||
case SUBST_MODALIAS:
|
||||
if (find_sysfs_attribute(NULL, sysfs_device, "modalias", temp2, sizeof(temp2)) != 0)
|
||||
break;
|
||||
strlcat(string, temp2, maxsize);
|
||||
dbg("substitute MODALIAS '%s'", temp2);
|
||||
break;
|
||||
default:
|
||||
err("unknown substitution type '%%%c'", c);
|
||||
err("unknown substitution type=%i", type);
|
||||
break;
|
||||
}
|
||||
/* truncate to specified length */
|
||||
if (len > 0)
|
||||
pos[len] = '\0';
|
||||
/* possibly truncate to format-char specified length */
|
||||
if (len != -1) {
|
||||
head[len] = '\0';
|
||||
dbg("truncate to %i chars, subtitution string becomes '%s'", len, head);
|
||||
}
|
||||
|
||||
strlcat(string, tail, maxsize);
|
||||
strlcat(string, temp, maxsize);
|
||||
}
|
||||
}
|
||||
|
||||
@ -519,6 +601,42 @@ static int match_rule(struct udevice *udev, struct udev_rule *rule,
|
||||
dbg(KEY_SUBSYSTEM " key is true");
|
||||
}
|
||||
|
||||
if (rule->devpath_operation != KEY_OP_UNSET) {
|
||||
dbg("check for " KEY_DEVPATH " rule->devpath='%s' udev->devpath='%s'",
|
||||
rule->devpath, udev->devpath);
|
||||
if (strcmp_pattern(rule->devpath, udev->devpath) != 0) {
|
||||
dbg(KEY_DEVPATH " is not matching");
|
||||
if (rule->devpath_operation != KEY_OP_NOMATCH)
|
||||
goto exit;
|
||||
} else {
|
||||
dbg(KEY_DEVPATH " matches");
|
||||
if (rule->devpath_operation == KEY_OP_NOMATCH)
|
||||
goto exit;
|
||||
}
|
||||
dbg(KEY_DEVPATH " key is true");
|
||||
}
|
||||
|
||||
if (rule->modalias_operation != KEY_OP_UNSET) {
|
||||
char value[NAME_SIZE];
|
||||
|
||||
if (find_sysfs_attribute(NULL, sysfs_device, "modalias", value, sizeof(value)) != 0) {
|
||||
dbg(KEY_MODALIAS " value not found");
|
||||
goto exit;
|
||||
}
|
||||
dbg("check for " KEY_MODALIAS " rule->modalias='%s' modalias='%s'",
|
||||
rule->modalias, value);
|
||||
if (strcmp_pattern(rule->modalias, value) != 0) {
|
||||
dbg(KEY_MODALIAS " is not matching");
|
||||
if (rule->modalias_operation != KEY_OP_NOMATCH)
|
||||
goto exit;
|
||||
} else {
|
||||
dbg(KEY_MODALIAS " matches");
|
||||
if (rule->modalias_operation == KEY_OP_NOMATCH)
|
||||
goto exit;
|
||||
}
|
||||
dbg(KEY_MODALIAS " key is true");
|
||||
}
|
||||
|
||||
if (rule->env_pair_count) {
|
||||
int i;
|
||||
|
||||
@ -729,13 +847,13 @@ int udev_rules_get_name(struct udevice *udev, struct sysfs_class_device *class_d
|
||||
|
||||
/* look for a matching rule to apply */
|
||||
list_for_each_entry(rule, &udev_rule_list, node) {
|
||||
if (udev->name_set && rule->name_operation != KEY_OP_UNSET) {
|
||||
dbg("node name already set, rule ignored");
|
||||
continue;
|
||||
}
|
||||
|
||||
dbg("process rule");
|
||||
if (match_rule(udev, rule, class_dev, sysfs_device) == 0) {
|
||||
if (udev->name[0] != '\0' && rule->name[0] != '\0') {
|
||||
dbg("node name already set, rule ignored");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* apply options */
|
||||
if (rule->ignore_device) {
|
||||
info("configured rule in '%s[%i]' applied, '%s' is ignored",
|
||||
@ -754,67 +872,106 @@ int udev_rules_get_name(struct udevice *udev, struct sysfs_class_device *class_d
|
||||
}
|
||||
|
||||
/* apply permissions */
|
||||
if (rule->mode != 0000) {
|
||||
if (!udev->mode_final && rule->mode != 0000) {
|
||||
if (rule->mode_operation == KEY_OP_ASSIGN_FINAL)
|
||||
udev->mode_final = 1;
|
||||
udev->mode = rule->mode;
|
||||
dbg("applied mode=%#o to '%s'", udev->mode, udev->kernel_name);
|
||||
}
|
||||
if (rule->owner[0] != '\0') {
|
||||
if (!udev->owner_final && rule->owner[0] != '\0') {
|
||||
if (rule->owner_operation == KEY_OP_ASSIGN_FINAL)
|
||||
udev->owner_final = 1;
|
||||
strlcpy(udev->owner, rule->owner, sizeof(udev->owner));
|
||||
apply_format(udev, udev->owner, sizeof(udev->owner), class_dev, sysfs_device);
|
||||
dbg("applied owner='%s' to '%s'", udev->owner, udev->kernel_name);
|
||||
}
|
||||
if (rule->group[0] != '\0') {
|
||||
if (!udev->group_final && rule->group[0] != '\0') {
|
||||
if (rule->group_operation == KEY_OP_ASSIGN_FINAL)
|
||||
udev->group_final = 1;
|
||||
strlcpy(udev->group, rule->group, sizeof(udev->group));
|
||||
apply_format(udev, udev->group, sizeof(udev->group), class_dev, sysfs_device);
|
||||
dbg("applied group='%s' to '%s'", udev->group, udev->kernel_name);
|
||||
}
|
||||
|
||||
/* collect symlinks */
|
||||
if (rule->symlink[0] != '\0') {
|
||||
if (!udev->symlink_final && rule->symlink_operation != KEY_OP_UNSET) {
|
||||
char temp[PATH_SIZE];
|
||||
char *pos, *next;
|
||||
|
||||
info("configured rule in '%s[%i]' applied, added symlink '%s'",
|
||||
rule->config_file, rule->config_line, rule->symlink);
|
||||
strlcpy(temp, rule->symlink, sizeof(temp));
|
||||
apply_format(udev, temp, sizeof(temp), class_dev, sysfs_device);
|
||||
if (rule->symlink_operation == KEY_OP_ASSIGN_FINAL)
|
||||
udev->symlink_final = 1;
|
||||
if (rule->symlink_operation == KEY_OP_ASSIGN || rule->symlink_operation == KEY_OP_ASSIGN_FINAL) {
|
||||
struct name_entry *name_loop;
|
||||
struct name_entry *temp_loop;
|
||||
|
||||
/* add multiple symlinks separated by spaces */
|
||||
pos = temp;
|
||||
next = strchr(temp, ' ');
|
||||
while (next) {
|
||||
next[0] = '\0';
|
||||
info("reset symlink list");
|
||||
list_for_each_entry_safe(name_loop, temp_loop, &udev->symlink_list, node) {
|
||||
list_del(&name_loop->node);
|
||||
free(name_loop);
|
||||
}
|
||||
}
|
||||
if (rule->symlink[0] != '\0') {
|
||||
info("configured rule in '%s[%i]' applied, added symlink '%s'",
|
||||
rule->config_file, rule->config_line, rule->symlink);
|
||||
strlcpy(temp, rule->symlink, sizeof(temp));
|
||||
apply_format(udev, temp, sizeof(temp), class_dev, sysfs_device);
|
||||
|
||||
/* add multiple symlinks separated by spaces */
|
||||
pos = temp;
|
||||
next = strchr(temp, ' ');
|
||||
while (next) {
|
||||
next[0] = '\0';
|
||||
info("add symlink '%s'", pos);
|
||||
name_list_add(&udev->symlink_list, pos, 0);
|
||||
pos = &next[1];
|
||||
next = strchr(pos, ' ');
|
||||
}
|
||||
info("add symlink '%s'", pos);
|
||||
name_list_add(&udev->symlink_list, pos, 0);
|
||||
pos = &next[1];
|
||||
next = strchr(pos, ' ');
|
||||
}
|
||||
info("add symlink '%s'", pos);
|
||||
name_list_add(&udev->symlink_list, pos, 0);
|
||||
}
|
||||
|
||||
/* set name, later rules with name set will be ignored */
|
||||
if (rule->name[0] != '\0') {
|
||||
info("configured rule in '%s[%i]' applied, '%s' becomes '%s'",
|
||||
rule->config_file, rule->config_line, udev->kernel_name, rule->name);
|
||||
if (rule->name_operation != KEY_OP_UNSET) {
|
||||
udev->name_set = 1;
|
||||
if (rule->name[0] == '\0') {
|
||||
info("configured rule in '%s[%i]' applied, node handling for '%s' supressed",
|
||||
rule->config_file, rule->config_line, udev->kernel_name);
|
||||
} else {
|
||||
strlcpy(udev->name, rule->name, sizeof(udev->name));
|
||||
apply_format(udev, udev->name, sizeof(udev->name), class_dev, sysfs_device);
|
||||
strlcpy(udev->config_file, rule->config_file, sizeof(udev->config_file));
|
||||
udev->config_line = rule->config_line;
|
||||
|
||||
strlcpy(udev->name, rule->name, sizeof(udev->name));
|
||||
apply_format(udev, udev->name, sizeof(udev->name), class_dev, sysfs_device);
|
||||
strlcpy(udev->config_file, rule->config_file, sizeof(udev->config_file));
|
||||
udev->config_line = rule->config_line;
|
||||
|
||||
if (udev->type != DEV_NET)
|
||||
dbg("name, '%s' is going to have owner='%s', group='%s', mode=%#o partitions=%i",
|
||||
udev->name, udev->owner, udev->group, udev->mode, udev->partitions);
|
||||
info("configured rule in '%s:%i' applied, '%s' becomes '%s'",
|
||||
rule->config_file, rule->config_line, udev->kernel_name, rule->name);
|
||||
if (udev->type != DEV_NET)
|
||||
dbg("name, '%s' is going to have owner='%s', group='%s', mode=%#o partitions=%i",
|
||||
udev->name, udev->owner, udev->group, udev->mode, udev->partitions);
|
||||
}
|
||||
}
|
||||
|
||||
if (rule->run[0] != '\0') {
|
||||
if (!udev->run_final && rule->run_operation != KEY_OP_UNSET) {
|
||||
char program[PATH_SIZE];
|
||||
|
||||
strlcpy(program, rule->run, sizeof(program));
|
||||
apply_format(udev, program, sizeof(program), class_dev, sysfs_device);
|
||||
dbg("add run '%s'", program);
|
||||
name_list_add(&udev->run_list, program, 0);
|
||||
if (rule->run_operation == KEY_OP_ASSIGN_FINAL)
|
||||
udev->run_final = 1;
|
||||
if (rule->run_operation == KEY_OP_ASSIGN || rule->run_operation == KEY_OP_ASSIGN_FINAL) {
|
||||
struct name_entry *name_loop;
|
||||
struct name_entry *temp_loop;
|
||||
|
||||
info("reset run list");
|
||||
list_for_each_entry_safe(name_loop, temp_loop, &udev->run_list, node) {
|
||||
list_del(&name_loop->node);
|
||||
free(name_loop);
|
||||
}
|
||||
}
|
||||
if (rule->run[0] != '\0') {
|
||||
strlcpy(program, rule->run, sizeof(program));
|
||||
apply_format(udev, program, sizeof(program), class_dev, sysfs_device);
|
||||
dbg("add run '%s'", program);
|
||||
name_list_add(&udev->run_list, program, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (rule->last_rule) {
|
||||
@ -838,113 +995,58 @@ int udev_rules_get_name(struct udevice *udev, struct sysfs_class_device *class_d
|
||||
return 0;
|
||||
}
|
||||
|
||||
int udev_rules_get_run(struct udevice *udev)
|
||||
int udev_rules_get_run(struct udevice *udev, struct sysfs_device *sysfs_device)
|
||||
{
|
||||
struct udev_rule *rule;
|
||||
char program[PATH_SIZE];
|
||||
|
||||
/* look for a matching rule to apply */
|
||||
list_for_each_entry(rule, &udev_rule_list, node) {
|
||||
dbg("process rule");
|
||||
|
||||
if (rule->run[0] == '\0')
|
||||
if (rule->run_operation == KEY_OP_UNSET)
|
||||
continue;
|
||||
|
||||
if (rule->name[0] != '\0' || rule->symlink[0] != '\0' ||
|
||||
if (rule->name_operation != KEY_OP_UNSET || rule->symlink_operation != KEY_OP_UNSET ||
|
||||
rule->mode != 0000 || rule->owner[0] != '\0' || rule->group[0] != '\0') {
|
||||
dbg("skip rule that names a device");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rule->action_operation != KEY_OP_UNSET) {
|
||||
dbg("check for " KEY_ACTION " rule->action='%s' udev->action='%s'",
|
||||
rule->action, udev->action);
|
||||
if (strcmp_pattern(rule->action, udev->action) != 0) {
|
||||
dbg(KEY_ACTION " is not matching");
|
||||
if (rule->action_operation != KEY_OP_NOMATCH)
|
||||
continue;
|
||||
} else {
|
||||
dbg(KEY_ACTION " matches");
|
||||
if (rule->action_operation == KEY_OP_NOMATCH)
|
||||
continue;
|
||||
if (match_rule(udev, rule, NULL, sysfs_device) == 0) {
|
||||
if (rule->ignore_device) {
|
||||
info("configured rule in '%s[%i]' applied, '%s' is ignored",
|
||||
rule->config_file, rule->config_line, udev->kernel_name);
|
||||
udev->ignore_device = 1;
|
||||
return 0;
|
||||
}
|
||||
dbg(KEY_ACTION " key is true");
|
||||
}
|
||||
|
||||
if (rule->kernel_operation != KEY_OP_UNSET) {
|
||||
dbg("check for " KEY_KERNEL " rule->kernel='%s' udev->kernel_name='%s'",
|
||||
rule->kernel, udev->kernel_name);
|
||||
if (strcmp_pattern(rule->kernel, udev->kernel_name) != 0) {
|
||||
dbg(KEY_KERNEL " is not matching");
|
||||
if (rule->kernel_operation != KEY_OP_NOMATCH)
|
||||
continue;
|
||||
} else {
|
||||
dbg(KEY_KERNEL " matches");
|
||||
if (rule->kernel_operation == KEY_OP_NOMATCH)
|
||||
continue;
|
||||
}
|
||||
dbg(KEY_KERNEL " key is true");
|
||||
}
|
||||
if (!udev->run_final && rule->run_operation != KEY_OP_UNSET) {
|
||||
char program[PATH_SIZE];
|
||||
|
||||
if (rule->subsystem_operation != KEY_OP_UNSET) {
|
||||
dbg("check for " KEY_SUBSYSTEM " rule->subsystem='%s' udev->subsystem='%s'",
|
||||
rule->subsystem, udev->subsystem);
|
||||
if (strcmp_pattern(rule->subsystem, udev->subsystem) != 0) {
|
||||
dbg(KEY_SUBSYSTEM " is not matching");
|
||||
if (rule->subsystem_operation != KEY_OP_NOMATCH)
|
||||
continue;
|
||||
} else {
|
||||
dbg(KEY_SUBSYSTEM " matches");
|
||||
if (rule->subsystem_operation == KEY_OP_NOMATCH)
|
||||
continue;
|
||||
}
|
||||
dbg(KEY_SUBSYSTEM " key is true");
|
||||
}
|
||||
if (rule->run_operation == KEY_OP_ASSIGN || rule->run_operation == KEY_OP_ASSIGN_FINAL) {
|
||||
struct name_entry *name_loop;
|
||||
struct name_entry *temp_loop;
|
||||
|
||||
if (rule->env_pair_count) {
|
||||
int i;
|
||||
|
||||
dbg("check for " KEY_ENV " pairs");
|
||||
for (i = 0; i < rule->env_pair_count; i++) {
|
||||
struct key_pair *pair;
|
||||
const char *value;
|
||||
|
||||
pair = &rule->env_pair[i];
|
||||
value = getenv(pair->name);
|
||||
if (!value) {
|
||||
dbg(KEY_ENV "{'%s'} is not found", pair->name);
|
||||
continue;
|
||||
info("reset run list");
|
||||
list_for_each_entry_safe(name_loop, temp_loop, &udev->run_list, node) {
|
||||
list_del(&name_loop->node);
|
||||
free(name_loop);
|
||||
}
|
||||
}
|
||||
if (strcmp_pattern(pair->value, value) != 0) {
|
||||
dbg(KEY_ENV "{'%s'} is not matching", pair->name);
|
||||
if (pair->operation != KEY_OP_NOMATCH)
|
||||
continue;
|
||||
} else {
|
||||
dbg(KEY_ENV "{'%s'} matches", pair->name);
|
||||
if (pair->operation == KEY_OP_NOMATCH)
|
||||
continue;
|
||||
if (rule->run[0] != '\0') {
|
||||
strlcpy(program, rule->run, sizeof(program));
|
||||
apply_format(udev, program, sizeof(program), NULL, sysfs_device);
|
||||
dbg("add run '%s'", program);
|
||||
name_list_add(&udev->run_list, program, 0);
|
||||
}
|
||||
if (rule->run_operation == KEY_OP_ASSIGN_FINAL)
|
||||
break;
|
||||
}
|
||||
dbg(KEY_ENV " key is true");
|
||||
}
|
||||
|
||||
/* rule matches */
|
||||
|
||||
if (rule->ignore_device) {
|
||||
info("configured rule in '%s[%i]' applied, '%s' is ignored",
|
||||
rule->config_file, rule->config_line, udev->kernel_name);
|
||||
udev->ignore_device = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
strlcpy(program, rule->run, sizeof(program));
|
||||
apply_format(udev, program, sizeof(program), NULL, NULL);
|
||||
dbg("add run '%s'", program);
|
||||
name_list_add(&udev->run_list, program, 0);
|
||||
|
||||
if (rule->last_rule) {
|
||||
dbg("last rule to be applied");
|
||||
break;
|
||||
if (rule->last_rule) {
|
||||
dbg("last rule to be applied");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
15
udev_rules.h
15
udev_rules.h
@ -31,6 +31,7 @@
|
||||
#define KEY_KERNEL "KERNEL"
|
||||
#define KEY_SUBSYSTEM "SUBSYSTEM"
|
||||
#define KEY_ACTION "ACTION"
|
||||
#define KEY_DEVPATH "DEVPATH"
|
||||
#define KEY_BUS "BUS"
|
||||
#define KEY_ID "ID"
|
||||
#define KEY_PROGRAM "PROGRAM"
|
||||
@ -38,6 +39,7 @@
|
||||
#define KEY_DRIVER "DRIVER"
|
||||
#define KEY_SYSFS "SYSFS"
|
||||
#define KEY_ENV "ENV"
|
||||
#define KEY_MODALIAS "MODALIAS"
|
||||
#define KEY_NAME "NAME"
|
||||
#define KEY_SYMLINK "SYMLINK"
|
||||
#define KEY_OWNER "OWNER"
|
||||
@ -62,6 +64,7 @@ enum key_operation {
|
||||
KEY_OP_NOMATCH,
|
||||
KEY_OP_ADD,
|
||||
KEY_OP_ASSIGN,
|
||||
KEY_OP_ASSIGN_FINAL,
|
||||
};
|
||||
|
||||
struct key_pair {
|
||||
@ -79,6 +82,8 @@ struct udev_rule {
|
||||
enum key_operation subsystem_operation;
|
||||
char action[NAME_SIZE];
|
||||
enum key_operation action_operation;
|
||||
char devpath[PATH_SIZE];
|
||||
enum key_operation devpath_operation;
|
||||
char bus[NAME_SIZE];
|
||||
enum key_operation bus_operation;
|
||||
char id[NAME_SIZE];
|
||||
@ -93,13 +98,21 @@ struct udev_rule {
|
||||
int sysfs_pair_count;
|
||||
struct key_pair env_pair[KEY_ENV_PAIRS_MAX];
|
||||
int env_pair_count;
|
||||
enum key_operation modalias_operation;
|
||||
char modalias[PATH_SIZE];
|
||||
|
||||
char name[PATH_SIZE];
|
||||
enum key_operation name_operation;
|
||||
char symlink[PATH_SIZE];
|
||||
enum key_operation symlink_operation;
|
||||
char owner[USER_SIZE];
|
||||
enum key_operation owner_operation;
|
||||
char group[USER_SIZE];
|
||||
enum key_operation group_operation;
|
||||
mode_t mode;
|
||||
enum key_operation mode_operation;
|
||||
char run[PATH_SIZE];
|
||||
enum key_operation run_operation;
|
||||
|
||||
int last_rule;
|
||||
int ignore_device;
|
||||
@ -114,7 +127,7 @@ extern struct list_head udev_rule_list;
|
||||
|
||||
extern int udev_rules_init(void);
|
||||
extern int udev_rules_get_name(struct udevice *udev, struct sysfs_class_device *class_dev);
|
||||
extern int udev_rules_get_run(struct udevice *udev);
|
||||
extern int udev_rules_get_run(struct udevice *udev, struct sysfs_device *sysfs_device);
|
||||
extern void udev_rules_close(void);
|
||||
|
||||
#endif
|
||||
|
@ -89,6 +89,8 @@ static int get_key(char **line, char **key, enum key_operation *operation, char
|
||||
break;
|
||||
if (linepos[0] == '!')
|
||||
break;
|
||||
if (linepos[0] == ':')
|
||||
break;
|
||||
}
|
||||
|
||||
/* remember end of key */
|
||||
@ -115,6 +117,10 @@ static int get_key(char **line, char **key, enum key_operation *operation, char
|
||||
*operation = KEY_OP_ASSIGN;
|
||||
linepos++;
|
||||
dbg("operator=assign");
|
||||
} else if (linepos[0] == ':' && linepos[1] == '=') {
|
||||
*operation = KEY_OP_ASSIGN_FINAL;
|
||||
linepos += 2;
|
||||
dbg("operator=assign_final");
|
||||
} else
|
||||
return -1;
|
||||
|
||||
@ -263,6 +269,13 @@ static int rules_parse(const char *filename)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcasecmp(key, KEY_DEVPATH) == 0) {
|
||||
strlcpy(rule.devpath, value, sizeof(rule.devpath));
|
||||
rule.devpath_operation = operation;
|
||||
valid = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcasecmp(key, KEY_BUS) == 0) {
|
||||
strlcpy(rule.bus, value, sizeof(rule.bus));
|
||||
rule.bus_operation = operation;
|
||||
@ -319,6 +332,13 @@ static int rules_parse(const char *filename)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcasecmp(key, KEY_MODALIAS) == 0) {
|
||||
strlcpy(rule.modalias, value, sizeof(rule.modalias));
|
||||
rule.modalias_operation = operation;
|
||||
valid = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcasecmp(key, KEY_DRIVER) == 0) {
|
||||
strlcpy(rule.driver, value, sizeof(rule.driver));
|
||||
rule.driver_operation = operation;
|
||||
@ -343,51 +363,54 @@ static int rules_parse(const char *filename)
|
||||
|
||||
if (strncasecmp(key, KEY_NAME, sizeof(KEY_NAME)-1) == 0) {
|
||||
attr = get_key_attribute(key + sizeof(KEY_NAME)-1);
|
||||
/* FIXME: remove old style options and make OPTIONS= mandatory */
|
||||
if (attr != NULL) {
|
||||
if (strstr(attr, OPTION_PARTITIONS) != NULL) {
|
||||
dbg("creation of partition nodes requested");
|
||||
rule.partitions = DEFAULT_PARTITIONS_COUNT;
|
||||
}
|
||||
/* FIXME: remove old style option and make OPTIONS= mandatory */
|
||||
if (strstr(attr, OPTION_IGNORE_REMOVE) != NULL) {
|
||||
dbg("remove event should be ignored");
|
||||
rule.ignore_remove = 1;
|
||||
}
|
||||
}
|
||||
if (value[0] != '\0')
|
||||
strlcpy(rule.name, value, sizeof(rule.name));
|
||||
else
|
||||
rule.ignore_device = 1;
|
||||
rule.name_operation = operation;
|
||||
strlcpy(rule.name, value, sizeof(rule.name));
|
||||
valid = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcasecmp(key, KEY_SYMLINK) == 0) {
|
||||
strlcpy(rule.symlink, value, sizeof(rule.symlink));
|
||||
rule.symlink_operation = operation;
|
||||
valid = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcasecmp(key, KEY_OWNER) == 0) {
|
||||
strlcpy(rule.owner, value, sizeof(rule.owner));
|
||||
rule.owner_operation = operation;
|
||||
valid = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcasecmp(key, KEY_GROUP) == 0) {
|
||||
strlcpy(rule.group, value, sizeof(rule.group));
|
||||
rule.group_operation = operation;
|
||||
valid = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcasecmp(key, KEY_MODE) == 0) {
|
||||
rule.mode = strtol(value, NULL, 8);
|
||||
rule.mode_operation = operation;
|
||||
valid = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcasecmp(key, KEY_RUN) == 0) {
|
||||
strlcpy(rule.run, value, sizeof(rule.run));
|
||||
rule.run_operation = operation;
|
||||
valid = 1;
|
||||
continue;
|
||||
}
|
||||
|
54
udev_sysfs.c
54
udev_sysfs.c
@ -297,38 +297,38 @@ int wait_for_devices_device(struct sysfs_device *devices_dev,
|
||||
{ .bus = "usb", .file = "idVendor" },
|
||||
{ .bus = "usb", .file = "iInterface" },
|
||||
{ .bus = "usb", .file = "bNumEndpoints" },
|
||||
{ .bus = "usb-serial", .file = "detach_state" },
|
||||
{ .bus = "ide", .file = "detach_state" },
|
||||
{ .bus = "usb-serial", .file = "power" },
|
||||
{ .bus = "ide", .file = "power" },
|
||||
{ .bus = "pci", .file = "vendor" },
|
||||
{ .bus = "platform", .file = "detach_state" },
|
||||
{ .bus = "pcmcia", .file = "detach_state" },
|
||||
{ .bus = "i2c", .file = "detach_state" },
|
||||
{ .bus = "platform", .file = "power" },
|
||||
{ .bus = "pcmcia", .file = "power" },
|
||||
{ .bus = "i2c", .file = "power" },
|
||||
{ .bus = "ieee1394", .file = "node_count" },
|
||||
{ .bus = "ieee1394", .file = "nodeid" },
|
||||
{ .bus = "ieee1394", .file = "address" },
|
||||
{ .bus = "bttv-sub", .file = NULL },
|
||||
{ .bus = "pnp", .file = "detach_state" },
|
||||
{ .bus = "eisa", .file = "detach_state" },
|
||||
{ .bus = "serio", .file = "detach_state" },
|
||||
{ .bus = "pseudo", .file = "detach_state" },
|
||||
{ .bus = "mmc", .file = "detach_state" },
|
||||
{ .bus = "macio", .file = "detach_state" },
|
||||
{ .bus = "of_platform", .file = "detach_state" },
|
||||
{ .bus = "vio", .file = "detach_state" },
|
||||
{ .bus = "ecard", .file = "detach_state" },
|
||||
{ .bus = "sa1111-rab", .file = "detach_state" },
|
||||
{ .bus = "amba", .file = "detach_state" },
|
||||
{ .bus = "locomo-bus", .file = "detach_state" },
|
||||
{ .bus = "logicmodule", .file = "detach_state" },
|
||||
{ .bus = "parisc", .file = "detach_state" },
|
||||
{ .bus = "ocp", .file = "detach_state" },
|
||||
{ .bus = "dio", .file = "detach_state" },
|
||||
{ .bus = "MCA", .file = "detach_state" },
|
||||
{ .bus = "wl", .file = "detach_state" },
|
||||
{ .bus = "ccwgroup", .file = "detach_state" },
|
||||
{ .bus = "css", .file = "detach_state" },
|
||||
{ .bus = "ccw", .file = "detach_state" },
|
||||
{ .bus = "iucv", .file = "detach_state" },
|
||||
{ .bus = "pnp", .file = "power" },
|
||||
{ .bus = "eisa", .file = "power" },
|
||||
{ .bus = "serio", .file = "power" },
|
||||
{ .bus = "pseudo", .file = "power" },
|
||||
{ .bus = "mmc", .file = "power" },
|
||||
{ .bus = "macio", .file = "power" },
|
||||
{ .bus = "of_platform", .file = "power" },
|
||||
{ .bus = "vio", .file = "power" },
|
||||
{ .bus = "ecard", .file = "power" },
|
||||
{ .bus = "sa1111-rab", .file = "power" },
|
||||
{ .bus = "amba", .file = "power" },
|
||||
{ .bus = "locomo-bus", .file = "power" },
|
||||
{ .bus = "logicmodule", .file = "power" },
|
||||
{ .bus = "parisc", .file = "power" },
|
||||
{ .bus = "ocp", .file = "power" },
|
||||
{ .bus = "dio", .file = "power" },
|
||||
{ .bus = "MCA", .file = "power" },
|
||||
{ .bus = "wl", .file = "power" },
|
||||
{ .bus = "ccwgroup", .file = "power" },
|
||||
{ .bus = "css", .file = "power" },
|
||||
{ .bus = "ccw", .file = "power" },
|
||||
{ .bus = "iucv", .file = "power" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
const struct device_file *devicefile = NULL;
|
||||
|
40
udev_utils.c
40
udev_utils.c
@ -27,6 +27,7 @@
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
#include <syslog.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
@ -107,6 +108,41 @@ void udev_cleanup_device(struct udevice *udev)
|
||||
list_del(&name_loop->node);
|
||||
free(name_loop);
|
||||
}
|
||||
list_for_each_entry_safe(name_loop, temp_loop, &udev->run_list, node) {
|
||||
list_del(&name_loop->node);
|
||||
free(name_loop);
|
||||
}
|
||||
}
|
||||
|
||||
int string_is_true(const char *str)
|
||||
{
|
||||
if (strcasecmp(str, "true") == 0)
|
||||
return 1;
|
||||
if (strcasecmp(str, "yes") == 0)
|
||||
return 1;
|
||||
if (strcasecmp(str, "1") == 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int log_priority(const char *priority)
|
||||
{
|
||||
char *endptr;
|
||||
int prio;
|
||||
|
||||
prio = strtol(priority, &endptr, 10);
|
||||
if (endptr[0] == '\0')
|
||||
return prio;
|
||||
if (strncasecmp(priority, "err", 3) == 0)
|
||||
return LOG_ERR;
|
||||
if (strcasecmp(priority, "info") == 0)
|
||||
return LOG_INFO;
|
||||
if (strcasecmp(priority, "debug") == 0)
|
||||
return LOG_DEBUG;
|
||||
if (string_is_true(priority))
|
||||
return LOG_ERR;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kernel_release_satisfactory(unsigned int version, unsigned int patchlevel, unsigned int sublevel)
|
||||
@ -373,10 +409,10 @@ int execute_command(const char *command, const char *subsystem)
|
||||
close(devnull);
|
||||
}
|
||||
retval = execv(arg, argv);
|
||||
err("exec of child failed");
|
||||
err("exec of child '%s' failed", command);
|
||||
_exit(1);
|
||||
case -1:
|
||||
dbg("fork of child failed");
|
||||
dbg("fork of child '%s' failed", command);
|
||||
break;
|
||||
return -1;
|
||||
default:
|
||||
|
@ -34,6 +34,8 @@ extern void udev_cleanup_device(struct udevice *udev);
|
||||
|
||||
extern int kernel_release_satisfactory(unsigned int version, unsigned int patchlevel, unsigned int sublevel);
|
||||
extern int create_path(const char *path);
|
||||
extern int log_priority(const char *priority);
|
||||
extern int string_is_true(const char *str);
|
||||
extern int parse_get_pair(char **orig_string, char **left, char **right);
|
||||
extern int unlink_secure(const char *filename);
|
||||
extern int file_map(const char *filename, char **buf, size_t *bufsize);
|
||||
|
136
udevcontrol.c
Normal file
136
udevcontrol.c
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* udevcontrol.c
|
||||
*
|
||||
* Userspace devfs
|
||||
*
|
||||
* Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation version 2 of the License.
|
||||
*
|
||||
* 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 GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/un.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/stddef.h>
|
||||
|
||||
#include "udev.h"
|
||||
#include "udev_version.h"
|
||||
#include "udevd.h"
|
||||
#include "udev_utils.h"
|
||||
#include "logging.h"
|
||||
|
||||
/* global variables */
|
||||
static int sock = -1;
|
||||
static int log = 0;
|
||||
|
||||
#ifdef USE_LOG
|
||||
void log_message (int priority, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (priority > log)
|
||||
return;
|
||||
|
||||
va_start(args, format);
|
||||
vsyslog(priority, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int main(int argc, char *argv[], char *envp[])
|
||||
{
|
||||
static struct udevd_msg usend_msg;
|
||||
struct sockaddr_un saddr;
|
||||
socklen_t addrlen;
|
||||
const char *env;
|
||||
const char *val;
|
||||
int *intval;
|
||||
int retval = 1;
|
||||
|
||||
env = getenv("UDEV_LOG");
|
||||
if (env)
|
||||
log = log_priority(env);
|
||||
|
||||
logging_init("udevcontrol");
|
||||
dbg("version %s", UDEV_VERSION);
|
||||
|
||||
if (argc != 2) {
|
||||
err("error finding comand");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
memset(&usend_msg, 0x00, sizeof(struct udevd_msg));
|
||||
strcpy(usend_msg.magic, UDEV_MAGIC);
|
||||
|
||||
if (!strcmp(argv[1], "stop_exec_queue"))
|
||||
usend_msg.type = UDEVD_STOP_EXEC_QUEUE;
|
||||
else if (!strcmp(argv[1], "start_exec_queue"))
|
||||
usend_msg.type = UDEVD_START_EXEC_QUEUE;
|
||||
else if (!strncmp(argv[1], "log_priority=", strlen("log_priority="))) {
|
||||
intval = (int *) usend_msg.envbuf;
|
||||
val = &argv[1][strlen("log_priority=")];
|
||||
usend_msg.type = UDEVD_SET_LOG_LEVEL;
|
||||
*intval = log_priority(val);
|
||||
info("send log_priority=%i", *intval);
|
||||
} else if (!strncmp(argv[1], "max_childs=", strlen("max_childs="))) {
|
||||
intval = (int *) usend_msg.envbuf;
|
||||
val = &argv[1][strlen("max_childs=")];
|
||||
usend_msg.type = UDEVD_SET_MAX_CHILDS;
|
||||
*intval = atoi(val);
|
||||
info("send max_childs=%i", *intval);
|
||||
} else {
|
||||
err("error parsing command\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
sock = socket(AF_LOCAL, SOCK_DGRAM, 0);
|
||||
if (sock == -1) {
|
||||
err("error getting socket");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
memset(&saddr, 0x00, sizeof(struct sockaddr_un));
|
||||
saddr.sun_family = AF_LOCAL;
|
||||
/* use abstract namespace for socket path */
|
||||
strcpy(&saddr.sun_path[1], UDEVD_SOCK_PATH);
|
||||
addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(saddr.sun_path+1) + 1;
|
||||
|
||||
|
||||
retval = sendto(sock, &usend_msg, sizeof(usend_msg), 0, (struct sockaddr *)&saddr, addrlen);
|
||||
if (retval == -1) {
|
||||
info("error sending message (%s)", strerror(errno));
|
||||
retval = 1;
|
||||
} else {
|
||||
dbg("sent message type=0x%02x, %u bytes sent", usend_msg.type, retval);
|
||||
retval = 0;
|
||||
}
|
||||
|
||||
close(sock);
|
||||
|
||||
exit:
|
||||
logging_close();
|
||||
|
||||
return retval;
|
||||
}
|
481
udevd.c
481
udevd.c
@ -38,6 +38,7 @@
|
||||
#include <sys/un.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include <sys/stat.h>
|
||||
#include <linux/netlink.h>
|
||||
|
||||
#include "list.h"
|
||||
#include "udev_libc_wrapper.h"
|
||||
@ -48,16 +49,17 @@
|
||||
#include "logging.h"
|
||||
|
||||
/* global variables*/
|
||||
static int udevsendsock;
|
||||
static int udevd_sock;
|
||||
static int uevent_netlink_sock;
|
||||
static pid_t sid;
|
||||
|
||||
static int pipefds[2];
|
||||
static long startup_time;
|
||||
static unsigned long long expected_seqnum = 0;
|
||||
static volatile int sigchilds_waiting;
|
||||
static volatile int run_msg_q;
|
||||
static volatile int sig_flag;
|
||||
static int init_phase = 1;
|
||||
static int run_exec_q;
|
||||
static int stop_exec_q;
|
||||
|
||||
static LIST_HEAD(msg_list);
|
||||
static LIST_HEAD(exec_list);
|
||||
@ -67,7 +69,13 @@ static void exec_queue_manager(void);
|
||||
static void msg_queue_manager(void);
|
||||
static void user_sighandler(void);
|
||||
static void reap_sigchilds(void);
|
||||
char *udev_bin;
|
||||
|
||||
static char *udev_bin;
|
||||
static unsigned long long expected_seqnum;
|
||||
static int event_timeout;
|
||||
static int max_childs;
|
||||
static int max_childs_running;
|
||||
|
||||
|
||||
#ifdef USE_LOG
|
||||
void log_message (int priority, const char *format, ...)
|
||||
@ -86,23 +94,23 @@ void log_message (int priority, const char *format, ...)
|
||||
static void msg_dump_queue(void)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
struct hotplug_msg *msg;
|
||||
struct uevent_msg *msg;
|
||||
|
||||
list_for_each_entry(msg, &msg_list, node)
|
||||
dbg("sequence %llu in queue", msg->seqnum);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void run_queue_delete(struct hotplug_msg *msg)
|
||||
static void run_queue_delete(struct uevent_msg *msg)
|
||||
{
|
||||
list_del(&msg->node);
|
||||
free(msg);
|
||||
}
|
||||
|
||||
/* orders the message in the queue by sequence number */
|
||||
static void msg_queue_insert(struct hotplug_msg *msg)
|
||||
static void msg_queue_insert(struct uevent_msg *msg)
|
||||
{
|
||||
struct hotplug_msg *loop_msg;
|
||||
struct uevent_msg *loop_msg;
|
||||
struct sysinfo info;
|
||||
|
||||
if (msg->seqnum == 0) {
|
||||
@ -112,6 +120,20 @@ static void msg_queue_insert(struct hotplug_msg *msg)
|
||||
return;
|
||||
}
|
||||
|
||||
/* store timestamp of queuing */
|
||||
sysinfo(&info);
|
||||
msg->queue_time = info.uptime;
|
||||
|
||||
/* with the first event we provide a phase of shorter timeout */
|
||||
if (init_phase) {
|
||||
static long init_time;
|
||||
|
||||
if (init_time == 0)
|
||||
init_time = info.uptime;
|
||||
if (info.uptime - init_time >= UDEVD_INIT_TIME)
|
||||
init_phase = 0;
|
||||
}
|
||||
|
||||
/* don't delay messages with timeout set */
|
||||
if (msg->timeout) {
|
||||
dbg("move seq %llu with timeout %u to exec queue", msg->seqnum, msg->timeout);
|
||||
@ -126,17 +148,13 @@ static void msg_queue_insert(struct hotplug_msg *msg)
|
||||
break;
|
||||
|
||||
if (loop_msg->seqnum == msg->seqnum) {
|
||||
info("ignoring duplicate message seq %llu", msg->seqnum);
|
||||
dbg("ignoring duplicate message seq %llu", msg->seqnum);
|
||||
free(msg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* store timestamp of queuing */
|
||||
sysinfo(&info);
|
||||
msg->queue_time = info.uptime;
|
||||
|
||||
list_add(&msg->node, &loop_msg->node);
|
||||
dbg("queued message seq %llu", msg->seqnum);
|
||||
info("seq %llu queued, devpath '%s'", msg->seqnum, msg->devpath);
|
||||
|
||||
/* run msg queue manager */
|
||||
run_msg_q = 1;
|
||||
@ -145,16 +163,19 @@ static void msg_queue_insert(struct hotplug_msg *msg)
|
||||
}
|
||||
|
||||
/* forks event and removes event from run queue when finished */
|
||||
static void execute_udev(struct hotplug_msg *msg)
|
||||
static void execute_udev(struct uevent_msg *msg)
|
||||
{
|
||||
char *const argv[] = { "udev", msg->subsystem, NULL };
|
||||
pid_t pid;
|
||||
struct sysinfo info;
|
||||
|
||||
pid = fork();
|
||||
switch (pid) {
|
||||
case 0:
|
||||
/* child */
|
||||
close(udevsendsock);
|
||||
if (uevent_netlink_sock != -1)
|
||||
close(uevent_netlink_sock);
|
||||
close(udevd_sock);
|
||||
logging_close();
|
||||
|
||||
setpriority(PRIO_PROCESS, 0, UDEV_PRIORITY);
|
||||
@ -168,7 +189,9 @@ static void execute_udev(struct hotplug_msg *msg)
|
||||
break;
|
||||
default:
|
||||
/* get SIGCHLD in main loop */
|
||||
dbg("==> exec seq %llu [%d] working at '%s'", msg->seqnum, pid, msg->devpath);
|
||||
sysinfo(&info);
|
||||
info("seq %llu forked, pid %d, %ld seconds old",
|
||||
msg->seqnum, pid, info.uptime - msg->queue_time);
|
||||
msg->pid = pid;
|
||||
}
|
||||
}
|
||||
@ -293,73 +316,84 @@ static int compare_devpath(const char *running, const char *waiting)
|
||||
}
|
||||
|
||||
/* returns still running task for the same device, its parent or its physical device */
|
||||
static struct hotplug_msg *running_with_devpath(struct hotplug_msg *msg)
|
||||
static int running_with_devpath(struct uevent_msg *msg, int limit)
|
||||
{
|
||||
struct hotplug_msg *loop_msg;
|
||||
struct uevent_msg *loop_msg;
|
||||
int childs_count = 0;
|
||||
|
||||
if (msg->devpath == NULL)
|
||||
return NULL;
|
||||
return 0;
|
||||
|
||||
/* skip any events with a timeout set */
|
||||
if (msg->timeout)
|
||||
return NULL;
|
||||
if (msg->timeout != 0)
|
||||
return 0;
|
||||
|
||||
list_for_each_entry(loop_msg, &running_list, node) {
|
||||
if (limit && childs_count++ > limit) {
|
||||
dbg("%llu, maximum number (%i) of child reached", msg->seqnum, childs_count);
|
||||
return 1;
|
||||
}
|
||||
if (loop_msg->devpath == NULL)
|
||||
continue;
|
||||
|
||||
/* return running parent/child device event */
|
||||
if (compare_devpath(loop_msg->devpath, msg->devpath) != 0)
|
||||
return loop_msg;
|
||||
if (compare_devpath(loop_msg->devpath, msg->devpath) != 0) {
|
||||
dbg("%llu, child device event still running %llu (%s)",
|
||||
msg->seqnum, loop_msg->seqnum, loop_msg->devpath);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* return running physical device event */
|
||||
if (msg->physdevpath && msg->action && strcmp(msg->action, "add") == 0)
|
||||
if (compare_devpath(loop_msg->devpath, msg->physdevpath) != 0)
|
||||
return loop_msg;
|
||||
if (compare_devpath(loop_msg->devpath, msg->physdevpath) != 0) {
|
||||
dbg("%llu, physical device event still running %llu (%s)",
|
||||
msg->seqnum, loop_msg->seqnum, loop_msg->devpath);
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* exec queue management routine executes the events and serializes events in the same sequence */
|
||||
static void exec_queue_manager(void)
|
||||
{
|
||||
struct hotplug_msg *loop_msg;
|
||||
struct hotplug_msg *tmp_msg;
|
||||
struct hotplug_msg *msg;
|
||||
struct uevent_msg *loop_msg;
|
||||
struct uevent_msg *tmp_msg;
|
||||
int running;
|
||||
|
||||
if (list_empty(&exec_list))
|
||||
return;
|
||||
|
||||
running = running_processes();
|
||||
dbg("%d processes runnning on system", running);
|
||||
if (running < 0)
|
||||
running = THROTTLE_MAX_RUNNING_CHILDS;
|
||||
running = max_childs_running;
|
||||
|
||||
list_for_each_entry_safe(loop_msg, tmp_msg, &exec_list, node) {
|
||||
/* check running processes in our session and possibly throttle */
|
||||
if (running >= THROTTLE_MAX_RUNNING_CHILDS) {
|
||||
running = running_processes_in_session(sid, THROTTLE_MAX_RUNNING_CHILDS+10);
|
||||
dbg("%d processes running in session", running);
|
||||
if (running >= THROTTLE_MAX_RUNNING_CHILDS) {
|
||||
dbg("delay seq %llu, cause too many processes already running", loop_msg->seqnum);
|
||||
if (running >= max_childs_running) {
|
||||
running = running_processes_in_session(sid, max_childs_running+10);
|
||||
dbg("at least %d processes running in session", running);
|
||||
if (running >= max_childs_running) {
|
||||
dbg("delay seq %llu, cause too many processes already running",
|
||||
loop_msg->seqnum);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
msg = running_with_devpath(loop_msg);
|
||||
if (!msg) {
|
||||
if (running_with_devpath(loop_msg, max_childs) == 0) {
|
||||
/* move event to run list */
|
||||
list_move_tail(&loop_msg->node, &running_list);
|
||||
execute_udev(loop_msg);
|
||||
running++;
|
||||
dbg("moved seq %llu to running list", loop_msg->seqnum);
|
||||
} else {
|
||||
dbg("delay seq %llu (%s), cause seq %llu (%s) is still running",
|
||||
loop_msg->seqnum, loop_msg->devpath, msg->seqnum, msg->devpath);
|
||||
}
|
||||
} else
|
||||
dbg("delay seq %llu (%s)", loop_msg->seqnum, loop_msg->devpath);
|
||||
}
|
||||
}
|
||||
|
||||
static void msg_move_exec(struct hotplug_msg *msg)
|
||||
static void msg_move_exec(struct uevent_msg *msg)
|
||||
{
|
||||
list_move_tail(&msg->node, &exec_list);
|
||||
run_exec_q = 1;
|
||||
@ -371,15 +405,15 @@ static void msg_move_exec(struct hotplug_msg *msg)
|
||||
/* msg queue management routine handles the timeouts and dispatches the events */
|
||||
static void msg_queue_manager(void)
|
||||
{
|
||||
struct hotplug_msg *loop_msg;
|
||||
struct hotplug_msg *tmp_msg;
|
||||
struct uevent_msg *loop_msg;
|
||||
struct uevent_msg *tmp_msg;
|
||||
struct sysinfo info;
|
||||
long msg_age = 0;
|
||||
static int timeout = EVENT_INIT_TIMEOUT_SEC;
|
||||
static int init = 1;
|
||||
int timeout = event_timeout;
|
||||
|
||||
dbg("msg queue manager, next expected is %llu", expected_seqnum);
|
||||
recheck:
|
||||
sysinfo(&info);
|
||||
list_for_each_entry_safe(loop_msg, tmp_msg, &msg_list, node) {
|
||||
/* move event with expected sequence to the exec list */
|
||||
if (loop_msg->seqnum == expected_seqnum) {
|
||||
@ -387,15 +421,13 @@ recheck:
|
||||
continue;
|
||||
}
|
||||
|
||||
/* see if we are in the initialization phase and wait for the very first events */
|
||||
if (init && (info.uptime - startup_time >= INIT_TIME_SEC)) {
|
||||
init = 0;
|
||||
timeout = EVENT_TIMEOUT_SEC;
|
||||
dbg("initialization phase passed, set timeout to %i seconds", EVENT_TIMEOUT_SEC);
|
||||
/* limit timeout during initialization phase */
|
||||
if (init_phase) {
|
||||
timeout = UDEVD_INIT_EVENT_TIMEOUT;
|
||||
dbg("initialization phase, limit timeout to %i seconds", UDEVD_INIT_EVENT_TIMEOUT);
|
||||
}
|
||||
|
||||
/* move event with expired timeout to the exec list */
|
||||
sysinfo(&info);
|
||||
msg_age = info.uptime - loop_msg->queue_time;
|
||||
dbg("seq %llu is %li seconds old", loop_msg->seqnum, msg_age);
|
||||
if (msg_age >= timeout) {
|
||||
@ -416,67 +448,21 @@ recheck:
|
||||
}
|
||||
}
|
||||
|
||||
/* receive the udevsend message and do some sanity checks */
|
||||
static struct hotplug_msg *get_udevsend_msg(void)
|
||||
static struct uevent_msg *get_msg_from_envbuf(const char *buf, int buf_size)
|
||||
{
|
||||
static struct udevsend_msg usend_msg;
|
||||
struct hotplug_msg *msg;
|
||||
int bufpos;
|
||||
int i;
|
||||
ssize_t size;
|
||||
struct msghdr smsg;
|
||||
struct cmsghdr *cmsg;
|
||||
struct iovec iov;
|
||||
struct ucred *cred;
|
||||
char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
|
||||
int envbuf_size;
|
||||
struct uevent_msg *msg;
|
||||
|
||||
memset(&usend_msg, 0x00, sizeof(struct udevsend_msg));
|
||||
iov.iov_base = &usend_msg;
|
||||
iov.iov_len = sizeof(struct udevsend_msg);
|
||||
|
||||
memset(&smsg, 0x00, sizeof(struct msghdr));
|
||||
smsg.msg_iov = &iov;
|
||||
smsg.msg_iovlen = 1;
|
||||
smsg.msg_control = cred_msg;
|
||||
smsg.msg_controllen = sizeof(cred_msg);
|
||||
|
||||
size = recvmsg(udevsendsock, &smsg, 0);
|
||||
if (size < 0) {
|
||||
if (errno != EINTR)
|
||||
dbg("unable to receive udevsend message");
|
||||
return NULL;
|
||||
}
|
||||
cmsg = CMSG_FIRSTHDR(&smsg);
|
||||
cred = (struct ucred *) CMSG_DATA(cmsg);
|
||||
|
||||
if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
|
||||
info("no sender credentials received, message ignored");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (cred->uid != 0) {
|
||||
info("sender uid=%i, message ignored", cred->uid);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (strncmp(usend_msg.magic, UDEV_MAGIC, sizeof(UDEV_MAGIC)) != 0 ) {
|
||||
info("message magic '%s' doesn't match, ignore it", usend_msg.magic);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
envbuf_size = size - offsetof(struct udevsend_msg, envbuf);
|
||||
dbg("envbuf_size=%i", envbuf_size);
|
||||
msg = malloc(sizeof(struct hotplug_msg) + envbuf_size);
|
||||
msg = malloc(sizeof(struct uevent_msg) + buf_size);
|
||||
if (msg == NULL)
|
||||
return NULL;
|
||||
|
||||
memset(msg, 0x00, sizeof(struct hotplug_msg) + envbuf_size);
|
||||
memset(msg, 0x00, sizeof(struct uevent_msg) + buf_size);
|
||||
|
||||
/* copy environment buffer and reconstruct envp */
|
||||
memcpy(msg->envbuf, usend_msg.envbuf, envbuf_size);
|
||||
memcpy(msg->envbuf, buf, buf_size);
|
||||
bufpos = 0;
|
||||
for (i = 0; (bufpos < envbuf_size) && (i < HOTPLUG_NUM_ENVP-2); i++) {
|
||||
for (i = 0; (bufpos < buf_size) && (i < UEVENT_NUM_ENVP-2); i++) {
|
||||
int keylen;
|
||||
char *key;
|
||||
|
||||
@ -511,6 +497,142 @@ static struct hotplug_msg *get_udevsend_msg(void)
|
||||
return msg;
|
||||
}
|
||||
|
||||
/* receive the udevd message from userspace */
|
||||
static struct uevent_msg *get_udevd_msg(void)
|
||||
{
|
||||
static struct udevd_msg usend_msg;
|
||||
struct uevent_msg *msg;
|
||||
ssize_t size;
|
||||
struct msghdr smsg;
|
||||
struct cmsghdr *cmsg;
|
||||
struct iovec iov;
|
||||
struct ucred *cred;
|
||||
char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
|
||||
int envbuf_size;
|
||||
int *intval;
|
||||
|
||||
memset(&usend_msg, 0x00, sizeof(struct udevd_msg));
|
||||
iov.iov_base = &usend_msg;
|
||||
iov.iov_len = sizeof(struct udevd_msg);
|
||||
|
||||
memset(&smsg, 0x00, sizeof(struct msghdr));
|
||||
smsg.msg_iov = &iov;
|
||||
smsg.msg_iovlen = 1;
|
||||
smsg.msg_control = cred_msg;
|
||||
smsg.msg_controllen = sizeof(cred_msg);
|
||||
|
||||
size = recvmsg(udevd_sock, &smsg, 0);
|
||||
if (size < 0) {
|
||||
if (errno != EINTR)
|
||||
dbg("unable to receive udevd message");
|
||||
return NULL;
|
||||
}
|
||||
cmsg = CMSG_FIRSTHDR(&smsg);
|
||||
cred = (struct ucred *) CMSG_DATA(cmsg);
|
||||
|
||||
if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
|
||||
info("no sender credentials received, message ignored");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (cred->uid != 0) {
|
||||
info("sender uid=%i, message ignored", cred->uid);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (strncmp(usend_msg.magic, UDEV_MAGIC, sizeof(UDEV_MAGIC)) != 0 ) {
|
||||
info("message magic '%s' doesn't match, ignore it", usend_msg.magic);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (usend_msg.type) {
|
||||
case UDEVD_UEVENT_UDEVSEND:
|
||||
case UDEVD_UEVENT_INITSEND:
|
||||
info("udevd event message received");
|
||||
envbuf_size = size - offsetof(struct udevd_msg, envbuf);
|
||||
dbg("envbuf_size=%i", envbuf_size);
|
||||
msg = get_msg_from_envbuf(usend_msg.envbuf, envbuf_size);
|
||||
if (msg == NULL)
|
||||
return NULL;
|
||||
msg->type = usend_msg.type;
|
||||
return msg;
|
||||
case UDEVD_STOP_EXEC_QUEUE:
|
||||
info("udevd message (STOP_EXEC_QUEUE) received");
|
||||
stop_exec_q = 1;
|
||||
break;
|
||||
case UDEVD_START_EXEC_QUEUE:
|
||||
info("udevd message (START_EXEC_QUEUE) received");
|
||||
stop_exec_q = 0;
|
||||
exec_queue_manager();
|
||||
break;
|
||||
case UDEVD_SET_LOG_LEVEL:
|
||||
intval = (int *) usend_msg.envbuf;
|
||||
info("udevd message (SET_LOG_PRIORITY) received, udev_log_priority=%i", *intval);
|
||||
udev_log_priority = *intval;
|
||||
break;
|
||||
case UDEVD_SET_MAX_CHILDS:
|
||||
intval = (int *) usend_msg.envbuf;
|
||||
info("udevd message (UDEVD_SET_MAX_CHILDS) received, max_childs=%i", *intval);
|
||||
max_childs = *intval;
|
||||
break;
|
||||
default:
|
||||
dbg("unknown message type");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* receive the kernel user event message and do some sanity checks */
|
||||
static struct uevent_msg *get_netlink_msg(void)
|
||||
{
|
||||
struct uevent_msg *msg;
|
||||
int bufpos;
|
||||
ssize_t size;
|
||||
static char buffer[UEVENT_BUFFER_SIZE + 512];
|
||||
char *pos;
|
||||
|
||||
size = recv(uevent_netlink_sock, &buffer, sizeof(buffer), 0);
|
||||
if (size < 0) {
|
||||
if (errno != EINTR)
|
||||
dbg("unable to receive udevd message");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((size_t)size > sizeof(buffer)-1)
|
||||
size = sizeof(buffer)-1;
|
||||
buffer[size] = '\0';
|
||||
dbg("uevent_size=%i", size);
|
||||
|
||||
/* start of event payload */
|
||||
bufpos = strlen(buffer)+1;
|
||||
msg = get_msg_from_envbuf(&buffer[bufpos], size-bufpos);
|
||||
if (msg == NULL)
|
||||
return NULL;
|
||||
msg->type = UDEVD_UEVENT_NETLINK;
|
||||
|
||||
/* validate message */
|
||||
pos = strchr(buffer, '@');
|
||||
if (pos == NULL) {
|
||||
dbg("invalid uevent '%s'", buffer);
|
||||
free(msg);
|
||||
return NULL;
|
||||
}
|
||||
pos[0] = '\0';
|
||||
|
||||
if (msg->action == NULL) {
|
||||
dbg("no ACTION in payload found, skip event '%s'", buffer);
|
||||
free(msg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (strcmp(msg->action, buffer) != 0) {
|
||||
dbg("ACTION in payload does not match uevent, skip event '%s'", buffer);
|
||||
free(msg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
static void asmlinkage sig_handler(int signum)
|
||||
{
|
||||
int rc;
|
||||
@ -546,11 +668,13 @@ do_write:
|
||||
static void udev_done(int pid)
|
||||
{
|
||||
/* find msg associated with pid and delete it */
|
||||
struct hotplug_msg *msg;
|
||||
struct uevent_msg *msg;
|
||||
struct sysinfo info;
|
||||
|
||||
list_for_each_entry(msg, &running_list, node) {
|
||||
if (msg->pid == pid) {
|
||||
dbg("<== exec seq %llu came back", msg->seqnum);
|
||||
sysinfo(&info);
|
||||
info("seq %llu exit, %ld seconds old", msg->seqnum, info.uptime - msg->queue_time);
|
||||
run_queue_delete(msg);
|
||||
|
||||
/* we want to run the exec queue manager since there may
|
||||
@ -589,7 +713,7 @@ static void user_sighandler(void)
|
||||
}
|
||||
}
|
||||
|
||||
static int init_udevsend_socket(void)
|
||||
static int init_udevd_socket(void)
|
||||
{
|
||||
struct sockaddr_un saddr;
|
||||
socklen_t addrlen;
|
||||
@ -602,35 +726,65 @@ static int init_udevsend_socket(void)
|
||||
strcpy(&saddr.sun_path[1], UDEVD_SOCK_PATH);
|
||||
addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(saddr.sun_path+1) + 1;
|
||||
|
||||
udevsendsock = socket(AF_LOCAL, SOCK_DGRAM, 0);
|
||||
if (udevsendsock == -1) {
|
||||
udevd_sock = socket(AF_LOCAL, SOCK_DGRAM, 0);
|
||||
if (udevd_sock == -1) {
|
||||
err("error getting socket, %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* the bind takes care of ensuring only one copy running */
|
||||
retval = bind(udevsendsock, (struct sockaddr *) &saddr, addrlen);
|
||||
retval = bind(udevd_sock, (struct sockaddr *) &saddr, addrlen);
|
||||
if (retval < 0) {
|
||||
err("bind failed, %s", strerror(errno));
|
||||
close(udevsendsock);
|
||||
close(udevd_sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* enable receiving of the sender credentials */
|
||||
setsockopt(udevsendsock, SOL_SOCKET, SO_PASSCRED, &feature_on, sizeof(feature_on));
|
||||
setsockopt(udevd_sock, SOL_SOCKET, SO_PASSCRED, &feature_on, sizeof(feature_on));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init_uevent_netlink_sock(void)
|
||||
{
|
||||
struct sockaddr_nl snl;
|
||||
int retval;
|
||||
|
||||
memset(&snl, 0x00, sizeof(struct sockaddr_nl));
|
||||
snl.nl_family = AF_NETLINK;
|
||||
snl.nl_pid = getpid();
|
||||
snl.nl_groups = 0xffffffff;
|
||||
|
||||
uevent_netlink_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
|
||||
if (uevent_netlink_sock == -1) {
|
||||
dbg("error getting socket, %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
retval = bind(uevent_netlink_sock, (struct sockaddr *) &snl,
|
||||
sizeof(struct sockaddr_nl));
|
||||
if (retval < 0) {
|
||||
dbg("bind failed, %s", strerror(errno));
|
||||
close(uevent_netlink_sock);
|
||||
uevent_netlink_sock = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[], char *envp[])
|
||||
{
|
||||
struct sysinfo info;
|
||||
int maxsockplus;
|
||||
int retval;
|
||||
int fd;
|
||||
struct sigaction act;
|
||||
fd_set readfds;
|
||||
const char *udevd_expected_seqnum;
|
||||
const char *value;
|
||||
int uevent_netlink_active = 0;
|
||||
int daemonize = 0;
|
||||
int i;
|
||||
|
||||
logging_init("udevd");
|
||||
udev_init_config();
|
||||
@ -641,8 +795,18 @@ int main(int argc, char *argv[], char *envp[])
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* daemonize on request */
|
||||
if (argc == 2 && strcmp(argv[1], "-d") == 0) {
|
||||
for (i = 1 ; i < argc; i++) {
|
||||
char *arg = argv[i];
|
||||
if (strcmp(arg, "--daemon") == 0 || strcmp(arg, "-d") == 0) {
|
||||
info("will daemonize");
|
||||
daemonize = 1;
|
||||
}
|
||||
if (strcmp(arg, "--stop-exec-queue") == 0) {
|
||||
info("will not execute events until START_EXEC_QUEUE is received");
|
||||
stop_exec_q = 1;
|
||||
}
|
||||
}
|
||||
if (daemonize) {
|
||||
pid_t pid;
|
||||
|
||||
pid = fork();
|
||||
@ -663,7 +827,6 @@ int main(int argc, char *argv[], char *envp[])
|
||||
sid = setsid();
|
||||
dbg("our session is %d", sid);
|
||||
|
||||
/* make sure we don't lock any path */
|
||||
chdir("/");
|
||||
umask(umask(077) | 022);
|
||||
|
||||
@ -716,39 +879,65 @@ int main(int argc, char *argv[], char *envp[])
|
||||
sigaction(SIGALRM, &act, NULL);
|
||||
sigaction(SIGCHLD, &act, NULL);
|
||||
|
||||
if (init_udevsend_socket() < 0) {
|
||||
if (init_uevent_netlink_sock() < 0) {
|
||||
dbg("uevent socket not available");
|
||||
}
|
||||
|
||||
if (init_udevd_socket() < 0) {
|
||||
if (errno == EADDRINUSE)
|
||||
dbg("another udevd running, exit");
|
||||
else
|
||||
dbg("error initialising udevsend socket: %s", strerror(errno));
|
||||
dbg("error initialising udevd socket: %s", strerror(errno));
|
||||
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* possible override of udev binary, used for testing */
|
||||
/* override of forked udev binary, used for testing */
|
||||
udev_bin = getenv("UDEV_BIN");
|
||||
if (udev_bin != NULL)
|
||||
info("udev binary is set to '%s'", udev_bin);
|
||||
else
|
||||
udev_bin = UDEV_BIN;
|
||||
|
||||
/* possible init of expected_seqnum value */
|
||||
udevd_expected_seqnum = getenv("UDEVD_EXPECTED_SEQNUM");
|
||||
if (udevd_expected_seqnum != NULL) {
|
||||
expected_seqnum = strtoull(udevd_expected_seqnum, NULL, 10);
|
||||
/* init of expected_seqnum value */
|
||||
value = getenv("UDEVD_EXPECTED_SEQNUM");
|
||||
if (value) {
|
||||
expected_seqnum = strtoull(value, NULL, 10);
|
||||
info("initialize expected_seqnum to %llu", expected_seqnum);
|
||||
}
|
||||
|
||||
/* get current time to provide shorter timeout on startup */
|
||||
sysinfo(&info);
|
||||
startup_time = info.uptime;
|
||||
/* timeout to wait for missing events */
|
||||
value = getenv("UDEVD_EVENT_TIMEOUT");
|
||||
if (value)
|
||||
event_timeout = strtoul(value, NULL, 10);
|
||||
else
|
||||
event_timeout = UDEVD_EVENT_TIMEOUT;
|
||||
info("initialize event_timeout to %u", event_timeout);
|
||||
|
||||
/* maximum limit of forked childs */
|
||||
value = getenv("UDEVD_MAX_CHILDS");
|
||||
if (value)
|
||||
max_childs = strtoul(value, NULL, 10);
|
||||
else
|
||||
max_childs = UDEVD_MAX_CHILDS;
|
||||
info("initialize max_childs to %u", max_childs);
|
||||
|
||||
/* start to throttle forking if maximum number of _running_ childs is reached */
|
||||
value = getenv("UDEVD_MAX_CHILDS_RUNNING");
|
||||
if (value)
|
||||
max_childs_running = strtoull(value, NULL, 10);
|
||||
else
|
||||
max_childs_running = UDEVD_MAX_CHILDS_RUNNING;
|
||||
info("initialize max_childs_running to %u", max_childs_running);
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(udevsendsock, &readfds);
|
||||
FD_SET(udevd_sock, &readfds);
|
||||
if (uevent_netlink_sock != -1)
|
||||
FD_SET(uevent_netlink_sock, &readfds);
|
||||
FD_SET(pipefds[0], &readfds);
|
||||
maxsockplus = udevsendsock+1;
|
||||
maxsockplus = udevd_sock+1;
|
||||
while (1) {
|
||||
struct hotplug_msg *msg;
|
||||
struct uevent_msg *msg;
|
||||
|
||||
fd_set workreadfds = readfds;
|
||||
retval = select(maxsockplus, &workreadfds, NULL, NULL, NULL);
|
||||
@ -759,10 +948,29 @@ int main(int argc, char *argv[], char *envp[])
|
||||
continue;
|
||||
}
|
||||
|
||||
if (FD_ISSET(udevsendsock, &workreadfds)) {
|
||||
msg = get_udevsend_msg();
|
||||
if (msg)
|
||||
if (FD_ISSET(udevd_sock, &workreadfds)) {
|
||||
msg = get_udevd_msg();
|
||||
if (msg) {
|
||||
/* discard kernel messages if netlink is active */
|
||||
if (uevent_netlink_active && msg->type == UDEVD_UEVENT_UDEVSEND && msg->seqnum != 0) {
|
||||
dbg("skip uevent_helper message, netlink is active");
|
||||
free(msg);
|
||||
continue;
|
||||
}
|
||||
msg_queue_insert(msg);
|
||||
}
|
||||
}
|
||||
|
||||
if (FD_ISSET(uevent_netlink_sock, &workreadfds)) {
|
||||
msg = get_netlink_msg();
|
||||
if (msg) {
|
||||
msg_queue_insert(msg);
|
||||
/* disable udevsend with first netlink message */
|
||||
if (!uevent_netlink_active) {
|
||||
info("uevent_nl message received, disable udevsend messages");
|
||||
uevent_netlink_active = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (FD_ISSET(pipefds[0], &workreadfds))
|
||||
@ -786,7 +994,8 @@ int main(int argc, char *argv[], char *envp[])
|
||||
}
|
||||
|
||||
run_exec_q = 0;
|
||||
exec_queue_manager();
|
||||
if (!stop_exec_q)
|
||||
exec_queue_manager();
|
||||
}
|
||||
}
|
||||
|
||||
|
42
udevd.h
42
udevd.h
@ -26,32 +26,48 @@
|
||||
|
||||
#define UDEV_MAGIC "udevd_" UDEV_VERSION
|
||||
#define UDEVD_SOCK_PATH "udevd"
|
||||
#define SEND_WAIT_MAX_SECONDS 3
|
||||
#define SEND_WAIT_LOOP_PER_SECOND 10
|
||||
#define UDEVSEND_WAIT_MAX_SECONDS 3
|
||||
#define UDEVSEND_WAIT_LOOP_PER_SECOND 10
|
||||
|
||||
#define UDEVD_PRIORITY -4
|
||||
#define UDEV_PRIORITY -2
|
||||
|
||||
/* duration of initialization phase with shorter timeout */
|
||||
#define INIT_TIME_SEC 5
|
||||
#define EVENT_INIT_TIMEOUT_SEC 2
|
||||
#define UDEVD_INIT_TIME 5
|
||||
#define UDEVD_INIT_EVENT_TIMEOUT 2
|
||||
|
||||
/* timeout to wait for missing events */
|
||||
#define EVENT_TIMEOUT_SEC 10
|
||||
#define UDEVD_EVENT_TIMEOUT 5
|
||||
|
||||
/* maximum limit of runnig childs */
|
||||
#define UDEVD_MAX_CHILDS 64
|
||||
/* start to throttle forking if maximum number of running childs in our session is reached */
|
||||
#define THROTTLE_MAX_RUNNING_CHILDS 10
|
||||
#define UDEVD_MAX_CHILDS_RUNNING 8
|
||||
|
||||
/* environment buffer, should match the kernel's size in lib/kobject_uevent.h */
|
||||
#define HOTPLUG_BUFFER_SIZE 1024
|
||||
#define HOTPLUG_NUM_ENVP 32
|
||||
#define UEVENT_BUFFER_SIZE 1024
|
||||
#define UEVENT_NUM_ENVP 32
|
||||
|
||||
struct udevsend_msg {
|
||||
char magic[20];
|
||||
char envbuf[HOTPLUG_BUFFER_SIZE+256];
|
||||
enum udevd_msg_type {
|
||||
UDEVD_UNKNOWN,
|
||||
UDEVD_UEVENT_UDEVSEND,
|
||||
UDEVD_UEVENT_INITSEND,
|
||||
UDEVD_UEVENT_NETLINK,
|
||||
UDEVD_STOP_EXEC_QUEUE,
|
||||
UDEVD_START_EXEC_QUEUE,
|
||||
UDEVD_SET_LOG_LEVEL,
|
||||
UDEVD_SET_MAX_CHILDS,
|
||||
};
|
||||
|
||||
struct hotplug_msg {
|
||||
|
||||
struct udevd_msg {
|
||||
char magic[32];
|
||||
enum udevd_msg_type type;
|
||||
char envbuf[UEVENT_BUFFER_SIZE+512];
|
||||
};
|
||||
|
||||
struct uevent_msg {
|
||||
enum udevd_msg_type type;
|
||||
struct list_head node;
|
||||
pid_t pid;
|
||||
long queue_time;
|
||||
@ -61,6 +77,6 @@ struct hotplug_msg {
|
||||
unsigned long long seqnum;
|
||||
char *physdevpath;
|
||||
unsigned int timeout;
|
||||
char *envp[HOTPLUG_NUM_ENVP+1];
|
||||
char *envp[UEVENT_NUM_ENVP+1];
|
||||
char envbuf[];
|
||||
};
|
||||
|
127
udeveventrecorder.c
Normal file
127
udeveventrecorder.c
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* udeveventrecorder.c
|
||||
*
|
||||
* Userspace devfs
|
||||
*
|
||||
* Copyright (C) 2004, 2005 Olaf Hering <olh@suse.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation version 2 of the License.
|
||||
*
|
||||
* 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 GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "udev.h"
|
||||
#include "udev_version.h"
|
||||
#include "udev_utils.h"
|
||||
#include "logging.h"
|
||||
|
||||
#define BUFSIZE 12345
|
||||
#define FNSIZE 123
|
||||
|
||||
static int log = 0;
|
||||
|
||||
#ifdef USE_LOG
|
||||
void log_message (int priority, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (priority > log)
|
||||
return;
|
||||
|
||||
va_start(args, format);
|
||||
vsyslog(priority, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv, char **envp)
|
||||
{
|
||||
int fd, i;
|
||||
unsigned long seq;
|
||||
char **ep = envp;
|
||||
char *buf, *p, *a;
|
||||
struct stat sb;
|
||||
const char *env;
|
||||
|
||||
if (stat("/events", &sb) || !(S_ISDIR(sb.st_mode)))
|
||||
return 1;
|
||||
|
||||
env = getenv("UDEV_LOG");
|
||||
if (env)
|
||||
log = log_priority(env);
|
||||
|
||||
logging_init("udeveventrecorder");
|
||||
dbg("version %s", UDEV_VERSION);
|
||||
|
||||
p = getenv("SEQNUM");
|
||||
a = getenv("ACTION");
|
||||
buf = malloc(FNSIZE);
|
||||
if (!(buf && a && argv[1]))
|
||||
goto error;
|
||||
if (p)
|
||||
seq = strtoul(p, NULL, 0);
|
||||
else
|
||||
seq = 0;
|
||||
|
||||
snprintf(buf, FNSIZE, "/events/debug.%05lu.%s.%s.%u", seq, argv[1], a ? a : "", getpid());
|
||||
if ((fd = open(buf, O_CREAT | O_WRONLY | O_TRUNC, 0644)) < 0) {
|
||||
err("error creating '%s'", buf);
|
||||
goto error;
|
||||
}
|
||||
free(buf);
|
||||
p = malloc(BUFSIZE);
|
||||
buf = p;
|
||||
buf += snprintf(buf, p + BUFSIZE - buf, "set --");
|
||||
for (i = 1; i < argc; ++i) {
|
||||
buf += snprintf(buf, p + BUFSIZE - buf, " %s", argv[i]);
|
||||
if (buf > p + BUFSIZE)
|
||||
goto full;
|
||||
}
|
||||
buf += snprintf(buf, p + BUFSIZE - buf, "\n");
|
||||
if (buf > p + BUFSIZE)
|
||||
goto full;
|
||||
while (*ep) {
|
||||
unsigned char *t;
|
||||
t = memchr(*ep, '=', strlen(*ep));
|
||||
if (t) {
|
||||
*t = '\0';
|
||||
t++;
|
||||
buf += snprintf(buf, p + BUFSIZE - buf, "%s='%s'\n", *ep, t);
|
||||
--t;
|
||||
*t = '=';
|
||||
}
|
||||
ep++;
|
||||
if (buf > p + BUFSIZE)
|
||||
break;
|
||||
}
|
||||
|
||||
full:
|
||||
buf = p;
|
||||
write(fd, buf, strlen(buf));
|
||||
close(fd);
|
||||
free(buf);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
fprintf(stderr, "record enviroment to /events, to be called from udev context\n");
|
||||
return 1;
|
||||
}
|
239
udevinitsend.c
Normal file
239
udevinitsend.c
Normal file
@ -0,0 +1,239 @@
|
||||
/*
|
||||
* udevinitsend.c
|
||||
*
|
||||
* Userspace devfs
|
||||
*
|
||||
* Copyright (C) 2004, 2005 Hannes Reinecke <hare@suse.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation version 2 of the License.
|
||||
*
|
||||
* 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 GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/un.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "udev.h"
|
||||
#include "udev_version.h"
|
||||
#include "udevd.h"
|
||||
#include "udev_utils.h"
|
||||
#include "logging.h"
|
||||
|
||||
static int log = 0;
|
||||
|
||||
#ifdef USE_LOG
|
||||
void log_message (int priority, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (priority > log)
|
||||
return;
|
||||
|
||||
va_start(args, format);
|
||||
vsyslog(priority, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* udevsend
|
||||
*
|
||||
* Scan a file, write all variables into the msgbuf and
|
||||
* fires the message to udevd.
|
||||
*/
|
||||
static int udevsend(char *filename, int sock, int disable_loop_detection)
|
||||
{
|
||||
static struct udevd_msg usend_msg;
|
||||
int usend_msg_len;
|
||||
int bufpos = 0;
|
||||
struct stat statbuf;
|
||||
int fd;
|
||||
char *fdmap, *ls, *le, *ch;
|
||||
struct sockaddr_un saddr;
|
||||
socklen_t addrlen;
|
||||
int retval = 0;
|
||||
|
||||
if (stat(filename,&statbuf) < 0) {
|
||||
dbg("cannot stat %s: %s\n", filename, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
fd = open(filename,O_RDONLY);
|
||||
if (fd < 0)
|
||||
return 1;
|
||||
|
||||
fdmap = mmap(0, statbuf.st_size,
|
||||
PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
close(fd);
|
||||
if (fdmap == MAP_FAILED) {
|
||||
dbg("mmap failed, errno %d\n", errno);
|
||||
return 1;
|
||||
}
|
||||
|
||||
memset(&saddr, 0x00, sizeof(struct sockaddr_un));
|
||||
saddr.sun_family = AF_LOCAL;
|
||||
/* use abstract namespace for socket path */
|
||||
strcpy(&saddr.sun_path[1], UDEVD_SOCK_PATH);
|
||||
addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(saddr.sun_path+1) + 1;
|
||||
|
||||
memset(&usend_msg, 0x00, sizeof(struct udevd_msg));
|
||||
strcpy(usend_msg.magic, UDEV_MAGIC);
|
||||
usend_msg.type = UDEVD_UEVENT_INITSEND;
|
||||
|
||||
ls = fdmap;
|
||||
ch = le = ls;
|
||||
while (*ch && ch < fdmap + statbuf.st_size) {
|
||||
le = strchr(ch, '\n');
|
||||
if (!le)
|
||||
break;
|
||||
ch = strchr(ch, '=');
|
||||
if (!ch)
|
||||
break;
|
||||
|
||||
/* prevent loops in the scripts we execute */
|
||||
if (strncmp(ls, "UDEVD_EVENT=", 12) == 0) {
|
||||
if (!disable_loop_detection) {
|
||||
dbg("event already handled by udev\n");
|
||||
retval = -1;
|
||||
break;
|
||||
}
|
||||
goto loop_end;
|
||||
}
|
||||
|
||||
/* omit shell-generated keys */
|
||||
if (ls[0] == '_' && ls[1] == '=') {
|
||||
goto loop_end;
|
||||
}
|
||||
|
||||
if (ch < le) {
|
||||
|
||||
strncpy(&usend_msg.envbuf[bufpos],ls,(ch - ls) + 1);
|
||||
bufpos += (ch - ls) + 1;
|
||||
if (ch[1] == '\'' && le[-1] == '\'') {
|
||||
strncpy(&usend_msg.envbuf[bufpos],ch + 2, (le - ch) -3);
|
||||
bufpos += (le - ch) - 3;
|
||||
} else {
|
||||
strncpy(&usend_msg.envbuf[bufpos],ch, (le - ch));
|
||||
bufpos += (le - ch);
|
||||
}
|
||||
bufpos++;
|
||||
}
|
||||
loop_end:
|
||||
ch = le + 1;
|
||||
ls = ch;
|
||||
}
|
||||
munmap(fdmap, statbuf.st_size);
|
||||
|
||||
usend_msg_len = offsetof(struct udevd_msg, envbuf) + bufpos;
|
||||
dbg("usend_msg_len=%i", usend_msg_len);
|
||||
|
||||
if (!retval) {
|
||||
retval = sendto(sock, &usend_msg, usend_msg_len, 0, (struct sockaddr *)&saddr, addrlen);
|
||||
if (retval < 0) {
|
||||
dbg("error sending message (%s)", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[], char *envp[])
|
||||
{
|
||||
static const char short_options[] = "d:f:lVh";
|
||||
int option;
|
||||
char *event_dir = NULL;
|
||||
char *event_file = NULL;
|
||||
DIR *dirstream;
|
||||
struct dirent *direntry;
|
||||
int retval = 1;
|
||||
int disable_loop_detection = 0;
|
||||
int sock;
|
||||
const char *env;
|
||||
|
||||
env = getenv("UDEV_LOG");
|
||||
if (env)
|
||||
log = log_priority(env);
|
||||
|
||||
logging_init("udevinitsend");
|
||||
dbg("version %s", UDEV_VERSION);
|
||||
|
||||
/* get command line options */
|
||||
while (1) {
|
||||
option = getopt(argc, argv, short_options);
|
||||
if (option == -1)
|
||||
break;
|
||||
|
||||
dbg("option '%c': ", option);
|
||||
switch (option) {
|
||||
case 'd':
|
||||
dbg("scan directory %s\n", optarg);
|
||||
event_dir = optarg;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
dbg("use event file %s\n", optarg);
|
||||
event_file = optarg;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
dbg("disable loop detection, ignore UDEVD_EVENT\n");
|
||||
disable_loop_detection = 1;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
|
||||
sock = socket(AF_LOCAL, SOCK_DGRAM, 0);
|
||||
if (sock == -1) {
|
||||
dbg("error getting socket");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (event_dir) {
|
||||
dirstream = opendir(event_dir);
|
||||
if (!dirstream) {
|
||||
info("error opening directory %s: %s\n",
|
||||
event_dir, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
chdir(event_dir);
|
||||
while ((direntry = readdir(dirstream)) != NULL) {
|
||||
if (!strcmp(direntry->d_name,".") ||
|
||||
!strcmp(direntry->d_name,".."))
|
||||
continue;
|
||||
retval = udevsend(direntry->d_name, sock, disable_loop_detection);
|
||||
}
|
||||
closedir(dirstream);
|
||||
} else if (event_file) {
|
||||
retval = udevsend(event_file, sock, disable_loop_detection);
|
||||
}
|
||||
|
||||
if (sock != -1)
|
||||
close(sock);
|
||||
|
||||
return retval;
|
||||
}
|
15
udevsend.c
15
udevsend.c
@ -115,7 +115,7 @@ static void run_udev(const char *subsystem)
|
||||
|
||||
int main(int argc, char *argv[], char *envp[])
|
||||
{
|
||||
static struct udevsend_msg usend_msg;
|
||||
static struct udevd_msg usend_msg;
|
||||
int usend_msg_len;
|
||||
int i;
|
||||
int loop;
|
||||
@ -144,8 +144,9 @@ int main(int argc, char *argv[], char *envp[])
|
||||
strcpy(&saddr.sun_path[1], UDEVD_SOCK_PATH);
|
||||
addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(saddr.sun_path+1) + 1;
|
||||
|
||||
memset(&usend_msg, 0x00, sizeof(struct udevsend_msg));
|
||||
memset(&usend_msg, 0x00, sizeof(struct udevd_msg));
|
||||
strcpy(usend_msg.magic, UDEV_MAGIC);
|
||||
usend_msg.type = UDEVD_UEVENT_UDEVSEND;
|
||||
|
||||
/* copy all keys to send buffer */
|
||||
for (i = 0; envp[i]; i++) {
|
||||
@ -161,7 +162,7 @@ int main(int argc, char *argv[], char *envp[])
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (bufpos + keylen >= HOTPLUG_BUFFER_SIZE-1) {
|
||||
if (bufpos + keylen >= UEVENT_BUFFER_SIZE-1) {
|
||||
err("environment buffer too small, probably not called by the kernel");
|
||||
continue;
|
||||
}
|
||||
@ -180,11 +181,11 @@ int main(int argc, char *argv[], char *envp[])
|
||||
dbg("add 'SUBSYSTEM=%s' to env[%i] buffer from argv", argv[1], i);
|
||||
}
|
||||
|
||||
usend_msg_len = offsetof(struct udevsend_msg, envbuf) + bufpos;
|
||||
usend_msg_len = offsetof(struct udevd_msg, envbuf) + bufpos;
|
||||
dbg("usend_msg_len=%i", usend_msg_len);
|
||||
|
||||
/* If we can't send, try to start daemon and resend message */
|
||||
loop = SEND_WAIT_MAX_SECONDS * SEND_WAIT_LOOP_PER_SECOND;
|
||||
loop = UDEVSEND_WAIT_MAX_SECONDS * UDEVSEND_WAIT_LOOP_PER_SECOND;
|
||||
while (--loop) {
|
||||
retval = sendto(sock, &usend_msg, usend_msg_len, 0, (struct sockaddr *)&saddr, addrlen);
|
||||
if (retval != -1) {
|
||||
@ -207,8 +208,8 @@ int main(int argc, char *argv[], char *envp[])
|
||||
dbg("udevd daemon started");
|
||||
started_daemon = 1;
|
||||
} else {
|
||||
dbg("retry to connect %d", SEND_WAIT_MAX_SECONDS * SEND_WAIT_LOOP_PER_SECOND - loop);
|
||||
usleep(1000 * 1000 / SEND_WAIT_LOOP_PER_SECOND);
|
||||
dbg("retry to connect %d", UDEVSEND_WAIT_MAX_SECONDS * UDEVSEND_WAIT_LOOP_PER_SECOND - loop);
|
||||
usleep(1000 * 1000 / UDEVSEND_WAIT_LOOP_PER_SECOND);
|
||||
}
|
||||
}
|
||||
|
||||
|
32
udevstart.c
32
udevstart.c
@ -37,6 +37,7 @@
|
||||
|
||||
#include "libsysfs/sysfs/libsysfs.h"
|
||||
#include "udev_libc_wrapper.h"
|
||||
#include "udev_sysfs.h"
|
||||
#include "udev.h"
|
||||
#include "udev_version.h"
|
||||
#include "logging.h"
|
||||
@ -110,25 +111,36 @@ static int add_device(const char *path, const char *subsystem)
|
||||
const char *devpath;
|
||||
|
||||
devpath = &path[strlen(sysfs_path)];
|
||||
|
||||
/* set environment for callouts and dev.d/ */
|
||||
setenv("DEVPATH", devpath, 1);
|
||||
setenv("SUBSYSTEM", subsystem, 1);
|
||||
|
||||
dbg("exec: '%s' (%s)\n", devpath, path);
|
||||
|
||||
class_dev = sysfs_open_class_device_path(path);
|
||||
if (class_dev == NULL) {
|
||||
dbg ("sysfs_open_class_device_path failed");
|
||||
return -ENODEV;
|
||||
dbg("sysfs_open_class_device_path failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
udev_init_device(&udev, devpath, subsystem, "add");
|
||||
udev_add_device(&udev, class_dev);
|
||||
udev.devt = get_devt(class_dev);
|
||||
if (!udev.devt) {
|
||||
dbg("sysfs_open_class_device_path failed");
|
||||
return -1;
|
||||
}
|
||||
udev_rules_get_name(&udev, class_dev);
|
||||
if (udev.ignore_device) {
|
||||
dbg("device event will be ignored");
|
||||
goto exit;
|
||||
}
|
||||
if (udev.name[0] == '\0') {
|
||||
dbg("device node creation supressed");
|
||||
goto run;
|
||||
}
|
||||
|
||||
udev_add_device(&udev, class_dev);
|
||||
if (udev.devname[0] != '\0')
|
||||
setenv("DEVNAME", udev.devname, 1);
|
||||
|
||||
run:
|
||||
if (udev_run && !list_empty(&udev.run_list)) {
|
||||
struct name_entry *name_loop;
|
||||
|
||||
@ -136,11 +148,7 @@ static int add_device(const char *path, const char *subsystem)
|
||||
list_for_each_entry(name_loop, &udev.run_list, node)
|
||||
execute_command(name_loop->name, udev.subsystem);
|
||||
}
|
||||
|
||||
/* run dev.d/ scripts if we created a node or changed a netif name */
|
||||
if (udev_dev_d && udev.devname[0] != '\0')
|
||||
udev_multiplex_directory(&udev, DEVD_DIR, DEVD_SUFFIX);
|
||||
|
||||
exit:
|
||||
sysfs_close_class_device(class_dev);
|
||||
udev_cleanup_device(&udev);
|
||||
|
||||
|
17
udevtest.c
17
udevtest.c
@ -98,12 +98,6 @@ int main(int argc, char *argv[], char *envp[])
|
||||
/* fill in values and test_run flag*/
|
||||
udev_init_device(&udev, devpath, subsystem, "add");
|
||||
|
||||
/* skip subsystems without "dev", but handle net devices */
|
||||
if (udev.type != DEV_NET && subsystem_expect_no_dev(udev.subsystem)) {
|
||||
info("don't care about '%s' devices", udev.subsystem);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* open the device */
|
||||
snprintf(path, sizeof(path), "%s%s", sysfs_path, udev.devpath);
|
||||
path[sizeof(path)-1] = '\0';
|
||||
@ -112,13 +106,18 @@ int main(int argc, char *argv[], char *envp[])
|
||||
info("sysfs_open_class_device_path failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
info("opened class_dev->name='%s'", class_dev->name);
|
||||
|
||||
if (udev.type == DEV_BLOCK || udev.type == DEV_CLASS)
|
||||
udev.devt = get_devt(class_dev);
|
||||
|
||||
/* simulate node creation with test flag */
|
||||
udev.test_run = 1;
|
||||
udev_add_device(&udev, class_dev);
|
||||
|
||||
if (udev.type == DEV_NET || udev.devt) {
|
||||
udev_rules_get_name(&udev, class_dev);
|
||||
udev_add_device(&udev, class_dev);
|
||||
} else
|
||||
info("only char and block devices with a dev-file are supported by this test program");
|
||||
sysfs_close_class_device(class_dev);
|
||||
|
||||
return 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user