/bin/sh: can't access tty; job control turned off - linux

I have been following the commands from the book "Mastering embedded linux programming" by Chris Simmonds. I have created the toolchain, kernel zImage and busybox file system. When I combine these together to run on QEMU, It should display a root shell prompt.
When I run the command, I get the following.
/bin/sh: can't access tty; job control turned off
input: ImExPS/2 Generic Explorer Mouse as /devices/platform/amba/amba:fpga/10007000.kmi/serio1/input/input2
When I press enter, I am able to see the root shell prompt and I am able to execute simple shell commands.
However, when I press exit, I get the following error.
Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000000
CPU: 0 PID: 1 Comm: sh Not tainted 4.9.13 #1
Hardware name: ARM-Versatile (Device Tree Support)
[<c001b5a4>] (unwind_backtrace) from [<c0018860>] (show_stack+0x10/0x14)
[<c0018860>] (show_stack) from [<c00737f4>] (panic+0xb8/0x230)
[<c00737f4>] (panic) from [<c0024e24>] (do_exit+0x8e8/0x938)
[<c0024e24>] (do_exit) from [<c0025cf8>] (do_group_exit+0x38/0xb4)
[<c0025cf8>] (do_group_exit) from [<c0025d84>] (__wake_up_parent+0x0/0x18)
---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000000
How do I resolve this
EDIT:
The following is the QEMU command that I ran
QEMU_AUDIO_DRV=none \qemu-system-arm
-m 256M -nographic
-M versatilepb
-kernel ~/linux-4.9.13/arch/arm/boot/zImage
\-append "console=ttyAMA0,115200 rdinit=/bin/sh"
-dtb ~/linux-4.9.13/arch/arm/boot/dts/versatile-pb.dtb
-initrd ~/busybox/initramfs.cpio.gz

(You don't say what your QEMU command line is.)
These error messages generally are what you should expect if you tell the kernel to run /bin/sh directly as its process 1 (eg with "init=/bin/sh" on the kernel command line). First the shell complains that it doesn't have a tty, but it can continue anyway with some facilities disabled. Then, when you eventually tell the shell to exit, because the shell itself is process 1 the kernel complains. (Usually process 1 is supposed to be an "init" program, which runs forever and deals with starting other processes in the system. If "init" ever dies the kernel has nothing else it can do.)
If you were intending to run /bin/sh as your process 1, then this is all normal. If you didn't want to do that, then you have an issue with either your root filesystem or with your command line which means that it isn't properly starting an /sbin/init in the guest, and you should look at why.

Related

strace init process (PID 1) in linux

The strace manpage says:
On Linux, exciting as it would be, tracing the init process is
forbidden.
I checked the same and it doesn't allow it:
$ strace -p 1
attach: ptrace(PTRACE_ATTACH, ...): Operation not permitted
Why isn't it possible? Even the ptrace manpage says the same about tracing init process. Aren't these tools safe or just that the init process is deemed too special that no other processes (strace/ptrace) can signal it.
sudo strace -p 1 works for me ( you need root privileges for strace )
There was work to allow debugging of init. In 2.4.37 you can't attach to init, but in some kernel this condition was removed - I've found 3.8 kernel
Edit: on my Kubuntu 15.10 there is no On Linux, exciting as it would be, tracing the init process is forbidden. in strace man. Updated man?

mount fails from spawned process

I want to start a process that uses a USB hard drive once it gets inserted.
Since UDEV rules specifically mentions not to run long-time processes from RUN command, I send a FIFO message to my service which then opens the relevant process.
So the flow goes like this:
UDEV > runs action process > sends FIFO message to service > service gets message > runs the process who works with the HDD (aka HDD-PROCESS).
If I run my service from shell-1 and run 'action process' (the one that UDEV runs) from shell-2 everything works (including when trying it with udev).
But in deployment, the service is spawned from init, and when it does, the mount command fails saying "No such device".
I then detached "HDD-PROCESS" with fork and setsid, but that didn't help either.
from inittab:
::respawn:/opt/spwn_frm_init
ps relevant output:
PID PPID PGID SID COMM ARGS
31112 1 31112 31112 spwn_frm_init /bin/sh /opt/spwn_frm_init
31113 31112 31112 31112 runSvc /bin/sh /app/sys/runSvc
31114 31113 31112 31112 python python /app/sys/mainSvc.py
24064 1 24064 24064 python /usr/bin/python /app/sys/hdd_proc.py sdb1
everything runs under root (ps shows that too, I omitted that to save screen space).
So in short: when I run /opt/spwn_frm_init from shell, everything works. when I kill it and let it re-spawn from inittab, it doesn't and mount fails with error above.
UPDATE:
There is no problem when trying to mount an ext3 drive, but only on the NTFS one (using ntfs-3g).
Found it!
One of the differences between spawned process and another one who runs from shell is the environment variables which usually should be a problem when all I want is to call mount.
But when I noticed the problem happens only with the NTFS drive, it suddenly occurred to me that mount might need to call ntfs-3g so it worth checking if the second is accessible in the PATH variable.
which ntfs-3g led to /usr/local/bin/ntfs-3g which was mentioned in the default shell PATH but not in the one spawned from init.
To solve it, I added this /usr/local/bin to PATH in the "HDD-PROCESS" and mount began to work :)
A better error message in mount could have saved a lot of time here...

