Take the 2-minute tour ×
Ask Ubuntu is a question and answer site for Ubuntu users and developers. It's 100% free, no registration required.

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.

share|improve this question
    
As @Tuminoid pointed out, copying things in /etc/init sounds like a dirty way. Maybe you could describe a bit more detailed what should be different in the configurations? –  lumbric Mar 26 '12 at 17:25
    
If you just wish to configure system differently (and know your dependencies, such as mounts) you can do it all in the /sbin/preinit script. Just remember where you are - before "real" userspace, so mounts aren't there unless you mount them etc. Looking at your long answer, you basically just wish to modify gdm custom conf, so I don't see any reason why you need to mess with /etc/init at all: just do it all in the preinit script and in the end just exec init exec /sbin/init and it boots normally. –  Tuminoid Apr 10 '12 at 8:59
    
The problem I'm having @Tuminoid, is that the script is not prompting me at start up to make a choice. I've clarified six steps. Have I missed a step somewhere? –  bambuntu Apr 14 '12 at 18:52

2 Answers 2

up vote 1 down vote accepted

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.

share|improve this answer
    
Hey, I'm trying understand your answer better. Could you help me with step 11 in my edited question? –  bambuntu Apr 6 '12 at 15:49
    
@bambuntu Following my suggestion, the script is totaly independent from the grub menu. It just reads the selection from /proc/cmdline. It depends what you want to do and when it should run where you should place it. This can be in /etc/rc.local, a run level script or even after user login to start several application (as in the linked Q&A). I don't know enough details about the upstart config files in /etc/init to tell you how this could work. But Tuminoid's solution might be a better approach in your case, I'm not sure. –  lumbric Apr 6 '12 at 16:16
    
So, I just place the script in /etc and it will run fine with no other change neccessary? –  bambuntu Apr 6 '12 at 16:18
    
@bambuntu Sorry, I hit ENTER accidentally. BTW: Your step-by-step explanation is great, but probably it would be better to edit our answers instead your question. –  lumbric Apr 6 '12 at 16:21
    
it should run as soon as possible, because it decides between two users on which will be the one to auto-login. I will be placing a file in /etc/gdm/custom.conf that automatically logs in that user. –  bambuntu Apr 6 '12 at 16:31

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 than startup and you can build your boot-up to whatever you like.

For example, put something like this into /sbin/preinit:

#!/bin/sh 
EVENT="startup" 
while [ /bin/true ]; do   
  echo "Select boot:"   
  echo " 1) Normal"   
  echo " 2) Minimal"  
  echo " 3) Foobar"  
  echo ""   
  read selection   
  case "$selection" in 
2)   
  EVENT="minimal-startup"   
  ;; 
3)   
  EVENT="foobar-startup"   
  ;;
*)   
  ;;   
  esac 
done

exec /sbin/init --startup-event=$EVENT

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.

share|improve this answer
    
I'm a little unclear on this. Do you that I should use initctl emit signal for choosing a set of start up scripts? That I should use the script above to emit a set of signals based on the users choice here? If so, so good. But, I'm unfamiliear with the meaning of this script above. Is this going to replace my grub menu? Could you clearify? –  bambuntu Mar 30 '12 at 21:38
    
No, you should set init=/sbin/preinit kernel command line to your grub config, which then runs this script that allows you to exec init (Upstart) with a different startup signals. Normally execution of jobs begin with startup event, but if this signal isn't the default, Upstart runs nothing. So you will then create a job that has start on minimal-startup, which then launches what you wish. –  Tuminoid Mar 31 '12 at 11:07
    
@bambuntu I explained detailed in the answer I linked in my answer how to add options to the Grub menu. –  lumbric Mar 31 '12 at 12:01
    
@Tuminoid Could see my question again. I've edited it to try to create a step solution. I need your help. –  bambuntu Apr 6 '12 at 1:58
    
That EVENT is not meaning a filename in /etc/init. The file can be named anything, like /etc/init/config-1.conf. It just MUST have start on <EVENT> in it, such as start on minimal-startup to get it triggered to start. –  Tuminoid Apr 10 '12 at 8:54

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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