VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxShell/vboxshell.py@ 20819

Last change on this file since 20819 was 20818, checked in by vboxsync, 16 years ago

Python: generate capitalized version of callbacks on Windows, now Win32 callbacks work just fine

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.7 KB
Line 
1#!/usr/bin/python
2#
3# Copyright (C) 2009 Sun Microsystems, Inc.
4#
5# This file is part of VirtualBox Open Source Edition (OSE), as
6# available from http://www.virtualbox.org. This file is free software;
7# you can redistribute it and/or modify it under the terms of the GNU
8# General Public License (GPL) as published by the Free Software
9# Foundation, in version 2 as it comes in the "COPYING" file of the
10# VirtualBox OSE distribution. VirtualBox OSE is distributed in the
11# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
12#
13# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
14# Clara, CA 95054 USA or visit http://www.sun.com if you need
15# additional information or have any questions.
16#
17#
18#################################################################################
19# This program is a simple interactive shell for VirtualBox. You can query #
20# information and issue commands from a simple command line. #
21# #
22# It also provides you with examples on how to use VirtualBox's Python API. #
23# This shell is even somewhat documented and supports TAB-completion and #
24# history if you have Python readline installed. #
25# #
26# Enjoy. #
27################################################################################
28
29import os,sys
30import traceback
31
32class PerfCollector:
33 """ This class provides a wrapper over IPerformanceCollector in order to
34 get more 'pythonic' interface.
35
36 To begin collection of metrics use setup() method.
37
38 To get collected data use query() method.
39
40 It is possible to disable metric collection without changing collection
41 parameters with disable() method. The enable() method resumes metric
42 collection.
43 """
44
45 def __init__(self, vb):
46 """ Initializes the instance.
47
48 Pass an instance of IVirtualBox as parameter.
49 """
50 self.collector = vb.performanceCollector
51
52 def setup(self, names, objects, period, nsamples):
53 """ Discards all previously collected values for the specified
54 metrics, sets the period of collection and the number of retained
55 samples, enables collection.
56 """
57 self.collector.setupMetrics(names, objects, period, nsamples)
58
59 def enable(self, names, objects):
60 """ Resumes metric collection for the specified metrics.
61 """
62 self.collector.enableMetrics(names, objects)
63
64 def disable(self, names, objects):
65 """ Suspends metric collection for the specified metrics.
66 """
67 self.collector.disableMetrics(names, objects)
68
69 def query(self, names, objects):
70 """ Retrieves collected metric values as well as some auxiliary
71 information. Returns an array of dictionaries, one dictionary per
72 metric. Each dictionary contains the following entries:
73 'name': metric name
74 'object': managed object this metric associated with
75 'unit': unit of measurement
76 'scale': divide 'values' by this number to get float numbers
77 'values': collected data
78 'values_as_string': pre-processed values ready for 'print' statement
79 """
80 (values, names_out, objects_out, units, scales, sequence_numbers,
81 indices, lengths) = self.collector.queryMetricsData(names, objects)
82 out = []
83 for i in xrange(0, len(names_out)):
84 scale = int(scales[i])
85 if scale != 1:
86 fmt = '%.2f%s'
87 else:
88 fmt = '%d %s'
89 out.append({
90 'name':str(names_out[i]),
91 'object':str(objects_out[i]),
92 'unit':str(units[i]),
93 'scale':scale,
94 'values':[int(values[j]) for j in xrange(int(indices[i]), int(indices[i])+int(lengths[i]))],
95 'values_as_string':'['+', '.join([fmt % (int(values[j])/scale, units[i]) for j in xrange(int(indices[i]), int(indices[i])+int(lengths[i]))])+']'
96 })
97 return out
98
99# Simple implementation of IConsoleCallback, one can use it as skeleton
100# for custom implementations
101class GuestMonitor:
102 def __init__(self, mach):
103 self.mach = mach
104
105 def onMousePointerShapeChange(self, visible, alpha, xHot, yHot, width, height, shape):
106 print "%s: onMousePointerShapeChange: visible=%d" %(self.mach.name, visible)
107 def onMouseCapabilityChange(self, supportsAbsolute, needsHostCursor):
108 print "%s: onMouseCapabilityChange: needsHostCursor=%d" %(self.mach.name, needsHostCursor)
109
110 def onKeyboardLedsChange(self, numLock, capsLock, scrollLock):
111 print "%s: onKeyboardLedsChange capsLock=%d" %(self.mach.name, capsLock)
112
113 def onStateChange(self, state):
114 print "%s: onStateChange state=%d" %(self.mach.name, state)
115
116 def onAdditionsStateChange(self):
117 print "%s: onAdditionsStateChange" %(self.mach.name)
118
119 def onDVDDriveChange(self):
120 print "%s: onDVDDriveChange" %(self.mach.name)
121
122 def onFloppyDriveChange(self):
123 print "%s: onFloppyDriveChange" %(self.mach.name)
124
125 def onNetworkAdapterChange(self, adapter):
126 print "%s: onNetworkAdapterChange" %(self.mach.name)
127
128 def onSerialPortChange(self, port):
129 print "%s: onSerialPortChange" %(self.mach.name)
130
131 def onParallelPortChange(self, port):
132 print "%s: onParallelPortChange" %(self.mach.name)
133
134 def onStorageControllerChange(self):
135 print "%s: onStorageControllerChange" %(self.mach.name)
136
137 def onVRDPServerChange(self):
138 print "%s: onVRDPServerChange" %(self.mach.name)
139
140 def onUSBControllerChange(self):
141 print "%s: onUSBControllerChange" %(self.mach.name)
142
143 def onUSBDeviceStateChange(self, device, attached, error):
144 print "%s: onUSBDeviceStateChange" %(self.mach.name)
145
146 def onSharedFolderChange(self, scope):
147 print "%s: onSharedFolderChange" %(self.mach.name)
148
149 def onRuntimeError(self, fatal, id, message):
150 print "%s: onRuntimeError fatal=%d message=%s" %(self.mach.name, fatal, message)
151
152 def onCanShowWindow(self):
153 print "%s: onCanShowWindow" %(self.mach.name)
154 return True
155
156 def onShowWindow(self, winId):
157 print "%s: onShowWindow: %d" %(self.mach.name, winId)
158
159class VBoxMonitor:
160 def __init__(self, vbox):
161 self.vbox = vbox
162 pass
163
164 def onMachineStateChange(self, id, state):
165 print "onMachineStateChange: %s %d" %(id, state)
166
167 def onMachineDataChange(self,id):
168 print "onMachineDataChange: %s" %(id)
169
170 def onExtraDataCanChange(self, id, key, value):
171 print "onExtraDataCanChange: %s %s=>%s" %(id, key, value)
172 return True
173
174 def onExtraDataChange(self, id, key, value):
175 print "onExtraDataChange: %s %s=>%s" %(id, key, value)
176
177 def onMediaRegistred(self, id, type, registred):
178 print "onMediaRegistred: %s" %(id)
179
180 def onMachineRegistred(self, id, registred):
181 print "onMachineRegistred: %s" %(id)
182
183 def onSessionStateChange(self, id, state):
184 print "onSessionStateChange: %s %d" %(id, state)
185
186 def onSnapshotTaken(self, mach, id):
187 print "onSnapshotTaken: %s %s" %(mach, id)
188
189 def onSnapshotDiscarded(self, mach, id):
190 print "onSnapshotDiscarded: %s %s" %(mach, id)
191
192 def onSnapshotChange(self, mach, id):
193 print "onSnapshotChange: %s %s" %(mach, id)
194
195 def onGuestPropertyChange(self, id, val1, val2, val3):
196 print "onGuestPropertyChange: %s" %(id)
197
198
199g_hasreadline = 1
200try:
201 import readline
202 import rlcompleter
203except:
204 g_hasreadline = 0
205
206
207if g_hasreadline:
208 class CompleterNG(rlcompleter.Completer):
209 def __init__(self, dic, ctx):
210 self.ctx = ctx
211 return rlcompleter.Completer.__init__(self,dic)
212
213 def complete(self, text, state):
214 """
215 taken from:
216 http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/496812
217 """
218 if text == "":
219 return ['\t',None][state]
220 else:
221 return rlcompleter.Completer.complete(self,text,state)
222
223 def global_matches(self, text):
224 """
225 Compute matches when text is a simple name.
226 Return a list of all names currently defined
227 in self.namespace that match.
228 """
229
230 matches = []
231 n = len(text)
232
233 for list in [ self.namespace ]:
234 for word in list:
235 if word[:n] == text:
236 matches.append(word)
237
238
239 try:
240 for m in getMachines(self.ctx):
241 # although it has autoconversion, we need to cast
242 # explicitly for subscripts to work
243 word = str(m.name)
244 if word[:n] == text:
245 matches.append(word)
246 word = str(m.id)
247 if word[0] == '{':
248 word = word[1:-1]
249 if word[:n] == text:
250 matches.append(word)
251 except Exception,e:
252 traceback.print_exc()
253 print e
254
255 return matches
256
257
258def autoCompletion(commands, ctx):
259 if not g_hasreadline:
260 return
261
262 comps = {}
263 for (k,v) in commands.items():
264 comps[k] = None
265 completer = CompleterNG(comps, ctx)
266 readline.set_completer(completer.complete)
267 readline.parse_and_bind("tab: complete")
268
269g_verbose = True
270
271def split_no_quotes(s):
272 return s.split()
273
274def createVm(ctx,name,kind,base):
275 mgr = ctx['mgr']
276 vb = ctx['vb']
277 mach = vb.createMachine(name, kind, base,
278 "00000000-0000-0000-0000-000000000000")
279 mach.saveSettings()
280 print "created machine with UUID",mach.id
281 vb.registerMachine(mach)
282
283def removeVm(ctx,mach):
284 mgr = ctx['mgr']
285 vb = ctx['vb']
286 id = mach.id
287 print "removing machine ",mach.name,"with UUID",id
288 session = ctx['global'].openMachineSession(id)
289 mach=session.machine
290 for d in mach.getHardDiskAttachments():
291 mach.detachHardDisk(d.controller, d.port, d.device)
292 ctx['global'].closeMachineSession(session)
293 mach = vb.unregisterMachine(id)
294 if mach:
295 mach.deleteSettings()
296
297def startVm(ctx,mach,type):
298 mgr = ctx['mgr']
299 vb = ctx['vb']
300 perf = ctx['perf']
301 session = mgr.getSessionObject(vb)
302 uuid = mach.id
303 progress = vb.openRemoteSession(session, uuid, type, "")
304 progress.waitForCompletion(-1)
305 completed = progress.completed
306 rc = int(progress.resultCode)
307 print "Completed:", completed, "rc:",hex(rc&0xffffffff)
308 if rc == 0:
309 # we ignore exceptions to allow starting VM even if
310 # perf collector cannot be started
311 if perf:
312 try:
313 perf.setup(['*'], [mach], 10, 15)
314 except Exception,e:
315 print e
316 if g_verbose:
317 traceback.print_exc()
318 pass
319 # if session not opened, close doesn't make sense
320 session.close()
321 else:
322 # Not yet implemented error string query API for remote API
323 if not ctx['remote']:
324 print session.QueryErrorObject(rc)
325
326def getMachines(ctx):
327 return ctx['global'].getArray(ctx['vb'], 'machines')
328
329def asState(var):
330 if var:
331 return 'on'
332 else:
333 return 'off'
334
335def guestStats(ctx,mach):
336 if not ctx['perf']:
337 return
338 for metric in ctx['perf'].query(["*"], [mach]):
339 print metric['name'], metric['values_as_string']
340
341def guestExec(ctx, machine, console, cmds):
342 exec cmds
343
344def monitorGuest(ctx, machine, console, dur):
345 import time
346 cb = ctx['global'].createCallback('IConsoleCallback', GuestMonitor, machine)
347 console.registerCallback(cb)
348 if dur == -1:
349 # not infinity, but close enough
350 dur = 100000
351 try:
352 end = time.time() + dur
353 while time.time() < end:
354 ctx['global'].waitForEvents(500)
355 # We need to catch all exceptions here, otherwise callback will never be unregistered
356 except:
357 pass
358 console.unregisterCallback(cb)
359
360
361def monitorVbox(ctx, dur):
362 import time
363 vbox = ctx['vb']
364 cb = ctx['global'].createCallback('IVirtualBoxCallback', VBoxMonitor, vbox)
365 vbox.registerCallback(cb)
366 if dur == -1:
367 # not infinity, but close enough
368 dur = 100000
369 try:
370 end = time.time() + dur
371 while time.time() < end:
372 ctx['global'].waitForEvents(500)
373 # We need to catch all exceptions here, otherwise callback will never be unregistered
374 except:
375 if g_verbose:
376 traceback.print_exc()
377 vbox.unregisterCallback(cb)
378
379def cmdExistingVm(ctx,mach,cmd,args):
380 mgr=ctx['mgr']
381 vb=ctx['vb']
382 session = mgr.getSessionObject(vb)
383 uuid = mach.id
384 try:
385 progress = vb.openExistingSession(session, uuid)
386 except Exception,e:
387 print "Session to '%s' not open: %s" %(mach.name,e)
388 if g_verbose:
389 traceback.print_exc()
390 return
391 if session.state != ctx['ifaces'].SessionState_Open:
392 print "Session to '%s' in wrong state: %s" %(mach.name, session.state)
393 return
394 # unfortunately IGuest is suppressed, thus WebServices knows not about it
395 # this is an example how to handle local only functionality
396 if ctx['remote'] and cmd == 'stats2':
397 print 'Trying to use local only functionality, ignored'
398 return
399 console=session.console
400 ops={'pause' : lambda: console.pause(),
401 'resume': lambda: console.resume(),
402 'powerdown': lambda: console.powerDown(),
403 'stats': lambda: guestStats(ctx, mach),
404 'guest': lambda: guestExec(ctx, mach, console, args),
405 'monitorGuest': lambda: monitorGuest(ctx, mach, console, args)
406 }
407 try:
408 ops[cmd]()
409 except Exception, e:
410 print 'failed: ',e
411 if g_verbose:
412 traceback.print_exc()
413
414 session.close()
415
416# can cache known machines, if needed
417def machById(ctx,id):
418 mach = None
419 for m in getMachines(ctx):
420 if m.name == id:
421 mach = m
422 break
423 mid = str(m.id)
424 if mid[0] == '{':
425 mid = mid[1:-1]
426 if mid == id:
427 mach = m
428 break
429 return mach
430
431def argsToMach(ctx,args):
432 if len(args) < 2:
433 print "usage: %s [vmname|uuid]" %(args[0])
434 return None
435 id = args[1]
436 m = machById(ctx, id)
437 if m == None:
438 print "Machine '%s' is unknown, use list command to find available machines" %(id)
439 return m
440
441def helpCmd(ctx, args):
442 if len(args) == 1:
443 print "Help page:"
444 for i in commands:
445 print " ",i,":", commands[i][0]
446 else:
447 c = commands.get(args[1], None)
448 if c == None:
449 print "Command '%s' not known" %(args[1])
450 else:
451 print " ",args[1],":", c[0]
452 return 0
453
454def listCmd(ctx, args):
455 for m in getMachines(ctx):
456 print "Machine '%s' [%s], state=%s" %(m.name,m.id,m.sessionState)
457 return 0
458
459def infoCmd(ctx,args):
460 if (len(args) < 2):
461 print "usage: info [vmname|uuid]"
462 return 0
463 mach = argsToMach(ctx,args)
464 if mach == None:
465 return 0
466 os = ctx['vb'].getGuestOSType(mach.OSTypeId)
467 print " Name: ",mach.name
468 print " ID: ",mach.id
469 print " OS Type: ",os.description
470 print " RAM: %dM" %(mach.memorySize)
471 print " VRAM: %dM" %(mach.VRAMSize)
472 print " Clipboard mode: %d" %(mach.clipboardMode)
473 print " Machine status: " ,mach.sessionState
474 bios = mach.BIOSSettings
475 print " BIOS ACPI: ",bios.ACPIEnabled
476 print " PAE: ",mach.PAEEnabled
477 print " Hardware virtualization: ",asState(mach.HWVirtExEnabled)
478 print " Nested paging: ",asState(mach.HWVirtExNestedPagingEnabled)
479 print " Last changed: ",mach.lastStateChange
480
481 return 0
482
483def startCmd(ctx, args):
484 mach = argsToMach(ctx,args)
485 if mach == None:
486 return 0
487 if len(args) > 2:
488 type = args[2]
489 else:
490 type = "gui"
491 startVm(ctx, mach, type)
492 return 0
493
494def createCmd(ctx, args):
495 if (len(args) < 3 or len(args) > 4):
496 print "usage: create name ostype <basefolder>"
497 return 0
498 name = args[1]
499 oskind = args[2]
500 if len(args) == 4:
501 base = args[3]
502 else:
503 base = ''
504 try:
505 ctx['vb'].getGuestOSType(oskind)
506 except Exception, e:
507 print 'Unknown OS type:',oskind
508 return 0
509 createVm(ctx, name, oskind, base)
510 return 0
511
512def removeCmd(ctx, args):
513 mach = argsToMach(ctx,args)
514 if mach == None:
515 return 0
516 removeVm(ctx, mach)
517 return 0
518
519def pauseCmd(ctx, args):
520 mach = argsToMach(ctx,args)
521 if mach == None:
522 return 0
523 cmdExistingVm(ctx, mach, 'pause', '')
524 return 0
525
526def powerdownCmd(ctx, args):
527 mach = argsToMach(ctx,args)
528 if mach == None:
529 return 0
530 cmdExistingVm(ctx, mach, 'powerdown', '')
531 return 0
532
533def resumeCmd(ctx, args):
534 mach = argsToMach(ctx,args)
535 if mach == None:
536 return 0
537 cmdExistingVm(ctx, mach, 'resume', '')
538 return 0
539
540def statsCmd(ctx, args):
541 mach = argsToMach(ctx,args)
542 if mach == None:
543 return 0
544 cmdExistingVm(ctx, mach, 'stats', '')
545 return 0
546
547def guestCmd(ctx, args):
548 if (len(args) < 3):
549 print "usage: guest name commands"
550 return 0
551 mach = argsToMach(ctx,args)
552 if mach == None:
553 return 0
554 cmdExistingVm(ctx, mach, 'guest', ' '.join(args[2:]))
555 return 0
556
557def setvarCmd(ctx, args):
558 if (len(args) < 4):
559 print "usage: setvar [vmname|uuid] expr value"
560 return 0
561 mach = argsToMach(ctx,args)
562 if mach == None:
563 return 0
564 session = ctx['mgr'].getSessionObject(vbox)
565 vbox.openSession(session, mach.id)
566 mach = session.machine
567 expr = 'mach.'+args[2]+' = '+args[3]
568 print "Executing",expr
569 try:
570 exec expr
571 except Exception, e:
572 print 'failed: ',e
573 if g_verbose:
574 traceback.print_exc()
575 mach.saveSettings()
576 session.close()
577 return 0
578
579def quitCmd(ctx, args):
580 return 1
581
582def aliasesCmd(ctx, args):
583 for (k,v) in aliases.items():
584 print "'%s' is an alias for '%s'" %(k,v)
585 return 0
586
587def verboseCmd(ctx, args):
588 global g_verbose
589 g_verbose = not g_verbose
590 return 0
591
592def hostCmd(ctx, args):
593 host = ctx['vb'].host
594 cnt = host.processorCount
595 print "Processor count:",cnt
596 for i in range(0,cnt):
597 print "Processor #%d speed: %dMHz" %(i,host.getProcessorSpeed(i))
598
599 if ctx['perf']:
600 for metric in ctx['perf'].query(["*"], [host]):
601 print metric['name'], metric['values_as_string']
602
603 return 0
604
605
606def monitorGuestCmd(ctx, args):
607 if (len(args) < 2):
608 print "usage: monitorGuest name (duration)"
609 return 0
610 mach = argsToMach(ctx,args)
611 if mach == None:
612 return 0
613 dur = 5
614 if len(args) > 2:
615 dur = float(args[2])
616 cmdExistingVm(ctx, mach, 'monitorGuest', dur)
617 return 0
618
619def monitorVboxCmd(ctx, args):
620 if (len(args) > 2):
621 print "usage: monitorVbox (duration)"
622 return 0
623 dur = 5
624 if len(args) > 1:
625 dur = float(args[1])
626 monitorVbox(ctx, dur)
627 return 0
628
629def evalCmd(ctx, args):
630 expr = ' '.join(args[1:])
631 try:
632 exec expr
633 except Exception, e:
634 print 'failed: ',e
635 if g_verbose:
636 traceback.print_exc()
637 return 0
638
639aliases = {'s':'start',
640 'i':'info',
641 'l':'list',
642 'h':'help',
643 'a':'aliases',
644 'q':'quit', 'exit':'quit',
645 'v':'verbose'}
646
647commands = {'help':['Prints help information', helpCmd],
648 'start':['Start virtual machine by name or uuid', startCmd],
649 'create':['Create virtual machine', createCmd],
650 'remove':['Remove virtual machine', removeCmd],
651 'pause':['Pause virtual machine', pauseCmd],
652 'resume':['Resume virtual machine', resumeCmd],
653 'stats':['Stats for virtual machine', statsCmd],
654 'powerdown':['Power down virtual machine', powerdownCmd],
655 'list':['Shows known virtual machines', listCmd],
656 'info':['Shows info on machine', infoCmd],
657 'aliases':['Shows aliases', aliasesCmd],
658 'verbose':['Toggle verbosity', verboseCmd],
659 'setvar':['Set VMs variable: setvar Fedora BIOSSettings.ACPIEnabled True', setvarCmd],
660 'eval':['Evaluate arbitrary Python construction: eval for m in getMachines(ctx): print m.name,"has",m.memorySize,"M"', evalCmd],
661 'quit':['Exits', quitCmd],
662 'host':['Show host information', hostCmd],
663 'guest':['Execute command for guest: guest Win32 console.mouse.putMouseEvent(20, 20, 0, 0)', guestCmd],
664 'monitorGuest':['Monitor what happens with the guest for some time: monitorGuest Win32 10', monitorGuestCmd],
665 'monitorVbox':['Monitor what happens with Virtual Box for some time: monitorVbox 10', monitorVboxCmd],
666 }
667
668def runCommand(ctx, cmd):
669 if len(cmd) == 0: return 0
670 args = split_no_quotes(cmd)
671 if len(args) == 0: return 0
672 c = args[0]
673 if aliases.get(c, None) != None:
674 c = aliases[c]
675 ci = commands.get(c,None)
676 if ci == None:
677 print "Unknown command: '%s', type 'help' for list of known commands" %(c)
678 return 0
679 return ci[1](ctx, args)
680
681
682def interpret(ctx):
683 vbox = ctx['vb']
684 print "Running VirtualBox version %s" %(vbox.version)
685 ctx['perf'] = PerfCollector(vbox)
686
687 autoCompletion(commands, ctx)
688
689 # to allow to print actual host information, we collect info for
690 # last 150 secs maximum, (sample every 10 secs and keep up to 15 samples)
691 if ctx['perf']:
692 try:
693 ctx['perf'].setup(['*'], [vbox.host], 10, 15)
694 except:
695 pass
696
697 while True:
698 try:
699 cmd = raw_input("vbox> ")
700 done = runCommand(ctx, cmd)
701 if done != 0: break
702 except KeyboardInterrupt:
703 print '====== You can type quit or q to leave'
704 break
705 except EOFError:
706 break;
707 except Exception,e:
708 print e
709 if g_verbose:
710 traceback.print_exc()
711
712 try:
713 # There is no need to disable metric collection. This is just an example.
714 if ct['perf']:
715 ctx['perf'].disable(['*'], [vbox.host])
716 except:
717 pass
718
719
720from vboxapi import VirtualBoxManager
721
722def main(argv):
723 style = None
724 if len(argv) > 1:
725 if argv[1] == "-w":
726 style = "WEBSERVICE"
727
728 g_virtualBoxManager = VirtualBoxManager(style, None)
729 ctx = {'global':g_virtualBoxManager,
730 'mgr':g_virtualBoxManager.mgr,
731 'vb':g_virtualBoxManager.vbox,
732 'ifaces':g_virtualBoxManager.constants,
733 'remote':g_virtualBoxManager.remote,
734 'type':g_virtualBoxManager.type
735 }
736 interpret(ctx)
737 g_virtualBoxManager.deinit()
738 del g_virtualBoxManager
739
740if __name__ == '__main__':
741 main(sys.argv)
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette