#!/usr/bin/python

# (c) 2006 - Oliver Grawert (Canonical Ltd.)
# (c) 2006 - Scott Balneaves
# 
# cdpinger - a cdrom monitoring script for ltsp local devices 
#
# This software is distributed under the terms and conditions of the
# GNU General Public License. See file GPL for the full text of the license.
#

import sys
import fcntl
import os
import CDROM
import time
from subprocess import *

def make_mountpoint(mountpoint):
    mountpoint_exists=os.access(mountpoint, 0)
    if not mountpoint_exists:
        os.mkdir(mountpoint)

def remove_mountpoint(mountpoint):
    mountpoint_exists=os.access(mountpoint, 0)
    if mountpoint_exists:
        os.rmdir(mountpoint)

def get_login():
   if os.path.exists('/tmp/.ltspfs-socket'):
       p1=Popen(["/usr/bin/lsof", "/tmp/.ltspfs-socket"], stdout=PIPE)
       p2 = Popen(["grep", "ssh"], stdin=p1.stdout, stdout=PIPE)
       pid = p2.communicate()[0].split()[1].strip()
   else:
       return False
   if pid:
       proc='/proc/'+pid+'/cmdline'
       fd = open(proc, 'r')
       cmdline = fd.read().split('\x00')
       fd.close()
       for item in cmdline:
           if item.find('@') > 0:
               return item
   else:
       return False

def manage_fstab(device, mountpoint, option):
    fd = open('/etc/fstab', 'r')
    fstablines = fd.readlines()
    fd.close()
    if option=='add':
        fstablines.append(device + " " + mountpoint + " auto defaults 0 0\n")
        fd = open("/etc/fstab", 'w')
        fd.writelines(fstablines)
        fd.close()
    elif option=='remove':
        for i in range(len(fstablines)):
            if fstablines[i].find(device) >= 0:
                del fstablines[i]
                fd = open("/etc/fstab", 'w')
                fd.writelines(fstablines)
                fd.close()
                break

def do_ltspmount(mountpoint, option):
    fd = open('/etc/fstab', 'r')
    if fd.read().find(mountpoint) > 0:
        user=get_login()
        if user:
            call(['/usr/bin/ssh', '-S', '/tmp/.ltspfs-socket', user,
                  '/usr/sbin/ltspfsmounter', mountpoint, option])
        else:
            if os.path.exists('/var/run/.delayed-mount'):
                out = open('/var/run/.delayed-mount', 'a')
                out.write(mountpoint+" cdrom auto\n")
                out.close()
    fd.close()

def main():
    devicename=sys.argv[1]
    mountpointname=devicename

    # merge default paths
    mountpoint="/var/run/drives/"+mountpointname
    device="/dev/"+devicename
    flag=False

    while True:
        if os.path.islink(device):
            make_mountpoint(mountpoint)
            f=os.open(device, os.O_RDONLY|os.O_NONBLOCK)
            fcntl.ioctl(f, CDROM.CDROM_LOCKDOOR, 0)
            stat = fcntl.ioctl(f, CDROM.CDROM_DRIVE_STATUS, 0)
            if stat == CDROM.CDS_NO_DISC or stat == CDROM.CDS_TRAY_OPEN:
                do_ltspmount(mountpoint, 'remove')
                manage_fstab(device, mountpoint, 'remove')
                flag=False
            elif stat == CDROM.CDS_DISC_OK:
                if fcntl.ioctl(f, CDROM.CDROM_MEDIA_CHANGED, 0):
                    manage_fstab(device, mountpoint, 'add')
                    do_ltspmount(mountpoint, 'add')
                    flag=True
            os.close(f)
        else:
            # clean up if necessary
            if flag:
                do_ltspmount(mountpoint, 'remove')
                flag=False
        time.sleep(3)

if __name__ == "__main__":
    # do the UNIX double-fork magic, see Stevens' "Advanced 
    # Programming in the UNIX Environment" for details (ISBN 0201563177)
    try:
        pid = os.fork()
        if pid > 0:
            # exit first parent
            sys.exit(0)
    except OSError, e:
        print >>sys.stderr, "fork #1 failed: %d (%s)" % (e.errno, e.strerror)
        sys.exit(1)

    # decouple from parent environment
    os.chdir("/")
    os.setsid()
    os.umask(0)

    # do second fork
    try:
        pid = os.fork()
        if pid > 0:
            sys.exit(0)
    except OSError, e:
        print >>sys.stderr, "fork #2 failed: %d (%s)" % (e.errno, e.strerror)
        sys.exit(1)

    # start the daemon main loop
    main()