Simple replacement of init to just start console

On a very simple PC, I want to replace Ubuntu 12.04 /sbin/init by the most simple bash script in order to have the very minimum number of running processes. Obviously, no X, no USB, no detection of new hardware, no upgrade, no apt, "nothing", I just need a working console with a DHCP-based Wi-Fi IP address (ssid, passphrase are already stored in /etc/network/interfaces). That's all. Currently, I have tried this in replacement of /sbin/init:
#!/bin/sh
mount -o rw,remount /
mount -t proc none /proc
udevd --daemon
mkdir /run/network
ifup -a &
while [ 1 ]; do
/sbin/getty -8 115200 tty1 vt100
done
It's working as I'm getting an IP address and I can login but:
A) While running shutdown, I get "shutdown: Unable to shutdown system:"
B) control-c is not working in the console
C) After a login, I get: "bash: cannot set terminal process group (-1): Inappropriate ioctl for device"
D) After a login, I get: "bash: no job control in this shell"
Also, I have noticed that all the user-space processes have a "?" in the tty column when running ps avx. How can I fix those problems? I don't want to use upstart in order to really control what is started on the PC and have the very bare minimum.
I ended up using Busybox init. Great tiny init...
You could leverage runlevels and based on your question runlevel 3 is what you want to use.
If you have some services that you do not wish to start, you could turn them off too for that runlevel.
For booting into runlevel 3, you just append the boot argument to the kernel in your boot loader:
<EXISTING_BOOT_CMD> 3
If your distro uses systemd instead of sysvinit, they are instead called as targets. The equivalent of runlevel 3 in systemd is usually named as multi-user.target
The kernel boot argument you would need to pass in this case is systemd.unit=multi-user.target
<EXISTING_BOOT_CMD> systemd.unit=multi-user.target
An alternative, if you do not want to touch the boot loader:
systemctl enable multi-user.target

Activating a script using udev when power supply is connected/disconnected

