Fedora live CD and VNC

I was installing the latest Fedora 21 via Unetbootin-built USB and had an issue with monitors. They were in a vertical position and could not be easily rotated. I did not have a spare monitor to attach in a horizontal orientation.

The machine in question had a Nvidia GT 730 graphic card. By default Xorg chooses to use nouveau drivers. For some reason, they do not allow the rotation of the screen via xrandr – the output was:

$ xrandr -q
...
default connected 1920x1080+0+0 0mm x 0mm
...
$ xrandr --output default --rotate left
xrandr: output default cannot use rotation "left" reflection "none"

I tried installing proprietary nvidia drivers, using the instructions here:

However, that did not work – looks like it was running out of space on the root mount, which had this:

Filesystem           Size  Used  Avail Use% Mounted on
/dev/mapper/live-rw  2.9G  2.4G   538M  82% /

Running the given commands:

$ su -c 'yum localinstall --nogpgcheck http://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm http://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm'
$ yum install akmod-nvidia-304xx "kernel-devel-uname-r == $(uname -r)"
yum update -y

resulted in IO issues. Might have been just a faulty USB. :)

Anyway, I opted to use my laptop and set up a VNC connection instead. Here are the steps:

  • Install TigerVNC

Instructions here: http://docs.fedoraproject.org/en-US/Fedora/21/html/System_Administrators_Guide/ch-TigerVNC.html

root# yum install tigervnc-server
root# cp /lib/systemd/system/vncserver@.service /etc/systemd/system/vncserver@.service
  • Configure TigerVNC

Edit VNC server systemd config:

root# vi /etc/systemd/system/vncserver@.service

and change to liveuser, add geometry parameter as appropriate for your situation

  • Update SELinux policy

Due to this bug: https://bugzilla.redhat.com/show_bug.cgi?id=1062968

root# yum update selinux-policy

In my case, this updated selinux-policy to 3.13.1-105.9.fc21 and worked fine with it.

  • Set up the password
liveuser$ vncpasswd
  • Enable VNC port

Credits: http://www.howopensource.com/2011/08/vnc-error-unable-to-connect-to-host-no-route-to-host-113-solved/

root# iptables -I INPUT 1 -p tcp --dport 5901 -j ACCEPT
  • Reload the configuration and start the server
root# systemctl daemon-reload
root# systemctl start vncserver@:1.service

Credits: http://forums.fedoraforum.org/showthread.php?t=272137&page=4

Edit VNC xstartup file:

liveuser$ vi ~/.vnc/xstartup

Comment out this line:

exec /etc/X11/xinit/xinitrc

Add this line at the end:

/usr/bin/xfce4-session &

Restart VNC server:

root# systemctl restart vncserver@:1.service

Now you should have a running VNC server that you can access with some VNC client. I used vinagre as the laptop had Xubuntu, but any other should work. Fedora installation worked fine using this setup and was really quick.

The nicest thing – VNC session was horizontal :).


Basic X Window keyboard and mouse input blocking

Here’s a small Python script using python-xlib that will block the keyboard and mouse input and then display random-colored, random-sized rectangles whenever an event happens. I tested it in Xubuntu 14.10, not sure if it is possible to run on non-Linux platforms. Obviously, you’ll need to install python-xlib. I use virtualenv to do that, but there’s also a “regular” Debian package available.

from Xlib import Xatom, Xutil
from Xlib.display import Display, X
import sys
import signal 
import random

class bunch(dict):
  __getattr__ = dict.__getitem__
  __setattr__ = dict.__setitem__

def check_for_magic_keys(state, event):
  keys = state['keys']
  if event.type == X.KeyPress:
    keys[event.detail] = True
  elif event.type == X.KeyRelease:
    keys[event.detail] = False

  keycode_alt = 64
  keycode_1 = 10
  keycode_delete = 119

  magic_keys = keys.get(keycode_alt) and keys.get(keycode_1) and keys.get(keycode_delete)
  if magic_keys:
    print("Magic keys pressed, exiting")
    return True

  return False

def random_color(screen):
  red = random.randrange(0, 65536)
  green = random.randrange(0, 65536)
  blue = random.randrange(0, 65536)

  return screen.default_colormap.alloc_color(red, green, blue).pixel

