I want to create a boot up potential which allows a different upstart/runlevel configurations to load based upon specific key downs at boot (or combos). How do I detect a key down event with an upstart script?
I'm on 10.04 if that helps.
Alternative methods to achieve the same result are acceptable, i.e., How can I use grub to do this?
To help provide more clarity, I am creating a step by step instruction based upon both answers given by Tuminoid and Lumbric. (Please help me improve this, my interpretation of Tuminoid's answer does not work.)
Note: Everyone must have a reason for doing this. To give meaning to the following two Step-by-Step Solutions, I'll describe my purpose for wanting to have upstart scripts decided at boot.
I am creating a Live DVD for surfing the Internet called Surfer. For security, I want to disable the admin account and leave a non-privileged account for surfing the web. I also want to give myself and users the ability to remaster Surfer so they can add more online apps and customise their Surfer account, then burn their own live custom Surfer iso. So I will need two boot profiles: Surfer and Remaster. One for secure online surfing, the other for remastering and development.
Lumbric's Solution
Create a Custom grub File
1. To add custom entries to grub, open this file with gedit for editing:
gksudo gedit /etc/grub.d/40_custom
You will have the right file if you see this text in it:
#!/bin/sh
exec tail -n +3 $0
# This file provides an easy way to add custom menu entries. Simply type the
# menu entries you want to add after this comment. Be careful not to change
# the 'exec tail' line above.
2. In another gedit tab, open:
/boot/grub/grub.cfg
3. In grub.cfg, look for sections that begin with:
menuentry
Choose the default entry you use for booting. If you do not know the default entry by looking at this file, then reboot and take a note of the one you pick at boot. Do not save any changes if you have to reboot to find your default entry. When you are positive of your default entry, keep note that this is the entry to use for your custom profiles.
Each menuentry section will have some corresponding set of brackets:
menuentry ...text left out... { ...text left out... }
that encapsulate a few lines of text. Copy the your default entry section. Copy from the word menuentry to the closing bracket. I will need two entries, so I will paste my default entry twice.
It should look something like the following for two custom boot profile entries. (Keep in mind I took out text to make this easier to read):
#!/bin/sh
exec tail -n +3 $0
# This file provides an easy way to add custom menu entries. Simply type the
# menu entries you want to add after this comment. Be careful not to change
# the 'exec tail' line above.
menuentry ...text left out... {
...text left out...
}
menuentry ...text left out... {
...text left out...
}
4. Find your boot line by pressing ctrl + f. Type in the search field:
linux /boot
Each boot line will should be highlighted.
5. Cut and paste this text at the end of the highlighted boot line, but change the number for each entry.
boot-profile=1
After pasting, the menu entry should look similar to this:
menuentry ...text left out... {
...text left out...
linux /boot/vmlinuz-2.6.35-22-generic root=UUID=66cdrfwec91-0070-32f-b666-c9f2232j23232j ro quiet splash boot-profile=1
}
menuentry ...text left out... {
...text left out...
linux /boot/vmlinuz-2.6.35-22-generic root=UUID=66cdrfwec91-0070-32f-b666-c9f2232j23232j ro quiet splash boot-profile=2
}
6. Now, we will edit the line we see at boot. For the menu entry identified above, edit the text that is between the word menuentry and the first bracket. Replace with the text Surfer:
menuentry "Surfer" {
...text left out...
linux /boot/vmlinuz-2.6.35-22-generic root=UUID=66cdrfwec91-0070-32f-b666-c9f2232j23232j ro quiet splash boot-profile=1
}
Do the same for Remaster entry:
menuentry "Remaster" {
...text left out...
linux /boot/vmlinuz-2.6.35-22-generic root=UUID=66cdrfwec91-0070-32f-b666-c9f2232j23232j ro quiet splash boot-profile=2
}
7. Save the file 40_custom.
8. Now, update grub with this command:
sudo update-grub
Note: If you do any upgrading or installation of programs that modify your kernel, be aware of lumbric's point made in his link. How can we know if our kernel is going to be upgraded? Help me clarify how we can prevent upgrading our kernel without knowing it.
9. Reboot. When at the boot menu, look for your new entries. If you see them, things are going great so far. Choose one of your custom entries and hit enter.
10. When logged in, open up Terminal. Enter this command.
cat /proc/cmdline
Grub writes the boot line to this file. The boot line is where you added boot-profile=1 at the end. So, if you chose surfer, then it should read boot-profile=1 at the end or boot-profile=2 if you chose Remaster. If not, reread from step one and correct any logical errors.
11. Now, the script must be written that will handle the boot entry chosen from grub menu. I'm choosing to use an upstart script, because I know how to do that. The upstart will start as soon as possible, check the contents of /proc/cmdline and use that to determine our choice at the boot menu. Here is the upstart start script:
/etc/bootChoice.conf
12. Past the following text in:
task
start on startup or bootChoice
script
profile=$(cat /proc/cmdline |sed 's/.*boot-profile=\([0-9]\).*/\1/g')
case $profile in
1)
# Run script for Surfer Profile
initctl emit surferboot
;;
2)
# Run script for Remaster Profile
initctl emit remasterboot
;;
*)
echo Error
echo "Error" > /error
;;
esac
end script
13. Now, a signal will be emitted based on our choice. In order to handle each signal, two files must be created. One called: surfer.conf and another called remaster.conf. Place them in /etc/init/. Their contents will be similar to this:
# surfer user boot
task
start on surferboot
script
echo "surfer test-data" > /home/surfer/surfer
end script
We can see that when the surferboot signal is emitted, that the script above is started determined by this line: start on surferboot
Place all custom boot script code between script
and end script
. Same thing will be done for Remaster.
I tried this, it works. Thanks Lumbric.
Tuminoid's Solution
First, we must let grub know we want to call a script. We will place the path of the script inside /etc/default/grub.
1. Open the file: /etc/default/grub.
gksudo gedit /etc/default/grub
2. Add this line at the end of the file:
init=/sbin/preinit
3. Save and exit. Then, run this command:
update-grub
Now we will create the file that we made grub aware of.
4. Create the file with gedit:
gksudo gedit /sbin/preinit
5. Paste the following text inside:
#!/bin/sh EVENT="startup" while [ /bin/true ]; do echo "Select boot:" echo " 1) Surfer" echo " 2) Remaster" echo "" read selection case "$selection" in 1) EVENT="surfer" ;; 2) EVENT="remaster" ;; *) ;; esac done exec /sbin/init --startup-event=$EVENT
6. Make the script executable:
chmod +x /sbin/preinit
WIP NOTE: I've tried this up to this point and it does not work. Please help improve this interpretation of the answer by pointing out where I am going wrong.
Last Section: This section unfinished. Waiting for clarity on first steps to finish.
The events above are upstart signals. If you haven't used upstart signals, they will call a script in the directory: /etc/init. So, I will make two files in /etc/init called:
/etc/init/surfer.conf
/etc/init/remaster.conf
In these files I will use bash scripts to configure each boot.
I will create at upstart /etc/gdm/custom.conf to force an auto-login if Surfer is chosen. I will also open /etc/shadow and disable remasters password.
Alternatively, I will create /etc/gdm/custom.conf for a forced auto-login to the user remaster for remastering and development.
To catch a Shift key down event during boot seems to be an interesting task, but I have to no idea how to achieve this. But I described in a recent Q&A how to use the GRUB menu in order to run different start up scripts after login.
The script from Step 3 is meant to run after login, but it can be placed also in
/etc/rcXY
.You cannot do that for an Upstart script. They are non-interactive by nature.
What you could do is make a Grub menu entry that points to a a shell script as an init, prompt you for a type of boot you want (or interact with you in anyway you like) and then at the end do
exec /sbin/init --startup-event=<type of boot>
. This causes Upstart's startup event be something else thanstartup
and you can build your boot-up to whatever you like.For example, put something like this into
/sbin/preinit
:Using this solution, you don't need to copy /etc/init around, but can have nice static set of jobs, that just execute based on different start signal.