Bug 4177

Summary: "read" not working since 1.19.x
Product: Busybox Reporter: gandharva
Component: OtherAssignee: unassigned
Status: RESOLVED WORKSFORME    
Severity: major CC: busybox-cvs
Priority: P5    
Version: 1.19.x   
Target Milestone: ---   
Hardware: Other   
OS: Linux   
Host: Target:
Build:
Attachments: 1.18.5 config
config 1.19.2

Description gandharva 2011-09-12 10:21:58 UTC
It seems "read" is not working correctly since 1.19.x. I use it for mounting via mdev on an embedded system.

This is the related part of the code:
read MODEL < /sys/block/$DEVBASE/device/model

With BB 1.18.x it works fine. It returns the model name and strips off the blanks at the end of the string. With BB 1.19.x the system completely hangs or the variable MODEL is empty.
Comment 1 Denys Vlasenko 2011-09-15 08:28:04 UTC
Works for me:

# busybox ash -c 'read m </sys/block/sda/device/model; echo -$m-'
-ST9100821AS-

# busybox hush -c 'read m </sys/block/sda/device/model; echo -$m-'
-ST9100821AS-

# busybox | head -1
BusyBox v1.19.2 (2011-09-12 21:02:22 CEST) multi-call binary.

Can you attach your .config?
Comment 2 gandharva 2011-10-09 15:23:55 UTC
Created attachment 3625 [details]
1.18.5 config
Comment 3 gandharva 2011-10-09 15:25:54 UTC
Sorry for late answer. I attached the config. This is the relevant part from the mdev script:

