Home | History | Annotate | Download | only in scripts
      1 #!/usr/bin/python
      2 # -*- coding: utf-8 -*-
      3 """
      4 Auxiliary script used to send data between ports on guests.
      5 
      6 @copyright: 2010 Red Hat, Inc.
      7 @author: Jiri Zupka (jzupka (at] redhat.com)
      8 @author: Lukas Doktor (ldoktor (at] redhat.com)
      9 """
     10 import threading
     11 from threading import Thread
     12 import os, select, re, random, sys, array, stat
     13 import fcntl, traceback, signal, time
     14 
     15 DEBUGPATH = "/sys/kernel/debug"
     16 SYSFSPATH = "/sys/class/virtio-ports/"
     17 DEVPATH = "/dev/virtio-ports/"
     18 
     19 exiting = False
     20 
     21 class VirtioGuest:
     22     """
     23     Test tools of virtio_ports.
     24     """
     25     LOOP_NONE = 0
     26     LOOP_POLL = 1
     27     LOOP_SELECT = 2
     28 
     29     def __init__(self):
     30         self.files = {}
     31         self.exit_thread = threading.Event()
     32         self.threads = []
     33         self.ports = {}
     34         self.poll_fds = {}
     35         self.catch_signal = None
     36         self.use_config = threading.Event()
     37 
     38 
     39     def _readfile(self, name):
     40         """
     41         Read file and return content as string
     42 
     43         @param name: Name of file
     44         @return: Content of file as string
     45         """
     46         out = ""
     47         try:
     48             f = open(name, "r")
     49             out = f.read()
     50             f.close()
     51         except:
     52             print "FAIL: Cannot open file %s" % (name)
     53 
     54         return out
     55 
     56 
     57     def _get_port_status(self, in_files=None):
     58         """
     59         Get info about ports from kernel debugfs.
     60 
     61         @param in_files: Array of input files.
     62         @return: Ports dictionary of port properties
     63         """
     64         ports = {}
     65         not_present_msg = "FAIL: There's no virtio-ports dir in debugfs"
     66         if not os.path.ismount(DEBUGPATH):
     67             os.system('mount -t debugfs none %s' % (DEBUGPATH))
     68         try:
     69             if not os.path.isdir('%s/virtio-ports' % (DEBUGPATH)):
     70                 print not_present_msg
     71         except:
     72             print not_present_msg
     73         else:
     74             viop_names = os.listdir('%s/virtio-ports' % (DEBUGPATH))
     75             if in_files is not None:
     76                 dev_names = os.listdir('/dev')
     77                 rep = re.compile(r"vport[0-9]p[0-9]+")
     78                 dev_names = filter(lambda x: rep.match(x) is not None, dev_names)
     79                 if len(dev_names) != len(in_files):
     80                     print ("FAIL: Not all ports were successfully initialized "
     81                            "in /dev, only %d from %d." % (len(dev_names),
     82                                                           len(in_files)))
     83                     return
     84 
     85                 if len(viop_names) != len(in_files):
     86                     print ("FAIL: Not all ports were successfuly initialized "
     87                            "in debugfs, only %d from %d." % (len(viop_names),
     88                                                              len(in_files)))
     89                     return
     90 
     91             for name in viop_names:
     92                 open_db_file = "%s/virtio-ports/%s" % (DEBUGPATH, name)
     93                 f = open(open_db_file, 'r')
     94                 port = {}
     95                 file = []
     96                 for line in iter(f):
     97                     file.append(line)
     98                 try:
     99                     for line in file:
    100                         m = re.match("(\S+): (\S+)", line)
    101                         port[m.group(1)] = m.group(2)
    102 
    103                     if port['is_console'] == "yes":
    104                         port["path"] = "/dev/hvc%s" % (port["console_vtermno"])
    105                         # Console works like a serialport
    106                     else:
    107                         port["path"] = "/dev/%s" % name
    108 
    109                     if not os.path.exists(port['path']):
    110                         print "FAIL: %s not exist" % port['path']
    111 
    112                     sysfspath = SYSFSPATH + name
    113                     if not os.path.isdir(sysfspath):
    114                         print "FAIL: %s not exist" % (sysfspath)
    115 
    116                     info_name = sysfspath + "/name"
    117                     port_name = self._readfile(info_name).strip()
    118                     if port_name != port["name"]:
    119                         print ("FAIL: Port info does not match "
    120                                "\n%s - %s\n%s - %s" %
    121                                (info_name , port_name,
    122                                 "%s/virtio-ports/%s" % (DEBUGPATH, name),
    123                                 port["name"]))
    124                     dev_ppath = DEVPATH + port_name
    125                     if not os.path.exists(dev_ppath):
    126                         print "FAIL: Symlink %s does not exist." % dev_ppath
    127                     if not os.path.realpath(dev_ppath) != "/dev/name":
    128                         print "FAIL: Symlink %s is not correct." % dev_ppath
    129                 except AttributeError:
    130                     print ("Bad data on file %s:\n%s. " %
    131                            (open_db_file, "".join(file).strip()))
    132                     print "FAIL: Bad data on file %s." % open_db_file
    133                     return
    134 
    135                 ports[port['name']] = port
    136                 f.close()
    137 
    138         return ports
    139 
    140 
    141     def check_zero_sym(self):
    142         """
    143         Check if port /dev/vport0p0 was created.
    144         """
    145         symlink = "/dev/vport0p0"
    146         if os.path.exists(symlink):
    147             print "PASS: Symlink %s exists." % symlink
    148         else:
    149             print "FAIL: Symlink %s does not exist." % symlink
    150 
    151 
    152     def init(self, in_files):
    153         """
    154         Init and check port properties.
    155         """
    156         self.ports = self._get_port_status(in_files)
    157 
    158         if self.ports is None:
    159             return
    160         for item in in_files:
    161             if (item[1] != self.ports[item[0]]["is_console"]):
    162                 print self.ports
    163                 print "FAIL: Host console is not like console on guest side\n"
    164                 return
    165 
    166         print "PASS: Init and check virtioconsole files in system."
    167 
    168 
    169     class Switch(Thread):
    170         """
    171         Thread that sends data between ports.
    172         """
    173         def __init__ (self, in_files, out_files, event,
    174                       cachesize=1024, method=0):
    175             """
    176             @param in_files: Array of input files.
    177             @param out_files: Array of output files.
    178             @param method: Method of read/write access.
    179             @param cachesize: Block to receive and send.
    180             """
    181             Thread.__init__(self, name="Switch")
    182 
    183             self.in_files = in_files
    184             self.out_files = out_files
    185             self.exit_thread = event
    186             self.method = method
    187 
    188             self.cachesize = cachesize
    189 
    190 
    191         def _none_mode(self):
    192             """
    193             Read and write to device in blocking mode
    194             """
    195             data = ""
    196             while not self.exit_thread.isSet():
    197                 data = ""
    198                 for desc in self.in_files:
    199                     data += os.read(desc, self.cachesize)
    200                 if data != "":
    201                     for desc in self.out_files:
    202                         os.write(desc, data)
    203 
    204 
    205         def _poll_mode(self):
    206             """
    207             Read and write to device in polling mode.
    208             """
    209 
    210             pi = select.poll()
    211             po = select.poll()
    212 
    213             for fd in self.in_files:
    214                 pi.register(fd, select.POLLIN)
    215 
    216             for fd in self.out_files:
    217                 po.register(fd, select.POLLOUT)
    218 
    219             while not self.exit_thread.isSet():
    220                 data = ""
    221                 t_out = self.out_files
    222 
    223                 readyf = pi.poll(1.0)
    224                 for i in readyf:
    225                     data += os.read(i[0], self.cachesize)
    226 
    227                 if data != "":
    228                     while ((len(t_out) != len(readyf)) and not
    229                            self.exit_thread.isSet()):
    230                         readyf = po.poll(1.0)
    231                     for desc in t_out:
    232                         os.write(desc, data)
    233 
    234 
    235         def _select_mode(self):
    236             """
    237             Read and write to device in selecting mode.
    238             """
    239             while not self.exit_thread.isSet():
    240                 ret = select.select(self.in_files, [], [], 1.0)
    241                 data = ""
    242                 if ret[0] != []:
    243                     for desc in ret[0]:
    244                         data += os.read(desc, self.cachesize)
    245                 if data != "":
    246                     ret = select.select([], self.out_files, [], 1.0)
    247                     while ((len(self.out_files) != len(ret[1])) and not
    248                            self.exit_thread.isSet()):
    249                         ret = select.select([], self.out_files, [], 1.0)
    250                     for desc in ret[1]:
    251                         os.write(desc, data)
    252 
    253 
    254         def run(self):
    255             if (self.method == VirtioGuest.LOOP_POLL):
    256                 self._poll_mode()
    257             elif (self.method == VirtioGuest.LOOP_SELECT):
    258                 self._select_mode()
    259             else:
    260                 self._none_mode()
    261 
    262 
    263     class Sender(Thread):
    264         """
    265         Creates a thread which sends random blocks of data to dst port.
    266         """
    267         def __init__(self, port, event, length):
    268             """
    269             @param port: Destination port
    270             @param length: Length of the random data block
    271             """
    272             Thread.__init__(self, name="Sender")
    273             self.port = port
    274             self.exit_thread = event
    275             self.data = array.array('L')
    276             for i in range(max(length / self.data.itemsize, 1)):
    277                 self.data.append(random.randrange(sys.maxint))
    278 
    279         def run(self):
    280             while not self.exit_thread.isSet():
    281                 os.write(self.port, self.data)
    282 
    283 
    284     def _open(self, in_files):
    285         """
    286         Open devices and return array of descriptors
    287 
    288         @param in_files: Files array
    289         @return: Array of descriptor
    290         """
    291         f = []
    292 
    293         for item in in_files:
    294             name = self.ports[item]["path"]
    295             if (name in self.files):
    296                 f.append(self.files[name])
    297             else:
    298                 try:
    299                     self.files[name] = os.open(name, os.O_RDWR)
    300                     if (self.ports[item]["is_console"] == "yes"):
    301                         print os.system("stty -F %s raw -echo" % (name))
    302                         print os.system("stty -F %s -a" % (name))
    303                     f.append(self.files[name])
    304                 except Exception, inst:
    305                     print "FAIL: Failed to open file %s" % (name)
    306                     raise inst
    307         return f
    308 
    309     @staticmethod
    310     def pollmask_to_str(mask):
    311         """
    312         Conver pool mast to string
    313 
    314         @param mask: poll return mask
    315         """
    316         str = ""
    317         if (mask & select.POLLIN):
    318             str += "IN "
    319         if (mask & select.POLLPRI):
    320             str += "PRI IN "
    321         if (mask & select.POLLOUT):
    322             str += "OUT "
    323         if (mask & select.POLLERR):
    324             str += "ERR "
    325         if (mask & select.POLLHUP):
    326             str += "HUP "
    327         if (mask & select.POLLMSG):
    328             str += "MSG "
    329         return str
    330 
    331 
    332     def poll(self, port, expected, timeout=500):
    333         """
    334         Pool event from device and print event like text.
    335 
    336         @param file: Device.
    337         """
    338         in_f = self._open([port])
    339 
    340         p = select.poll()
    341         p.register(in_f[0])
    342 
    343         mask = p.poll(timeout)
    344 
    345         maskstr = VirtioGuest.pollmask_to_str(mask[0][1])
    346         if (mask[0][1] & expected) == expected:
    347             print "PASS: Events: " + maskstr
    348         else:
    349             emaskstr = VirtioGuest.pollmask_to_str(expected)
    350             print "FAIL: Events: " + maskstr + "  Expected: " + emaskstr
    351 
    352 
    353     def lseek(self, port, pos, how):
    354         """
    355         Use lseek on the device. The device is unseekable so PASS is returned
    356         when lseek command fails and vice versa.
    357 
    358         @param port: Name of the port
    359         @param pos: Offset
    360         @param how: Relativ offset os.SEEK_{SET,CUR,END}
    361         """
    362         fd = self._open([port])[0]
    363 
    364         try:
    365             os.lseek(fd, pos, how)
    366         except Exception, inst:
    367             if inst.errno == 29:
    368                 print "PASS: the lseek failed as expected"
    369             else:
    370                 print inst
    371                 print "FAIL: unknown error"
    372         else:
    373             print "FAIL: the lseek unexpectedly passed"
    374 
    375 
    376     def blocking(self, port, mode=False):
    377         """
    378         Set port function mode blocking/nonblocking
    379 
    380         @param port: port to set mode
    381         @param mode: False to set nonblock mode, True for block mode
    382         """
    383         fd = self._open([port])[0]
    384 
    385         try:
    386             fl = fcntl.fcntl(fd, fcntl.F_GETFL)
    387             if not mode:
    388                 fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
    389             else:
    390                 fcntl.fcntl(fd, fcntl.F_SETFL, fl & ~os.O_NONBLOCK)
    391 
    392         except Exception, inst:
    393             print "FAIL: Setting (non)blocking mode: " + str(inst)
    394             return
    395 
    396         if mode:
    397             print "PASS: set to blocking mode"
    398         else:
    399             print "PASS: set to nonblocking mode"
    400 
    401 
    402     def __call__(self, sig, frame):
    403         """
    404         Call function. Used for signal handle.
    405         """
    406         if (sig == signal.SIGIO):
    407             self.sigio_handler(sig, frame)
    408 
    409 
    410     def sigio_handler(self, sig, frame):
    411         """
    412         Handler for sigio operation.
    413 
    414         @param sig: signal which call handler.
    415         @param frame: frame of caller
    416         """
    417         if self.poll_fds:
    418             p = select.poll()
    419             map(p.register, self.poll_fds.keys())
    420 
    421             masks = p.poll(1)
    422             print masks
    423             for mask in masks:
    424                 self.poll_fds[mask[0]][1] |= mask[1]
    425 
    426 
    427     def get_sigio_poll_return(self, port):
    428         """
    429         Return PASS, FAIL and poll walue in string format.
    430 
    431         @param port: Port to check poll information.
    432         """
    433         fd = self._open([port])[0]
    434 
    435         maskstr = VirtioGuest.pollmask_to_str(self.poll_fds[fd][1])
    436         if (self.poll_fds[fd][0] ^ self.poll_fds[fd][1]):
    437             emaskstr = VirtioGuest.pollmask_to_str(self.poll_fds[fd][0])
    438             print "FAIL: Events: " + maskstr + "  Expected: " + emaskstr
    439         else:
    440             print "PASS: Events: " + maskstr
    441         self.poll_fds[fd][1] = 0
    442 
    443 
    444     def set_pool_want_return(self, port, poll_value):
    445         """
    446         Set value to static variable.
    447 
    448         @param port: Port which should be set excepted mask
    449         @param poll_value: Value to check sigio signal.
    450         """
    451         fd = self._open([port])[0]
    452         self.poll_fds[fd] = [poll_value, 0]
    453         print "PASS: Events: " + VirtioGuest.pollmask_to_str(poll_value)
    454 
    455 
    456     def catching_signal(self):
    457         """
    458         return: True if should set catch signal, False if ignore signal and
    459                 none when configuration is not changed.
    460         """
    461         ret = self.catch_signal
    462         self.catch_signal = None
    463         return ret
    464 
    465 
    466     def async(self, port, mode=True, exp_val=0):
    467         """
    468         Set port function mode async/sync.
    469 
    470         @param port: port which should be pooled.
    471         @param mode: False to set sync mode, True for sync mode.
    472         @param exp_val: Value which should be pooled.
    473         """
    474         fd = self._open([port])[0]
    475 
    476         try:
    477             fcntl.fcntl(fd, fcntl.F_SETOWN, os.getpid())
    478             fl = fcntl.fcntl(fd, fcntl.F_GETFL)
    479 
    480             self.use_config.clear()
    481             if mode:
    482                 fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_ASYNC)
    483                 self.poll_fds[fd] = [exp_val, 0]
    484                 self.catch_signal = True
    485             else:
    486                 del self.poll_fds[fd]
    487                 fcntl.fcntl(fd, fcntl.F_SETFL, fl & ~os.O_ASYNC)
    488                 self.catch_signal = False
    489 
    490             os.kill(os.getpid(), signal.SIGUSR1)
    491             self.use_config.wait()
    492 
    493         except Exception, inst:
    494             print "FAIL: Setting (a)sync mode: " + str(inst)
    495             return
    496 
    497         if mode:
    498             print "PASS: Set to async mode"
    499         else:
    500             print "PASS: Set to sync mode"
    501 
    502 
    503     def close(self, file):
    504         """
    505         Close open port.
    506 
    507         @param file: File to close.
    508         """
    509         descriptor = None
    510         path = self.ports[file]["path"]
    511         if path is not None:
    512             if path in self.files.keys():
    513                 descriptor = self.files[path]
    514                 del self.files[path]
    515             if descriptor is not None:
    516                 try:
    517                     os.close(descriptor)
    518                 except Exception, inst:
    519                     print "FAIL: Closing the file: " + str(inst)
    520                     return
    521         print "PASS: Close"
    522 
    523 
    524     def open(self, in_file):
    525         """
    526         Direct open devices.
    527 
    528         @param in_file: Array of files.
    529         @return: Array of descriptors.
    530         """
    531         name = self.ports[in_file]["path"]
    532         try:
    533             self.files[name] = os.open(name, os.O_RDWR)
    534             if (self.ports[in_file]["is_console"] == "yes"):
    535                 print os.system("stty -F %s raw -echo" % (name))
    536             print "PASS: Open all filles correctly."
    537         except Exception, inst:
    538             print "%s\nFAIL: Failed open file %s" % (str(inst), name)
    539 
    540 
    541     def loopback(self, in_files, out_files, cachesize=1024, mode=LOOP_NONE):
    542         """
    543         Start a switch thread.
    544 
    545         (There is a problem with multiple opens of a single file).
    546 
    547         @param in_files: Array of input files.
    548         @param out_files: Array of output files.
    549         @param cachesize: Cachesize.
    550         @param mode: Mode of switch.
    551         """
    552         self.ports = self._get_port_status()
    553 
    554         in_f = self._open(in_files)
    555         out_f = self._open(out_files)
    556 
    557         s = self.Switch(in_f, out_f, self.exit_thread, cachesize, mode)
    558         s.start()
    559         self.threads.append(s)
    560         print "PASS: Start switch"
    561 
    562 
    563     def exit_threads(self):
    564         """
    565         Function end all running data switch.
    566         """
    567         self.exit_thread.set()
    568         for th in self.threads:
    569             print "join"
    570             th.join()
    571         self.exit_thread.clear()
    572 
    573         del self.threads[:]
    574         for desc in self.files.itervalues():
    575             os.close(desc)
    576         self.files.clear()
    577         print "PASS: All threads finished"
    578 
    579 
    580     def die(self):
    581         """
    582         Quit consoleswitch.
    583         """
    584         self.exit_threads()
    585         exit()
    586 
    587 
    588     def send_loop_init(self, port, length):
    589         """
    590         Prepares the sender thread. Requires clean thread structure.
    591         """
    592         self.ports = self._get_port_status()
    593         in_f = self._open([port])
    594 
    595         self.threads.append(self.Sender(in_f[0], self.exit_thread, length))
    596         print "PASS: Sender prepare"
    597 
    598 
    599     def send_loop(self):
    600         """
    601         Start sender data transfer. Requires senderprepare run first.
    602         """
    603         self.threads[0].start()
    604         print "PASS: Sender start"
    605 
    606 
    607     def send(self, port, length=1, mode=True, is_static=False):
    608         """
    609         Send a data of some length
    610 
    611         @param port: Port to write data
    612         @param length: Length of data
    613         @param mode: True = loop mode, False = one shoot mode
    614         """
    615         in_f = self._open([port])
    616 
    617         data = ""
    618         writes = 0
    619 
    620         if not is_static:
    621             while len(data) < length:
    622                 data += "%c" % random.randrange(255)
    623             try:
    624                 writes = os.write(in_f[0], data)
    625             except Exception, inst:
    626                 print inst
    627         else:
    628             while len(data) < 4096:
    629                 data += "%c" % random.randrange(255)
    630         if mode:
    631             while (writes < length):
    632                 try:
    633                     writes += os.write(in_f[0], data)
    634                 except Exception, inst:
    635                     print inst
    636         if writes >= length:
    637             print "PASS: Send data length %d" % writes
    638         else:
    639             print ("FAIL: Partial send: desired %d, transfered %d" %
    640                    (length, writes))
    641 
    642 
    643     def recv(self, port, length=1, buffer=1024, mode=True):
    644         """
    645         Recv a data of some length
    646 
    647         @param port: Port to write data
    648         @param length: Length of data
    649         @param mode: True = loop mode, False = one shoot mode
    650         """
    651         in_f = self._open([port])
    652 
    653         recvs = ""
    654         try:
    655             recvs = os.read(in_f[0], buffer)
    656         except Exception, inst:
    657             print inst
    658         if mode:
    659             while (len(recvs) < length):
    660                 try:
    661                     recvs += os.read(in_f[0], buffer)
    662                 except Exception, inst:
    663                     print inst
    664         if len(recvs) >= length:
    665             print "PASS: Recv data length %d" % len(recvs)
    666         else:
    667             print ("FAIL: Partial recv: desired %d, transfered %d" %
    668                    (length, len(recvs)))
    669 
    670 
    671     def clean_port(self, port, buffer=1024):
    672         in_f = self._open([port])
    673         ret = select.select([in_f[0]], [], [], 1.0)
    674         buf = ""
    675         if ret[0]:
    676             buf = os.read(in_f[0], buffer)
    677         print ("PASS: Rest in socket: ") + str(buf[:10])
    678 
    679 
    680 def is_alive():
    681     """
    682     Check is only main thread is alive and if guest react.
    683     """
    684     if threading.activeCount() == 2:
    685         print ("PASS: Guest is ok no thread alive")
    686     else:
    687         threads = ""
    688         for thread in threading.enumerate():
    689             threads += thread.name + ", "
    690         print ("FAIL: On guest run thread. Active thread:" + threads)
    691 
    692 
    693 def compile():
    694     """
    695     Compile virtio_console_guest.py to speed up.
    696     """
    697     import py_compile
    698     py_compile.compile(sys.path[0] + "/virtio_console_guest.py")
    699     print "PASS: compile"
    700     sys.exit()
    701 
    702 
    703 def guest_exit():
    704     global exiting
    705     exiting = True
    706 
    707 
    708 def worker(virt):
    709     """
    710     Worker thread (infinite) loop of virtio_guest.
    711     """
    712     global exiting
    713     print "PASS: Daemon start."
    714     p = select.poll()
    715     p.register(sys.stdin.fileno())
    716     while not exiting:
    717         d = p.poll()
    718         if (d[0][1] == select.POLLIN):
    719             str = raw_input()
    720             try:
    721                 exec str
    722             except:
    723                 exc_type, exc_value, exc_traceback = sys.exc_info()
    724                 print "On Guest exception from: \n" + "".join(
    725                                 traceback.format_exception(exc_type,
    726                                                            exc_value,
    727                                                            exc_traceback))
    728                 print "FAIL: Guest command exception."
    729         elif (d[0][1] & select.POLLHUP):
    730             time.sleep(0.5)
    731 
    732 
    733 def sigusr_handler(sig, frame):
    734     pass
    735 
    736 
    737 class Daemon:
    738     """
    739     Daemonize guest
    740     """
    741     def __init__(self, stdin, stdout, stderr):
    742         """
    743         Init daemon.
    744 
    745         @param stdin: path to stdin file.
    746         @param stdout: path to stdout file.
    747         @param stderr: path to stderr file.
    748         """
    749         self.stdin = stdin
    750         self.stdout = stdout
    751         self.stderr = stderr
    752 
    753 
    754     @staticmethod
    755     def is_file_open(path):
    756         """
    757         Determine process which open file.
    758 
    759         @param path: Path to file.
    760         @return [[pid,mode], ... ].
    761         """
    762         opens = []
    763         pids = os.listdir('/proc')
    764         for pid in sorted(pids):
    765             try:
    766                 int(pid)
    767             except ValueError:
    768                 continue
    769             fd_dir = os.path.join('/proc', pid, 'fd')
    770             try:
    771                 for file in os.listdir(fd_dir):
    772                     try:
    773                         p = os.path.join(fd_dir, file)
    774                         link = os.readlink(os.path.join(fd_dir, file))
    775                         if link == path:
    776                             mode = os.lstat(p).st_mode
    777                             opens.append([pid, mode])
    778                     except OSError:
    779                         continue
    780             except OSError, e:
    781                 if e.errno == 2:
    782                     continue
    783                 raise
    784         return opens
    785 
    786 
    787     def daemonize(self):
    788         """
    789         Run guest as a daemon.
    790         """
    791         try:
    792             pid = os.fork()
    793             if pid > 0:
    794                 return False
    795         except OSError, e:
    796             sys.stderr.write("Daemonize failed: %s\n" % (e))
    797             sys.exit(1)
    798 
    799         os.chdir("/")
    800         os.setsid()
    801         os.umask(0)
    802 
    803         try:
    804             pid = os.fork()
    805             if pid > 0:
    806                 sys.exit(0)
    807         except OSError, e:
    808             sys.stderr.write("Daemonize failed: %s\n" % (e))
    809             sys.exit(1)
    810 
    811         sys.stdout.flush()
    812         sys.stderr.flush()
    813         si = file(self.stdin,'r')
    814         so = file(self.stdout,'w')
    815         se = file(self.stderr,'w')
    816 
    817         os.dup2(si.fileno(), sys.stdin.fileno())
    818         os.dup2(so.fileno(), sys.stdout.fileno())
    819         os.dup2(se.fileno(), sys.stderr.fileno())
    820 
    821         sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
    822         sys.stderr = os.fdopen(sys.stderr.fileno(), 'w', 0)
    823         return True
    824 
    825 
    826     def start(self):
    827         """
    828         Start the daemon
    829 
    830         @return: PID of daemon.
    831         """
    832         # Check for a pidfile to see if the daemon already runs
    833         openers = self.is_file_open(self.stdout)
    834         rundaemon = False
    835         if len(openers) > 0:
    836             for i in openers:
    837                 if i[1] & stat.S_IWUSR:
    838                     rundaemon = True
    839                     openers.remove(i)
    840             if len(openers) > 0:
    841                 for i in openers:
    842                     os.kill(int(i[0]), 9)
    843         time.sleep(0.3)
    844 
    845         # Start the daemon
    846         if not rundaemon:
    847             if self.daemonize():
    848                 self.run()
    849 
    850 
    851     def run(self):
    852         """
    853         Run guest main thread
    854         """
    855         global exiting
    856         virt = VirtioGuest()
    857         slave = Thread(target=worker, args=(virt, ))
    858         slave.start()
    859         signal.signal(signal.SIGUSR1, sigusr_handler)
    860         signal.signal(signal.SIGALRM, sigusr_handler)
    861         while not exiting:
    862             signal.alarm(1)
    863             signal.pause()
    864             catch = virt.catching_signal()
    865             if catch:
    866                 signal.signal(signal.SIGIO, virt)
    867             elif catch is False:
    868                 signal.signal(signal.SIGIO, signal.SIG_DFL)
    869             if catch is not None:
    870                 virt.use_config.set()
    871         print "PASS: guest_exit"
    872         sys.exit(0)
    873 
    874 
    875 def main():
    876     """
    877     Main function with infinite loop to catch signal from system.
    878     """
    879     if (len(sys.argv) > 1) and (sys.argv[1] == "-c"):
    880         compile()
    881     stdin = "/tmp/guest_daemon_pi"
    882     stdout = "/tmp/guest_daemon_po"
    883     stderr = "/tmp/guest_daemon_pe"
    884 
    885     for f in [stdin, stdout, stderr]:
    886         try:
    887             os.mkfifo(f)
    888         except OSError, e:
    889             if e.errno == 17:
    890                 pass
    891 
    892     daemon = Daemon(stdin,
    893                     stdout,
    894                     stderr)
    895     daemon.start()
    896 
    897     d_stdin = os.open(stdin, os.O_WRONLY)
    898     d_stdout = os.open(stdout, os.O_RDONLY)
    899     d_stderr = os.open(stderr, os.O_RDONLY)
    900 
    901     s_stdin = sys.stdin.fileno()
    902     s_stdout = sys.stdout.fileno()
    903     s_stderr = sys.stderr.fileno()
    904 
    905     pid = filter(lambda x: x[0] != str(os.getpid()),
    906                  daemon.is_file_open(stdout))[0][0]
    907 
    908     print "PASS: Start"
    909 
    910     while 1:
    911         ret = select.select([d_stderr,
    912                              d_stdout,
    913                              s_stdin],
    914                             [], [], 1.0)
    915         if s_stdin in ret[0]:
    916             os.write(d_stdin,os.read(s_stdin, 1))
    917         if d_stdout in ret[0]:
    918             os.write(s_stdout,os.read(d_stdout, 1024))
    919         if d_stderr in ret[0]:
    920             os.write(s_stderr,os.read(d_stderr, 1024))
    921         if not os.path.exists("/proc/" + pid):
    922             sys.exit(0)
    923 
    924     os.close(d_stdin)
    925     os.close(d_stdout)
    926     os.close(d_stderr)
    927 
    928 if __name__ == "__main__":
    929     main()
    930