Index: Makefile ================================================================== --- Makefile +++ Makefile @@ -11,13 +11,13 @@ clean: rm *.1 install: vws vws.1 find_free_port.1 vws.conf - $(INSTALL) -d -m 755 -o root $(DESTDIR)$(bindir) - $(INSTALL) -d -m 755 -o root $(DESTDIR)$(mandir) - $(INSTALL) -d -m 755 -o root $(DESTDIR)$(mandir)/man1 + [ -d $(DESTDIR)$(bindir) ] || $(INSTALL) -d -m 755 -o root $(DESTDIR)$(bindir) + [ -d $(DESTDIR)$(mandir) ] || $(INSTALL) -d -m 755 -o root $(DESTDIR)$(mandir) + [ -d $(DESTDIR)$(mandir)/man1 ]||$(INSTALL) -d -m 755 -o root $(DESTDIR)$(mandir)/man1 $(INSTALL) -c -m 755 -o root find_free_port $(DESTDIR)$(bindir) $(INSTALL) -c -m 755 -o root vws $(DESTDIR)$(bindir) [ -f $(DESTDIR)$(sysconfdir)/vws.conf ]|| $(INSTALL) -c -m 644 -o root vws.conf $(DESTDIR)$(sysconfdir) $(INSTALL) -c -m 644 -o root vws.1 $(DESTDIR)$(mandir)/man1 $(INSTALL) -c -m 644 -o root find_free_port.1 $(DESTDIR)$(mandir)/man1 Index: vws ================================================================== --- vws +++ vws @@ -87,10 +87,27 @@ name = line[:idx] if name == "bridge name": continue lst.append(name) return lst + +def parse_arp(iface): + """ + Returns map which maps mac addresses to IPs for specified interface" + """ + addr_map = {} + pipe = os.popen(config.get("tools","arp")+" -n -i "+iface, "r") + for line in pipe: + data = line.split() + mac=data[2] + if mac == "HWAddress": + continue + if mac == iface: + # Foind line with (incomplete) entry + continue + addr_map[data[2]]=data[0] + return addr_map def validate_size(size): """ Checks if size argument has proper format """ return re.match('\\d+[KMG]', size) is not None @@ -109,11 +126,39 @@ def snapshot_mode(sock): """ Returns True if VM is running in snapshot mode """ answer = send_command(sock, "info block") return re.search(": /tmp", answer) is not None - +def read_netinfo(filename): + """ Reads network information from start script """ + with open(filename,"r") as f: + for line in f: + match=re.search("-net nic,macaddr=(\\S+) -net ([^,]+)",line) + if match: + f={"mac":match.group(1)} + if match.group(2) == "user": + f["iface"]="user" + elif match.group(2) == "bridge": + f["iface"]=re.search("br=(\\S+)",line).group(1) + else: + f["iface"]="unknown"; + return f + return {"iface":"unknown","mac":"?","ip":"?"} +def get_netinfo(sock): + """ Gets network information from the running VM """ + answer = send_command(sock, "info network") + match=re.search("bridge\\.0:.*,br=(\\S+).*macaddr=(\\S+)", answer, re.S) + if match: + return {"iface":match.group(1), "mac":match.group(2)} + else: + match = re.search("user.0:.*net=([^,]+).*\n.*macaddr=(\\S+)",answer) + if match: + return {"iface":"user", "ip":match.group(1), + "mac":match.group(2)} + else: + print >>sys.stderr,answer + return {"iface":"unknown","ip":"?","mac":"?","card":"?"} # # command implementation # def cmd_spiceuri(options): @@ -307,38 +352,50 @@ ("shared",config.get("directories", "SharedVMs")), ("autostart",config.get("directories", "AutostartVMs"))] maxlen = 0 vms = [] + bridges = set() for (vmtype,dirname) in search_path: if not os.access(dirname + "/.", os.X_OK): continue for vmname in os.listdir(dirname): if os.access(dirname + "/" + vmname + "/start", os.X_OK): count += 1 - f = [vmname] + f = {"name":vmname} if maxlen < len(vmname): maxlen = len(vmname) if options.state: - f.append(vmtype) + f["type"]=vmtype sock = connect_vm(dirname + "/" + vmname) if sock is None: - state = "stopped" - uri="-" + f.update({"state":"stopped","uri":"-","ip":"-"}) + f.update(read_netinfo(dirname + "/" + vmname + "/start")) else: uri=spiceurl(sock) + f["uri"]=uri[uri.rindex(":")+1:] + f.update(get_netinfo(sock)) + if "ip" not in f: + bridges.add(f["iface"]) sock.shutdown(socket.SHUT_RDWR) sock.close() - state = "running" - f.append(state) - f.append(uri) + f["state"] = "running" vms.append(f) - for f in sorted(vms): - if len(f) == 4: - print "%*s %s %-9s %s" % (-maxlen, f[0], f[2], f[1], f[3]) + arp_data={} + for bridge in bridges: + arp_data.update(parse_arp(bridge)) + for f in sorted(vms,key=lambda x: x["name"]): + if "state" in f: + if "mac" in f and not "ip" in f: + if f["mac"] in arp_data: + f["ip"] = arp_data[f["mac"]] + else: + f["ip"] = "-" + f["name"] = f["name"].ljust(maxlen) + print "%(name)s %(state)s %(type)-9s %(uri)-4s %(iface)-5s %(mac)s %(ip)s " % f else: - print f[0] + print f["name"] if not count: sys.exit(1) def cmd_screenshot(options): """ vws screenshot """ @@ -700,10 +757,11 @@ config.set('create options', option, value) config.add_section('tools') config.set('tools', 'viewer', 'remote-viewer %s') config.set('tools', 'bridge_list', '/sbin/brctl show') config.set('tools', 'lsusb', 'lsusb') +config.set('tools', 'arp', '/usr/sbin/arp') config.add_section('permissions') config.set('permissions','vm_group','kvm') config.set('permissions','autostart_user','root') config.set('permissions','setgid_vm','yes') # Read configration files Index: vws.mkd ================================================================== --- vws.mkd +++ vws.mkd @@ -264,13 +264,15 @@ Stop recording sound. **vws monitor** *machine* Attaches to the machine monitor and allows user to send monitor commands -from the keyboard and see output. Uses lockin common to all **vws** +from the keyboard and see output. Uses locking common to all **vws** command, so you can use other **vws** command in parallel with -**monitor** command running. +**monitor** command running. Use **Ctrl-D** to exit monitor mode, because if +you send **quit** command it would quit virtual machine, not the +interaction with it. **vws spiceuri** *machine* Prints out URI you should feed into your spice viewer to access this machine.