1#!/usr/bin/python 2# -*- coding: utf-8 -*- 3""" 4Auxiliary script used to send data between ports on guests. 5 6@copyright: 2010 Red Hat, Inc. 7@author: Jiri Zupka (jzupka@redhat.com) 8@author: Lukas Doktor (ldoktor@redhat.com) 9""" 10import threading 11from threading import Thread 12import os, select, re, random, sys, array, stat 13import fcntl, traceback, signal, time 14 15DEBUGPATH = "/sys/kernel/debug" 16SYSFSPATH = "/sys/class/virtio-ports/" 17DEVPATH = "/dev/virtio-ports/" 18 19exiting = False 20 21class 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 680def 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 693def 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 703def guest_exit(): 704 global exiting 705 exiting = True 706 707 708def 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 733def sigusr_handler(sig, frame): 734 pass 735 736 737class 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 875def 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 928if __name__ == "__main__": 929 main() 930