OLD | NEW |
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 # -*- coding: utf-8 -*- | 2 # -*- coding: utf-8 -*- |
3 """ | 3 """ |
4 Auxiliary script used to send data between ports on guests. | 4 Auxiliary script used to send data between ports on guests. |
5 | 5 |
6 @copyright: 2010 Red Hat, Inc. | 6 @copyright: 2010 Red Hat, Inc. |
7 @author: Jiri Zupka (jzupka@redhat.com) | 7 @author: Jiri Zupka (jzupka@redhat.com) |
8 @author: Lukas Doktor (ldoktor@redhat.com) | 8 @author: Lukas Doktor (ldoktor@redhat.com) |
9 """ | 9 """ |
10 import threading | 10 import threading |
11 from threading import Thread | 11 from threading import Thread |
12 import os, select, re, random, sys, array | 12 import os, select, re, random, sys, array, stat |
13 import fcntl, traceback, signal | 13 import fcntl, traceback, signal, time |
14 | 14 |
15 DEBUGPATH = "/sys/kernel/debug" | 15 DEBUGPATH = "/sys/kernel/debug" |
16 SYSFSPATH = "/sys/class/virtio-ports/" | 16 SYSFSPATH = "/sys/class/virtio-ports/" |
17 DEVPATH = "/dev/virtio-ports/" | 17 DEVPATH = "/dev/virtio-ports/" |
18 | 18 |
19 exiting = False | 19 exiting = False |
20 | 20 |
21 class VirtioGuest: | 21 class VirtioGuest: |
22 """ | 22 """ |
23 Test tools of virtio_ports. | 23 Test tools of virtio_ports. |
(...skipping 516 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
540 | 540 |
541 def loopback(self, in_files, out_files, cachesize=1024, mode=LOOP_NONE): | 541 def loopback(self, in_files, out_files, cachesize=1024, mode=LOOP_NONE): |
542 """ | 542 """ |
543 Start a switch thread. | 543 Start a switch thread. |
544 | 544 |
545 (There is a problem with multiple opens of a single file). | 545 (There is a problem with multiple opens of a single file). |
546 | 546 |
547 @param in_files: Array of input files. | 547 @param in_files: Array of input files. |
548 @param out_files: Array of output files. | 548 @param out_files: Array of output files. |
549 @param cachesize: Cachesize. | 549 @param cachesize: Cachesize. |
| 550 @param mode: Mode of switch. |
550 """ | 551 """ |
551 self.ports = self._get_port_status() | 552 self.ports = self._get_port_status() |
552 | 553 |
553 in_f = self._open(in_files) | 554 in_f = self._open(in_files) |
554 out_f = self._open(out_files) | 555 out_f = self._open(out_files) |
555 | 556 |
556 s = self.Switch(in_f, out_f, self.exit_thread, cachesize, mode) | 557 s = self.Switch(in_f, out_f, self.exit_thread, cachesize, mode) |
557 s.start() | 558 s.start() |
558 self.threads.append(s) | 559 self.threads.append(s) |
559 print "PASS: Start switch" | 560 print "PASS: Start switch" |
560 | 561 |
561 | 562 |
562 def exit_threads(self): | 563 def exit_threads(self): |
563 """ | 564 """ |
564 Function end all running data switch. | 565 Function end all running data switch. |
565 """ | 566 """ |
566 self.exit_thread.set() | 567 self.exit_thread.set() |
567 for th in self.threads: | 568 for th in self.threads: |
568 print "join" | 569 print "join" |
569 th.join() | 570 th.join() |
570 self.exit_thread.clear() | 571 self.exit_thread.clear() |
571 | 572 |
572 del self.threads[:] | 573 del self.threads[:] |
573 for desc in self.files.itervalues(): | 574 for desc in self.files.itervalues(): |
574 os.close(desc) | 575 os.close(desc) |
575 self.files.clear() | 576 self.files.clear() |
576 print "PASS: All threads finished." | 577 print "PASS: All threads finished" |
577 | 578 |
578 | 579 |
579 def die(self): | 580 def die(self): |
580 """ | 581 """ |
581 Quit consoleswitch. | 582 Quit consoleswitch. |
582 """ | 583 """ |
583 self.exit_threads() | 584 self.exit_threads() |
584 exit() | 585 exit() |
585 | 586 |
586 | 587 |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
695 """ | 696 """ |
696 import py_compile | 697 import py_compile |
697 py_compile.compile(sys.path[0] + "/virtio_console_guest.py") | 698 py_compile.compile(sys.path[0] + "/virtio_console_guest.py") |
698 print "PASS: compile" | 699 print "PASS: compile" |
699 sys.exit() | 700 sys.exit() |
700 | 701 |
701 | 702 |
702 def guest_exit(): | 703 def guest_exit(): |
703 global exiting | 704 global exiting |
704 exiting = True | 705 exiting = True |
705 os.kill(os.getpid(), signal.SIGUSR1) | |
706 | 706 |
707 | 707 |
708 def worker(virt): | 708 def worker(virt): |
709 """ | 709 """ |
710 Worker thread (infinite) loop of virtio_guest. | 710 Worker thread (infinite) loop of virtio_guest. |
711 """ | 711 """ |
712 global exiting | 712 global exiting |
713 print "PASS: Start" | 713 print "PASS: Daemon start." |
714 | 714 p = select.poll() |
| 715 p.register(sys.stdin.fileno()) |
715 while not exiting: | 716 while not exiting: |
716 str = raw_input() | 717 d = p.poll() |
717 try: | 718 if (d[0][1] == select.POLLIN): |
718 exec str | 719 str = raw_input() |
719 except: | 720 try: |
720 exc_type, exc_value, exc_traceback = sys.exc_info() | 721 exec str |
721 print "On Guest exception from: \n" + "".join( | 722 except: |
722 traceback.format_exception(exc_type, | 723 exc_type, exc_value, exc_traceback = sys.exc_info() |
723 exc_value, | 724 print "On Guest exception from: \n" + "".join( |
724 exc_traceback)) | 725 traceback.format_exception(exc_type, |
725 print "FAIL: Guest command exception." | 726 exc_value, |
| 727 exc_traceback)) |
| 728 print "FAIL: Guest command exception." |
| 729 elif (d[0][1] & select.POLLHUP): |
| 730 time.sleep(0.5) |
726 | 731 |
727 | 732 |
728 def sigusr_handler(sig, frame): | 733 def sigusr_handler(sig, frame): |
729 pass | 734 pass |
730 | 735 |
731 | 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 |
732 def main(): | 875 def main(): |
733 """ | 876 """ |
734 Main function with infinite loop to catch signal from system. | 877 Main function with infinite loop to catch signal from system. |
735 """ | 878 """ |
736 if (len(sys.argv) > 1) and (sys.argv[1] == "-c"): | 879 if (len(sys.argv) > 1) and (sys.argv[1] == "-c"): |
737 compile() | 880 compile() |
738 | 881 stdin = "/tmp/guest_daemon_pi" |
739 global exiting | 882 stdout = "/tmp/guest_daemon_po" |
740 virt = VirtioGuest() | 883 stderr = "/tmp/guest_daemon_pe" |
741 slave = Thread(target=worker, args=(virt, )) | 884 |
742 slave.start() | 885 for f in [stdin, stdout, stderr]: |
743 signal.signal(signal.SIGUSR1, sigusr_handler) | 886 try: |
744 while not exiting: | 887 os.mkfifo(f) |
745 signal.pause() | 888 except OSError, e: |
746 catch = virt.catching_signal() | 889 if e.errno == 17: |
747 if catch: | 890 pass |
748 signal.signal(signal.SIGIO, virt) | 891 |
749 elif catch is False: | 892 daemon = Daemon(stdin, |
750 signal.signal(signal.SIGIO, signal.SIG_DFL) | 893 stdout, |
751 if catch is not None: | 894 stderr) |
752 virt.use_config.set() | 895 daemon.start() |
753 print "PASS: guest_exit" | 896 |
754 | 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) |
755 | 927 |
756 if __name__ == "__main__": | 928 if __name__ == "__main__": |
757 main() | 929 main() |
OLD | NEW |