create_symlinks() {
	DEVBASE=${MDEV:0:3} # first 3 characters
	PARTNUM=${MDEV:3}   # characters 4-
	read MODEL < /sys/block/$DEVBASE/device/model
	MODEL=${MODEL// /_} # replace ' ' with '_'
	OLDPWD=$PWD
	cd $MOUNTBASE
	if which blkid > /dev/null; then
		BLKID=$(blkid /dev/$MDEV)
		eval ${BLKID#*:}
	fi
	if [ -n "$LABEL" ]; then
		rm -f "$LABEL"
		ln -s $MDEV "$LABEL"
	fi
	if [ -n "$UUID" ]; then
		LINK="${TYPE}${TYPE:+-}${UUID}"
		rm -f "${LINK}"
		ln -s $MDEV "${LINK}"
	fi
	if [ -n "$MODEL" ]; then
		LINK="${MODEL}${PARTNUM:+-}${PARTNUM}"
		rm -f "${LINK}"
		ln -s $MDEV "${LINK}"
	fi
	BUS=""
	PORT=""
	P=$PHYSDEVPATH
	case "$P" in
	/devices/platform/cx2450x-ehci.?/usb?/?-?/?-?.?/?-?.?:?.?/host*) # hub
		PORT=${P#*.*.}	# strip off /devices/platform/cx2450x-ehci.?/usb?/?-?/?-?
		PORT=${PORT%%/*}	# strip off /?-?.?:?.?/host*, leaving the port
		BUS="usb-${P:31:1}-hub-${PORT}"
		;;
	/devices/platform/cx2450x-ehci.?/usb?/?-?/?-?:?.?/host*) # no hub
		BUS="usb-${P:31:1}"
		;;
	/devices/platform/cnxt_sata?-?.?/host*)
		BUS="sata-${P:27:1}"
		;;
	*)
		# BUS="unknown" # ignored for now
		;;
	esac
	if [ -n "$BUS" ]; then
		LINK="${BUS}${PARTNUM:+-}${PARTNUM}"
		rm -f "${LINK}"
		ln -s $MDEV "${LINK}"
	fi

	cd $OLDPWD
}
Comment 4 Oliver Metz 2011-10-09 15:49:04 UTC
I can confirm the behaviour. 1.18.5 worked. 1.19.2 hangs.

# strace sh -c read a b c d e < /proc/mounts
execve("/bin/sh", ["sh", "-c", "read", "a", "b", "c", "d", "e"], [/* 235 vars */]) = 0
...
wait4(-1, 0x7fe928f8, WNOHANG, NULL)    = -1 ECHILD (No child processes)
poll([{fd=0, events=POLLIN}], 1, -1^C <unfinished ...>
Comment 5 Oliver Metz 2011-10-09 15:53:18 UTC
Created attachment 3631 [details]
config 1.19.2

With http://git.busybox.net/busybox/commit/shell/shell_common.c?id=10c0131a8a1b3db7fd6b23b72ebd7b33afc7b018 reverted it's working for me.
Comment 6 gandharva 2011-10-20 08:32:55 UTC
Any news about this bug?
Comment 7 Denys Vlasenko 2012-01-10 23:55:18 UTC
(In reply to comment #5)
> Created attachment 3631 [details]
> config 1.19.2
> 
> With
> http://git.busybox.net/busybox/commit/shell/shell_common.c?id=10c0131a8a1b3db7fd6b23b72ebd7b33afc7b018
> reverted it's working for me.

Essentially, that patch added

+ pfd[0].fd = fd;
+ pfd[0].events = POLLIN;
+ if (poll(pfd, 1, timeout) != 1) {...}

before actual read:

+ if (read(fd, &buffer[bufpos], 1) != 1) {

which is a completely valid operation. It works for me, with both my .config and hush; and your .config and ash (your .config has hush disabled). In strace, I see this:

poll([{fd=0, events=POLLIN}], 1, -1)    = 1 ([{fd=0, revents=POLLIN|POLLERR}])
read(0, "I", 1)                         = 1
poll([{fd=0, events=POLLIN}], 1, -1)    = 1 ([{fd=0, revents=POLLIN}])
read(0, "N", 1)                         = 1
poll([{fd=0, events=POLLIN}], 1, -1)    = 1 ([{fd=0, revents=POLLIN}])
read(0, "T", 1)                         = 1
poll([{fd=0, events=POLLIN}], 1, -1)    = 1 ([{fd=0, revents=POLLIN}])
read(0, "E", 1)                         = 1
poll([{fd=0, events=POLLIN}], 1, -1)    = 1 ([{fd=0, revents=POLLIN}])
read(0, "L", 1)                         = 1
poll([{fd=0, events=POLLIN}], 1, -1)    = 1 ([{fd=0, revents=POLLIN}])
read(0, " ", 1)                         = 1
poll([{fd=0, events=POLLIN}], 1, -1)    = 1 ([{fd=0, revents=POLLIN}])
read(0, "S", 1)                         = 1
poll([{fd=0, events=POLLIN}], 1, -1)    = 1 ([{fd=0, revents=POLLIN}])
read(0, "S", 1)                         = 1
poll([{fd=0, events=POLLIN}], 1, -1)    = 1 ([{fd=0, revents=POLLIN}])
read(0, "D", 1)                         = 1

As you see, _for me_ poll does return. For you, for some reason it waits forever. This seem to be a kernel bug. (In fact, my kernel appears to exhibit a minor bug too: the POLLERR bit is bogus. Luckily, we ignore it...).

Try "strace -oLOG sh -c read </SOME/FILE". Note on what files it fails. I hazard to guess it would work on ordinary files, but would it work (as in: not hang until ^C) on /dev/null? On /proc/version? /proc/mounts? etc...

If it works on some of these file types but not others, let me know what is the exact syscall it stops at (likely it will be "poll([{fd=0, events=POLLIN}], 1, -1...") and what is the affected kernel version. Then we will probably need to bug kernel people...
Comment 8 Denys Vlasenko 2012-01-10 23:56:05 UTC
Oh, and btw, my kernel is 3.1.7.
Comment 9 Denys Vlasenko 2012-09-25 18:54:01 UTC
Cannot reproduce. Closing.
If you can  reproduce it, reopen the bug and give more details. The most important is kernel version and .config.