Question

I'm having some trouble mapping native OSX calls from OCaml where the c call expects a buffer and size to be passed in. I've worked through the examples in Real World OCaml on using CTypes and Foreign but they don't cover this case or at least it's not clear to me how I'd to it.

Here's my snippet of OCaml:

open Core.Std
open Unix
open Ctypes
open Foreign

(* from /usr/include/libproc.h
  int proc_pidpath(int pid, void * buffer, uint32_t  buffersize);
*)
let proc_pidpath = foreign "proc_pidpath" (int @-> ptr void @-> int @-> returning int)

let () =
  let pid = Pid.to_int (Unix.getpid ()) in
  let buf = allocate string 255 in
  let path = proc_pidpath(pid, buf, 255) in
  printf "Pid: %i Path: %s\n" pid buf

How do I allocate a buffer to pass into proc_pidpath() and is there a nicer way of wrapping this call so it returns an Option type (String or Nil) or just a String?

Was it helpful?

Solution

This question share a lot of the issue with this one. I encourage you to have a look at it.

For your particular problem the following should work (it doesn't use Core so you may have to adjust some things, did they make the result of Unix.getpid abstract ?).

open Ctypes;;
open Foreign;;

module Proc : sig
  val pidpath : int -> string 
  (** @raise [Unix.Unix_error] in case of error *)
end = struct

  let pidpathinfo_maxsize = 1024 * 4 
  (* value of PROC_PIDPATHINFO_MAXSIZE. 
     N.B. this should not be hardcoded, see 1) in this answer 
     https://stackoverflow.com/questions/20851390 *)

  let char_array_as_string a len =    
  (* This function should soon no longer be required see:
     https://github.com/ocamllabs/ocaml-ctypes/pull/139 *)
    let b = Buffer.create len in 
    for i = 0 to len -1 do Buffer.add_char b (Array.get a i) done;
    Buffer.contents b

  let pidpath = 
    foreign ~check_errno:true "proc_pidpath"
      (int @-> ptr char @-> int @-> returning int)

  let pidpath pid =
    let path = Array.make char ~initial:'\x00' pidpathinfo_maxsize in 
    let len = pidpath pid (Array.start path) pidpathinfo_maxsize in
    char_array_as_string path len
end

let () =
  let print_pidpath pid = 
    try
      let path = Proc.pidpath pid in 
      Format.printf "Pid %d: %s@." pid path; 
    with Unix.Unix_error (e, _, _) -> 
      Format.eprintf "Pid %d: %s@." pid (Unix.error_message e)
  in
  print_pidpath (Unix.getpid ()); 
  print_pidpath (-10000 (* bogus *))
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top