def random_rectangle(screen, window):
  x = random.randrange(0, screen.width_in_pixels)
  y = random.randrange(0, screen.height_in_pixels)
  width = random.randrange(0, screen.width_in_pixels - x)
  height = random.randrange(0, screen.height_in_pixels - y)

  window.window.fill_rectangle(
    gc = window.gc,
    x = x,
    y = y,
    width  = width,
    height = height,
  )

def draw(state, event):
  screen = state.display.screen()
  foreground = random_color(screen)
  background = random_color(screen)

  state.window.gc.change(
    foreground = foreground,
    background = background,
  )

  random_rectangle(screen, state.window)

def handle_event(state, event):
  debug = False
  if debug:
    print(event)
    return True

  if check_for_magic_keys(state, event):
    return False

  draw(state, event)
  return True

def grab_keyboard_and_mouse(root):
  root.grab_keyboard(
    owner_events = True,
    pointer_mode = X.GrabModeAsync,
    keyboard_mode = X.GrabModeAsync,
    time = X.CurrentTime
  )
  
  root.grab_pointer(
    owner_events = True,
    event_mask = X.ButtonPressMask | X.ButtonReleaseMask | X.PointerMotionMask,
    pointer_mode = X.GrabModeAsync,
    keyboard_mode = X.GrabModeAsync,
    confine_to = 0,
    cursor = 0,
    time = X.CurrentTime
  )

def create_window(display, root):
  screen = display.screen()

  window = root.create_window(
    x = 0,
    y = 0,
    width = screen.width_in_pixels,
    height = screen.height_in_pixels,
    border_width = 0,
    depth = screen.root_depth)
  
  atom_net_wm_state = display.intern_atom('_NET_WM_STATE', True)
  atom_net_wm_state_fullscreen = display.intern_atom('_NET_WM_STATE_FULLSCREEN', True)

  window.change_property(
    property = atom_net_wm_state,
    type = Xatom.ATOM,
    format = 32,
    data = [atom_net_wm_state_fullscreen], 
  )

  window.set_wm_normal_hints(
    flags = Xutil.PPosition | Xutil.PSize | Xutil.PMinSize,
    min_width = screen.width_in_pixels,
    min_height = screen.height_in_pixels,
  )

  gc = window.create_gc(
    foreground = screen.black_pixel,
    background = screen.white_pixel,
  )

  return bunch(window = window, gc = gc)

def event_loop(state):
  display = state.display

  while True:
    event = display.next_event()
    display.allow_events(
      mode = X.AsyncBoth,
      time = X.CurrentTime)            

    if not handle_event(state, event):
      break

def main():
  display = Display()
  root = display.screen().root

  grab_keyboard_and_mouse(root)
  window = create_window(display, root)
  window.window.map()

  state = bunch(
    display = display,
    root = root,
    window = window,
    keys = bunch())

  # Comment these out after you have confirmed the magic key works
  signal.signal(signal.SIGALRM, lambda a, b: sys.exit(1))
  signal.alarm(4)

  event_loop(state)

if __name__ == '__main__':
  main()

How it works:

  • It creates a window that covers the whole desktop
  • It then grabs both the key and the mouse input
  • Whenever an event happens, it will first check for a magic key
  • If it is a magic key, it will exit
  • If it is not a magic key, it will display a random rectangle and continue to run

The magic key is currently set to Alt + 1 + Del, pressed at the same time. There’s also a small debug section in the event loop that can be enabled by setting debug = True. Printing events like this allows for reconfiguration if needed, e.g. to change the magic key.

The above version has the signal.alarm call – I left this there, so that it exits after 4 seconds while testing. Otherwise, if it doesn’t work, you have no input. Well, actually you do – I found that Alt + F1 works, so you can escape to a console and kill the python process, but while testing I found it easier to just do a timed exit. In order to be used for longer periods, the signal lines should be commented out.


Grub2 multiple ISO booting

I recently needed to boot from a USB key to install Xubuntu, in my case Xubuntu 11.04 using alternate CD. I used Unetbootin before for this job, however one thing I did not like is that it expands the ISO onto the USB. While this can be beneficial in some cases – e.g. when you actually want to change the files already present on the ISO, I wanted to just drop ISO onto the USB key and boot from it verbatim. Here’s what worked for me using Grub2.

VM for testing