I'm trying to get udev to run a couple of small scripts when I connect/disconnect the powersupply. I have the following code in /etc/udev/rules.d/50-caff.rules :
SUBSYSTEM=="power_supply", ENV{POWER_SUPPLY_STATUS}=="Charging", RUN+="/home/haukur/rules/off.sh"
SUBSYSTEM=="power_supply", ENV{POWER_SUPPLY_STATUS}=="Discharging", RUN+="/home/haukur/rules/on.sh"
Here is on.sh:
#!/bin/sh
caffeine -a
and off.sh:
#!/bin/sh
caffeine -d
Anyway, I wrote these, wrote udevadm control --reload-rules into bash and... nothing happened. caffeine doesn't appear to activate at all when I plug or unplug the power supply.
According to /var/log/syslog (Ubuntu's replacement for /var/log/messages) udev recognizes when I pull the plug:
Feb 26 08:44:52 (none) udevd[3838]: starting '/home/haukur/rules/off.sh'
but when it tries to run off.sh (which itself tries to run caffeine), it returns this error:
udevd[2719]: '/home/haukur/rules/off.sh'(err) '** (caffeine:3840): WARNING **: Command line `dbus-launch --autolaunch=62907743a139af9b3c86412e00000026 --binary-syntax --close-stderr' exited with non-zero exit status 1: Autolaunch error: X11 initialization failed.\n'
Do you know any way to get around this? Running Ubuntu 12.04 LTS with xmonad WM.
If the application "caffeine" needs to access you desktop, you probably need to export the DISPLAY before calling the program:
export DISPLAY=:0
You may simply prepend this to the command invocation:
DISPLAY=:0 caffeine -a

How to debug the Linux kernel with GDB and QEMU?

I'm new to kernel development and I would like to know how to run/debug the linux kernel using QEMU and gdb. I'm actually reading Robert Love's book but unfortunately it doesn't help the reader on how to install proper tools to run or debug the kernel... So what I did was to follow this tutorial http://opensourceforu.efytimes.com/2011/02/kernel-development-debugging-using-eclipse/. I'm using eclipse as an IDE to develop on the kernel but I wanted first to get it work under QEMU/gdb. So what I did so far was:
1) To compile the kernel with:
make defconfig (then setting the CONFIG_DEBUG_INFO=y in the .config)
make -j4
2) Once the compilation is over I run Qemu using:
qemu-system-x86_64 -s -S /dev/zero -kernel /arch/x86/boot/bzImage
which launch the kernel in "stopped" state
3) Thus I have to use gdb, I try the following command:
gdb ./vmlinux
which run it correctly but... Now I don't know what to do... I know that I have to use remote debugging on the port 1234 (default port used by Qemu), using the vmlinux as the symbol table file for debugging.
So my question is: What should I do to run the kernel on Qemu, attach my debugger to it and thus, get them work together to make my life easier with kernel development.
I'd try:
(gdb) target remote localhost:1234
(gdb) continue
Using the '-s' option makes qemu listen on port tcp::1234, which you can connect to as localhost:1234 if you are on the same machine. Qemu's '-S' option makes Qemu stop execution until you give the continue command.
Best thing would probably be to have a look at a decent GDB tutorial to get along with what you are doing. This one looks quite nice.
Step-by-step procedure tested on Ubuntu 16.10 host
To get started from scratch quickly I've made a minimal fully automated QEMU + Buildroot example at: https://github.com/cirosantilli/linux-kernel-module-cheat/blob/c7bbc6029af7f4fab0a23a380d1607df0b2a3701/gdb-step-debugging.md Major steps are covered below.
First get a root filesystem rootfs.cpio.gz. If you need one, consider:
a minimal init-only executable image: https://unix.stackexchange.com/questions/122717/custom-linux-distro-that-runs-just-one-program-nothing-else/238579#238579
a Busybox interactive system: https://unix.stackexchange.com/questions/2692/what-is-the-smallest-possible-linux-implementation/203902#203902
Then on the Linux kernel:
git checkout v4.15
make mrproper
make x86_64_defconfig
cat <<EOF >.config-fragment
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_KERNEL=y
CONFIG_GDB_SCRIPTS=y
EOF
./scripts/kconfig/merge_config.sh .config .config-fragment
make -j"$(nproc)"
qemu-system-x86_64 -kernel arch/x86/boot/bzImage \
-initrd rootfs.cpio.gz -S -s \
-append nokaslr
On another terminal, from inside the Linux kernel tree, supposing you want to start debugging from start_kernel:
gdb \
-ex "add-auto-load-safe-path $(pwd)" \
-ex "file vmlinux" \
-ex 'set arch i386:x86-64:intel' \
-ex 'target remote localhost:1234' \
-ex 'break start_kernel' \
-ex 'continue' \
-ex 'disconnect' \
-ex 'set arch i386:x86-64' \
-ex 'target remote localhost:1234'
and we are done!!
For kernel modules see: How to debug Linux kernel modules with QEMU?
For Ubuntu 14.04, GDB 7.7.1, hbreak was needed, break software breakpoints were ignored. Not the case anymore in 16.10. See also: https://bugs.launchpad.net/ubuntu/+source/qemu-kvm/+bug/901944
The messy disconnect and what come after it are to work around the error:
Remote 'g' packet reply is too long: 000000000000000017d11000008ef4810120008000000000fdfb8b07000000000d352828000000004040010000000000903fe081ffffffff883fe081ffffffff00000000000e0000ffffffffffe0ffffffffffff07ffffffffffffffff9fffff17d11000008ef4810000000000800000fffffffff8ffffffffff0000ffffffff2ddbf481ffffffff4600000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007f0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000801f0000
Related threads:
https://sourceware.org/bugzilla/show_bug.cgi?id=13984 might be a GDB bug
Remote 'g' packet reply is too long
http://wiki.osdev.org/QEMU_and_GDB_in_long_mode osdev.org is as usual an awesome source for these problems
https://lists.nongnu.org/archive/html/qemu-discuss/2014-10/msg00069.html
nokaslr: https://unix.stackexchange.com/questions/397939/turning-off-kaslr-to-debug-linux-kernel-using-qemu-and-gdb/421287#421287
Known limitations:
the Linux kernel does not support (and does not even compile without patches) with -O0: How to de-optimize the Linux kernel to and compile it with -O0?
GDB 7.11 will blow your memory on some types of tab completion, even after the max-completions fix: Tab completion interrupt for large binaries Likely some corner case which was not covered in that patch. So an ulimit -Sv 500000 is a wise action before debugging. Blew up specifically when I tab completed file<tab> for the filename argument of sys_execve as in: https://stackoverflow.com/a/42290593/895245
See also:
https://github.com/torvalds/linux/blob/v4.9/Documentation/dev-tools/gdb-kernel-debugging.rst official Linux kernel "documentation"
Linux kernel live debugging, how it's done and what tools are used?
When you try to start vmlinux exe using gdb, then first thing on gdb is to issue cmds:
(gdb) target remote localhost:1234
(gdb) break start_kernel
(continue)
This will break the kernel at start_kernel.
BjoernID's answer did not really work for me. After the first continuation, no breakpoint is reached and on interrupt, I would see lines such as:
0x0000000000000000 in ?? ()
(gdb) break rapl_pmu_init
Breakpoint 1 at 0xffffffff816631e7
(gdb) c
Continuing.
^CRemote 'g' packet reply is too long: 08793000000000002988d582000000002019[..]
I guess this has something to do with different CPU modes (real mode in BIOS vs. long mode when Linux has booted). Anyway, the solution is to run QEMU first without waiting (i.e. without -S):
qemu-system-x86_64 -enable-kvm -kernel arch/x86/boot/bzImage -cpu SandyBridge -s
In my case, I needed to break at something during boot, so after some deciseconds, I ran the gdb command. If you have more time (e.g. you need to debug a module that is loaded manually), then the timing doesn't really matter.
gdb allows you to specify commands that should be run when started. This makes automation a bit easier. To connect to QEMU (which should now already be started), break on a function and continue execution, use:
gdb -ex 'target remote localhost:1234' -ex 'break rapl_pmu_init' -ex c ./vmlinux
As for me the best solution for debugging the kernel - is to use gdb from Eclipse environment. You should just set appropriate port for gdb (must be the same with one you specified in qemu launch string) in remote debugging section. Here is the manual:
http://www.sw-at.com/blog/2011/02/11/linux-kernel-development-and-debugging-using-eclipse-cdt/
On Linux systems, vmlinux is a statically linked executable file that contains
the Linux kernel in one of the object file formats supported by Linux, which
includes ELF, COFF and a.out. The vmlinux file might be required for kernel
debugging, symbol table generation or other operations, but must be made
bootable before being used as an operating system kernel by adding a multiboot
header, bootsector and setup routines.
An image of this initial root file system must be stored somewhere accessible
by the Linux bootloader to the boot firmware of the computer. This can be the
root file system itself, a boot image on an optical disc, a small partition on
a local disk (a boot paratition, usually using ext4 or FAT file systems), or a
TFTP server (on systems that can boot from Ethernet).
Compile linux kernel
Build the kernel with this series applied, enabling CONFIG_DEBUG_INFO (but leave CONFIG_DEBUG_INFO_REDUCED off)
https://www.kernel.org/doc/html/latest/admin-guide/README.html
https://wiki.archlinux.org/index.php/Kernel/Traditional_compilation
https://lwn.net/Articles/533552/
Install GDB and Qemu
sudo pacman -S gdb qemu
Create initramfs
#!/bin/bash
# Os : Arch Linux
# Kernel : 5.0.3
INIT_DIR=$(pwd)
BBOX_URL="https://busybox.net/downloads/busybox-1.30.1.tar.bz2"
BBOX_FILENAME=$(basename ${BBOX_URL})
BBOX_DIRNAME=$(basename ${BBOX_FILENAME} ".tar.bz2")
RAM_FILENAME="${INIT_DIR}/initramfs.cpio.gz"
function download_busybox {
wget -c ${BBOX_URL} 2>/dev/null
}
function compile_busybox {
tar xvf ${BBOX_FILENAME} && cd "${INIT_DIR}/${BBOX_DIRNAME}/"
echo "[*] Settings > Build options > Build static binary (no shared libs)"
echo "[!] Please enter to continue"
read tmpvar
make menuconfig && make -j2 && make install
}
function config_busybox {
cd "${INIT_DIR}/${BBOX_DIRNAME}/"
rm -rf initramfs/ && cp -rf _install/ initramfs/
rm -f initramfs/linuxrc
mkdir -p initramfs/{dev,proc,sys}
sudo cp -a /dev/{null,console,tty,tty1,tty2,tty3,tty4} initramfs/dev/
cat > "${INIT_DIR}/${BBOX_DIRNAME}/initramfs/init" << EOF
#!/bin/busybox sh
mount -t proc none /proc
mount -t sysfs none /sys
exec /sbin/init
EOF
chmod a+x initramfs/init
cd "${INIT_DIR}/${BBOX_DIRNAME}/initramfs/"
find . -print0 | cpio --null -ov --format=newc | gzip -9 > "${RAM_FILENAME}"
echo "[*] output: ${RAM_FILENAME}"
}
download_busybox
compile_busybox
config_busybox
Boot Linux Kernel With Qemu
#!/bin/bash
KER_FILENAME="/home/debug/Projects/kernelbuild/linux-5.0.3/arch/x86/boot/bzImage"
RAM_FILENAME="/home/debug/Projects/kerneldebug/initramfs.cpio.gz"
qemu-system-x86_64 -s -kernel "${KER_FILENAME}" -initrd "${RAM_FILENAME}" -nographic -append "console=ttyS0"
$ ./qemuboot_vmlinux.sh
SeaBIOS (version 1.12.0-20181126_142135-anatol)
iPXE (http://ipxe.org) 00:03.0 C980 PCI2.10 PnP PMM+07F92120+07EF2120 C980
Booting from ROM...
Probing EDD (edd=off to disable)... o
[ 0.019814] Spectre V2 : Spectre mitigation: LFENCE not serializing, switching to generic retpoline
can't run '/etc/init.d/rcS': No such file or directory
Please press Enter to activate this console.
/ # uname -a
Linux archlinux 5.0.3 #2 SMP PREEMPT Mon Mar 25 10:27:13 CST 2019 x86_64 GNU/Linux
/ #
Debug Linux Kernel With GDB
~/Projects/kernelbuild/linux-5.0.3 ➭ gdb vmlinux
...
(gdb) target remote localhost:1234
Remote debugging using localhost:1234
0xffffffff89a4b852 in ?? ()
(gdb) break start_kernel
Breakpoint 1 at 0xffffffff826ccc08
(gdb)
Display all 190 possibilities? (y or n)
(gdb) info functions
All defined functions:
Non-debugging symbols:
0xffffffff81000000 _stext
0xffffffff81000000 _text
0xffffffff81000000 startup_64
0xffffffff81000030 secondary_startup_64
0xffffffff810000e0 verify_cpu
0xffffffff810001e0 start_cpu0
0xffffffff810001f0 __startup_64
0xffffffff81000410 pvh_start_xen
0xffffffff81001000 hypercall_page
0xffffffff81001000 xen_hypercall_set_trap_table
0xffffffff81001020 xen_hypercall_mmu_update
0xffffffff81001040 xen_hypercall_set_gdt
0xffffffff81001060 xen_hypercall_stack_switch
0xffffffff81001080 xen_hypercall_set_callbacks
0xffffffff810010a0 xen_hypercall_fpu_taskswitch
0xffffffff810010c0 xen_hypercall_sched_op_compat
0xffffffff810010e0 xen_hypercall_platform_op

Resources