2

Consider the following script wrapcat.sh (a wrapper for cat) for illustrative purposes. It is run with busybox (ash) in an embedded Linux 2.6 box.

#!/bin/sh
cat $1

Under certain circumstances, this script will not always exit cleanly. For instance, when I run

$./wrapcat.sh /proc/pid/cmdline

for some pid, I will sometimes be dropped into a shell awaiting a command. After hitting return or the like, it terminates.

My diagnosis is that cat is interrupted by some signal, and therefore the script does not exit cleanly (as I do not set any -e option). So I am interested in the return status of the cat command. I modify the script as follows:

#!/bin/sh
cat $1
echo $? # echo the exit status

However, the exit status is not echoed when the script fails to exit cleanly. I'd like to know why the $? exit status is not echoed (and perhaps more specifically why a clean exit doesn't always happen particularly when catting /proc/pid/cmdline). The same also sometimes occurs when catting /proc/pid/auxv and /proc/pid/environ. Relevant function in source: http://lxr.linux.no/#linux+v2.6.31/fs/proc/base.c#L253

I don't want to necessarily know how to 'fix' this, that can probably be done by setting the aforementioned -e option.

Note: you will probably not be able to reproduce this in something like Ubuntu or Debian - the phenomenon may be specific to busybox ash, cat, or embedded Linux. You can, however, simulate it by interrupting a child process sleep run inside a script.

E.g. run a script s.sh:

#!/bin/sh
sleep 1000
echo $?

Then $./s.sh, ctrl-z, bg, disown %1 to run the script in it's own process. Now in ps you will see something like:

15610 pts/35   00:00:00 s.sh
15611 pts/35   00:00:00 sleep

If you go ahead and run kill -2 15611 (on the child process), you observe

$ 130 # the exit status, which does get printed
command line waits for next command without clean exit
  • The bug is probably specific to a particular version of BusyBox, a particular set of BB compilation options, a particular architecture… Post all this information about your setup. Have you looked for an existing bug report? Have you made a bug report? We might help you find a workaround, but the best way to have this fixed is to report the bug. – Gilles Dec 19 '13 at 23:29
  • You observe $ 130 because the background process has output that 130, your shell doesn't redraw its prompt but that's to be expected since it has no way to know that something has written to the terminal in background. – Stéphane Chazelas Dec 20 '13 at 23:03
  • That makes sense - the example is a bit contrived and not really representative of the issue then (see below). – user54945 Dec 21 '13 at 16:41
1

You're misinterpreting the output.

It's just that those files (cmdline, environ...) are not terminated by a newline character.

So for instance, if /proc/pid/cmdline contains xxx, cat /proc/pid/cmdline will output xxx, but because there's no newline character (which the terminal discipline converts on output to CRLF) the cursor will not go back to the beginning of the line (CR), nor go down by one (LF).

Then upon exit, your shell will output its prompt to wait for the next command, so you'll see something like:

xxx$ 

and if there's a echo $?, that will be:

xxx0
$ 

If the file contains more than xxx, that may get more confusing.

If you want a newline character to be added when it's missing you could use cut instead of cat:

#! /bin/sh -
cut -b1- < "$1"
  • perhaps tr '\0' '\n' ? – glenn jackman Dec 21 '13 at 0:03
  • Almost, but not quite. I do realize it does not output a newline. To clarify, instead of seeing xxx$ I only see xxx without it redrawing the prompt, or printing the echo $?, and simply waits for the next command. The cursor is still on the xxx line, as you point out it should be. – user54945 Dec 21 '13 at 16:42
  • So why would it not redraw the prompt? Does the script truly exit? – user54945 Dec 21 '13 at 16:49
0

I can see, if $1 evaluates to an empty string, that cat is waiting to read from stdin. Then you need to hit Ctrl-D or Ctrl-C to close cat so the script can continue. For this issue specifically, I'd try

cat "${1:-/dev/null}"

So that if $1 is empty or unset, then at least cat gets a valid filename with finite contents to work on.

  • Yes, overlook that and assume a filename is specified. – user54945 Dec 19 '13 at 18:12
  • 1
    cat "$1" would not be a problem if $1 were empty. Better, cat < "$1" to avoid problems if $1 is - or an option. – Stéphane Chazelas Dec 20 '13 at 23:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.