I’m going to use Qemu VM for testing this. The VM will have a small HDD, a DVD reader and a USB key. To simulate the HDD and USB key, let’s create two images:

$ qemu-img create -f qcow2 sda.img 5G
$ qemu-img create -f qcow2 sdb.img 1G

sda is the HDD, sdb is the USB stick. I will put the following distributions there and add them to the Grub2 boot menu:

 30M slitaz-3.0.iso
 11M tinycore_3.8.4.iso
640M xubuntu-11.04-alternate-amd64.iso

In order to actually do this, I downloaded the desktop variant of Xubuntu 11.04. I’ll use it to boot the VM initially and prepare the USB stick from within VM.

Here are the links you can use to download these:

Obviously, you can use other versions, especially if newer ones come in in the meantime, or try other distributions. Note also that Xubuntu links from the above are amd64 versions, so if you want 32-bit check this page.

Starting the VM

First, let’s boot Xubuntu 11.04 desktop:

$ qemu-system-x86_64 -m 512 -hda sda.img -hdb sdb.img -cdrom xubuntu-11.04-desktop-amd64.iso -boot d

Choose the first option “Try Xubuntu without installing” and boot the Xubuntu. When it boots, open the terminal by right clicking on the desktop and choosing Applications/Accessories/Terminal Emulator. Let’s confirm we have both disks as expected:

ubuntu@ubuntu:~$ sudo fdisk -cul
Disk /dev/sda: 5368 MB, 5368709120 bytes
255 heads, 63 sectors/track, 652 cylinders, total 10485760 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0xa9af789e

Disk /dev/sda doesn't contain a valid partition table

Disk /dev/sdb: 1073 MB, 1073741824 bytes
139 heads, 8 sectors/track, 1885 cylinders, total 2097152 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x5e2afaf3

Disk /dev/sdb doesn't contain a valid partition table

Let’s make a LVM partition on sda:

ubuntu@ubuntu:~$ sudo fdisk -cu /dev/sda
Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel
Building a new DOS disklabel with disk identifier 0xa9af789e.
Changes will remain in memory only, until you decide to write them.
After that, of course, the previous content won't be recoverable.

Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite)

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 1
First sector (2048-10485759, default 2048): 
Using default value 2048
Last sector, +sectors or +size{K,M,G} (2048-10485750, default 10485759): 
Using default value 10485759

Command (m for help): t
Selected partition 1
Hex code (type L to list codes): 8e
Changed system type of partition 1 to 8e (Linux LVM)

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.

and a Linux partition on sdb:

ubuntu@ubuntu:~$ sudo fdisk -cu /dev/sdb
Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel
Building a new DOS disklabel with disk identifier 0x5e2afaf3.
Changes will remain in memory only, until you decide to write them.
After that, of course, the previous content won't be recoverable.

Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite)

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 1
First sector (2048-2097151, default 2048): 
Using default value 2048
Last sector, +sectors or +size{K,M,G} (2048-2097151, default 2097151): 
Using default value 2097151

Command (m for help): a
Partition number (1-4): 1

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.

Let’s now format /dev/sdb1 as ext4:

ubuntu@ubuntu:~$ sudo mkfs.ext4 /dev/sdb1
mke2fs 1.41.14 (22-Dec-2010)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
65536 inodes, 261888 blocks
13094 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=268435456
8 block groups
32768 blocks per group, 32768 fragments per group
8192 inodes per group
Superblock backups stored on blocks: 
    32768, 98304, 163840, 229376

Writing inode tables: done                            
Creating journal (4096 blocks): done
Writing superblocks and filesystem accounting information: done

This filesystem will be automatically checked every 32 mounts or
180 days, whichever comes first.  Use tune2fs -c or -i to override.

Note other partition types should work – e.g. vfat might be a better choice if you have Windows machines around that might access this USB.

We have all set up now to install and configure Grub2.

Copying the ISO files from host to guest USB stick

Qemu has a built-in router that exposes host within the guest on IP 10.0.2.2. This can be used to communicate with the host and can be handy when copying files between hosts. My host is Ubuntu 11.10-beta1, but should not matter going forward. I will be using SMB with Samba to copy this. First, make sure you have a share on the host and that all ISO files are there. To create a share on the host from command line, you can do this:

$ net usershare add isos /path/to/isos "" "" guest_ok=y

