Fix 'make install'
[virt-mem.git] / ps / virt_ps.ml
index 94301ce..a9bcf1f 100644 (file)
@@ -21,16 +21,81 @@ open Printf
 
 open Virt_mem_gettext.Gettext
 open Virt_mem_utils
-open Virt_mem_mmap
+open Virt_mem_types
 
-let usage = s_"NAME
-  virt-ps - process listing command for virtual machines
+open Kernel_task_struct
 
-SUMMARY
-  virt-ps [-options] [domains]
+let run debug (image, ksymmap, utsname) =
+  try
+    let { domname = domname } = image in
 
-DESCRIPTION
-  virt-ps prints a process listing for virtual machines running under
-  libvirt."
+    let kernel_version =
+      match utsname with
+      | None ->
+         eprintf (f_"%s: could not guess kernel version\n") domname;
+         raise Exit
+      | Some { kernel_release = v } -> v in
 
-let debug, images = Virt_mem.start usage
+    if not (task_struct_known kernel_version) then (
+      eprintf (f_"%s: %s: unknown kernel version
+Try a newer version of virt-mem, or if the guest is not from a
+supported Linux distribution, see this page about adding support:
+  http://et.redhat.com/~rjones/virt-mem/faq.html\n") domname kernel_version;
+      raise Exit
+    );
+
+    let task_struct_size = task_struct_size kernel_version in
+
+    let init_task, init_task_addr =
+      let init_task_addr =
+       try Ksymmap.find "init_task" ksymmap
+       with Not_found ->
+         eprintf (f_"%s: could not find init_task in kernel image\n") domname;
+         raise Exit in
+      let init_task =
+       get_task_struct kernel_version image.mem init_task_addr in
+      init_task, init_task_addr in
+
+    (* Starting at init_task, navigate through the linked list of
+     * tasks (through tasks.next).  Grab each task_struct as we go.
+     *)
+    let tasks, image =
+      let rec loop image acc task =
+       let next = task.task_struct_tasks'next in
+       if next <> init_task_addr then (
+         let mapped =
+           Virt_mem_mmap.is_mapped_range image.mem next task_struct_size in
+         let image =
+           if not mapped then load_memory image next task_struct_size
+           else image in
+         let task = get_task_struct kernel_version image.mem next in
+         let task = {
+           task with
+             task_struct_comm = truncate_c_string task.task_struct_comm
+         } in
+         let acc = task :: acc in
+         loop image acc task
+       ) else
+         acc, image
+      in
+      loop image [] init_task in
+
+    (* Sort tasks by PID. *)
+    let cmp { task_struct_pid = p1 } { task_struct_pid = p2 } = compare p1 p2 in
+    let tasks = List.sort cmp tasks in
+
+    printf "  PID STAT COMMAND\n";
+
+    List.iter (
+      fun task ->
+       printf "%5Ld      %s\n" task.task_struct_pid task.task_struct_comm
+    ) tasks
+
+  with Exit -> ()
+
+let summary = s_"list processes in virtual machine"
+let description = s_"\
+virt-ps prints a process listing for virtual machines running under
+libvirt."
+
+let () = Virt_mem.register "ps" summary description ~run