type pathname = string
type info = {
+ kv_i : int;
kernel_version : string;
arch : string;
basename : string;
| FStructPointer of string
| FVoidPointer
| FAnonListHeadPointer
- | FListHeadPointer of string
+ | FListHeadPointer of (string * string) option
| FInteger
| FString of int
let string_of_info i =
- sprintf "%s: %s %s" i.basename i.kernel_version i.arch
+ sprintf "%s: %s (%d) %s" i.basename i.kernel_version i.kv_i i.arch
let rec string_of_structure s =
let fields = List.map string_of_field s.struct_fields in
| FStructPointer struct_name -> sprintf "struct %s *" struct_name
| FVoidPointer -> "void *"
| FAnonListHeadPointer -> "struct list_head *"
- | FListHeadPointer struct_name ->
- sprintf "struct /* %s */ list_head *" struct_name
+ | FListHeadPointer None ->
+ sprintf "struct /* self */ list_head *"
+ | FListHeadPointer (Some (struct_name, field_name)) ->
+ sprintf "struct /* to %s.%s */ list_head *" struct_name field_name
| FInteger -> "int"
| FString width -> sprintf "char[%d]" width
+let file_exists name =
+ try Unix.access name [Unix.F_OK]; true
+ with Unix.Unix_error _ -> false
+
(* Regular expressions. We really really should use ocaml-mikmatch ... *)
let re_oldformat = Pcre.regexp "^RPM: \\d+: \\(build \\d+\\) ([-\\w]+) ([\\w.]+) ([\\w.]+) \\(.*?\\) (\\w+)"
let re_keyvalue = Pcre.regexp "^(\\w+): (.*)"
(* Parse in the *.info files. These have historically had a few different
* formats that we need to support.
*)
- let infos = List.map (
- fun filename ->
+ let infos = List.mapi (
+ fun i filename ->
(* Get the basename (for getting the .data file later on). *)
let basename = Filename.chop_suffix filename ".info" in
(*printf "%s -> %s %s\n%!" basename version arch;*)
- { basename = basename; arch = arch;
+ { kv_i = i;
+ basename = basename; arch = arch;
kernel_version = version }
) infos in
+
+ (* Check the .data, .data.gz or .data.bz2 file exists, and skip with
+ * a warning if not.
+ *)
+ let infos = List.filter (
+ fun { basename = basename } ->
+ if not (file_exists (basename ^ ".data")) &&
+ not (file_exists (basename ^ ".data.gz")) &&
+ not (file_exists (basename ^ ".data.bz2")) then (
+ eprintf "warning: %s: no data file found for this kernel - skipping\n%!"
+ basename;
+ false
+ )
+ else
+ true
+ ) infos in
+
infos
(* XXX This would be better as a proper lex/yacc parser.
) struct_names;
(* Now read the data file and parse out the structures of interest. *)
- let file_exists name =
- try Unix.access name [Unix.F_OK]; true
- with Unix.Unix_error _ -> false
- in
let close_process_in cmd chan =
match Unix.close_process_in chan with
| Unix.WEXITED 0 -> ()
*)
let h = Hashtbl.create 13 in
+ (* A hash to check for fields which aren't always available by
+ * counting the number of times we see each field.
+ *)
+ let count, get =
+ let h = Hashtbl.create 13 in
+ let count field_name =
+ let r =
+ try Hashtbl.find h field_name
+ with Not_found -> let r = ref 0 in Hashtbl.add h field_name r; r in
+ incr r
+ in
+ let get field_name = try !(Hashtbl.find h field_name) with Not_found -> 0 in
+ count, get
+ in
+
List.iter (
fun ({kernel_version = version},
{struct_name = struct_name; struct_fields = fields}) ->
List.iter (
fun {field_name = name; field_type = typ} ->
+ count name;
try
let (field_type, version_first_seen) = Hashtbl.find h name in
if typ <> field_type then (
) fields
) structures;
+ let nr_kernels = List.length structures in
+
let fields =
Hashtbl.fold (
fun name (typ, _) fields ->
- (name, typ) :: fields
+ let always_available = get name = nr_kernels in
+ (name, (typ, always_available)) :: fields
) h [] in
List.sort fields