The above adds a share called isos to the path where you saved isos (/path/to/isos) and allows guest access.

From within guest, we’ll mount this, but in Xubuntu 11.04 desktop live CD we need to install smbfs first. Here are all the steps:

ubuntu@ubuntu:~$ sudo apt-get install smbfs
... <installation information> ...
ubuntu@ubuntu:~$ mkdir isos
ubuntu@ubuntu:~$ sudo smbmount //10.0.2.2/isos isos
Password:
ubuntu@ubuntu:~$ cd isos
ubuntu@ubuntu:~/isos$ ls -1hs
total 1.5G
 30M slitaz-3.0.iso
 11M tinycore_3.8.4.iso
640M xubuntu-11.04-alternate-amd64.iso
688M xubuntu-11.04-desktop-amd64.iso

Let’s copy all but the desktop ISO to our USB stick:

ubuntu@ubuntu:~$ mkdir sdb1
ubuntu@ubuntu:~$ sudo mount /dev/sdb1 sdb1
ubuntu@ubuntu:~$ mkdir sdb1/isos
ubuntu@ubuntu:~/isos$ sudo cp lubu-528.iso slitaz-3.0.iso tinycore_3.8.4.iso xubuntu-11.04-alternate-amd64.iso ~/sdb1/isos
ubuntu@ubuntu:~/isos$ cd ..
ubuntu@ubuntu:~$

This will take a few minutes to complete.

Installing Grub2

We can install Grub2 using this:

ubuntu@ubuntu:~$ sudo grub-install --root-directory=sdb1 /dev/sdb
Installation finished. No error reported.

The only thing left is to make a configuration with the above-mentioned distributions:

ubuntu@ubuntu:~$ cd ~/sdb1/boot/grub
ubuntu@ubuntu:~/sdb1/boot/grub$ sudo sh -c "cat > grub.cfg"
menuentry "SliTaz 3.0" {
  set iso=/isos/slitaz-3.0.iso
  loopback loop $iso
  linux (loop)/boot/bzImage isofrom=$iso boot=live --
  initrd (loop)/boot/rootfs.gz autologin
}
menuentry "Tinycore 3.8.4" {
  loopback loop /isos/tinycore_3.8.4.iso
  linux (loop)/boot/bzImage --
  initrd (loop)/boot/tinycore.gz
}
menuentry "Xubuntu 11.04 alternate" {
  set iso=/isos/xubuntu-11.04-alternate-amd64.iso
  loopback loop $iso
  linux (loop)/install/vmlinuz findiso=$iso file=/cdrom/preseed/xubuntu.seed quiet --
  initrd  (loop)/install/initrd.gz
}
^D
ubuntu@ubuntu:~/sdb1/boot/grub$ cd 
ubuntu@ubuntu:~$ sudo umount sdb1
ubuntu@ubuntu:~$ sudo umount isos

^D means press Ctrl+D to send EOF to cat. After this, we are all set to try to boot from our newly created USB stick. Close the current Qemu instance and launch another one like this:

$ qemu-system-x86_64 -m 512 -hda sdb.img -hdb sda.img -boot c

Note that the order is reversed, as we can only boot from the first HDD. You should be presented with the menu we just created and be able to boot the 3 distributions.

Installing Xubuntu 11.04 alternate on the above system

You may be wondering why I have a 5GB /dev/sda (well, /dev/sdb now after exchanging sda and sdb to be able to boot from USB) at all. I used this to test Xubuntu install before I installed on a physical machine. Anyway, this worked pretty much excellent provided one additional step on VM. Not sure if this is related to using ext4 on the USB, but if I’m not mistaken doing this on a physical machine worked fine without any intervention. Anyway, the issue was that Xubuntu alternate installer could not detect the CD-ROM, even though findiso parameter has been supplied. This was easy to fix – go to the second console (Alt-F2) and do this:

$ mv /dev/sr0 /dev/sr0a
$ mount /dev/sda1 /mnt
$ ln -s /mnt/isos/xubuntu-11.04-alternate-amd64.iso /dev/sr0

This will basically put the Xubuntu alternate CD in place of what really should be CD-ROM (/dev/sr0 in this case). Now just repeat the CD-ROM detection step and you’ll be all set. Installing Xubuntu went like a charm from withing Qemu and also on another physical machine.