Richard W.M. Jones
2012-Oct-30 11:57 UTC
[Libguestfs] [PATCH v2 0/7] Add symbol versioning (now working).
This rather more complex patch series adds symbol versioning (7/7 shows it in action). This works for me, tested by running old and new virt-inspector binaries against the new library. Rich.
Richard W.M. Jones
2012-Oct-30 11:57 UTC
[Libguestfs] [PATCH v2 1/7] generator: Move struct-freeing functions to a separate source file.
From: "Richard W.M. Jones" <rjones at redhat.com> This is just code motion. --- .gitignore | 1 + generator/c.ml | 69 +++++++++++++++++++++++++++++++++---------------------- generator/main.ml | 1 + po/POTFILES | 1 + src/Makefile.am | 2 ++ 5 files changed, 47 insertions(+), 27 deletions(-) diff --git a/.gitignore b/.gitignore index 5b91286..b3c9ef7 100644 --- a/.gitignore +++ b/.gitignore @@ -346,6 +346,7 @@ Makefile.in /src/errnostring-gperf.c /src/errnostring-gperf.gperf /src/errnostring.h +/src/free-structs.c /src/guestfs.3 /src/guestfs-actions.pod /src/guestfs-availability.pod diff --git a/generator/c.ml b/generator/c.ml index ac8fd5e..484b4f9 100644 --- a/generator/c.ml +++ b/generator/c.ml @@ -687,6 +687,48 @@ and generate_internal_actions_h () c_name style ) non_daemon_functions +(* Functions to free structures. *) +and generate_client_free_structs () + generate_header CStyle LGPLv2plus; + + pr "\ +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> + +#include \"guestfs.h\" +#include \"guestfs-internal.h\" +#include \"guestfs_protocol.h\" + +"; + + pr "/* Structure-freeing functions. These rely on the fact that the\n"; + pr " * structure format is identical to the XDR format. See note in\n"; + pr " * generator.ml.\n"; + pr " */\n"; + pr "\n"; + + List.iter ( + fun (typ, _) -> + pr "void\n"; + pr "guestfs_free_%s (struct guestfs_%s *x)\n" typ typ; + pr "{\n"; + pr " xdr_free ((xdrproc_t) xdr_guestfs_int_%s, (char *) x);\n" typ; + pr " free (x);\n"; + pr "}\n"; + pr "\n"; + + pr "void\n"; + pr "guestfs_free_%s_list (struct guestfs_%s_list *x)\n" typ typ; + pr "{\n"; + pr " xdr_free ((xdrproc_t) xdr_guestfs_int_%s_list, (char *) x);\n" typ; + pr " free (x);\n"; + pr "}\n"; + pr "\n"; + + ) structs + (* Generate the client-side dispatch stubs. *) and generate_client_actions () generate_header CStyle LGPLv2plus; @@ -1425,33 +1467,6 @@ trace_send_line (guestfs_h *g) fun f -> generate_daemon_stub f ) daemon_functions; - (* Functions to free structures. *) - pr "/* Structure-freeing functions. These rely on the fact that the\n"; - pr " * structure format is identical to the XDR format. See note in\n"; - pr " * generator.ml.\n"; - pr " */\n"; - pr "\n"; - - List.iter ( - fun (typ, _) -> - pr "void\n"; - pr "guestfs_free_%s (struct guestfs_%s *x)\n" typ typ; - pr "{\n"; - pr " xdr_free ((xdrproc_t) xdr_guestfs_int_%s, (char *) x);\n" typ; - pr " free (x);\n"; - pr "}\n"; - pr "\n"; - - pr "void\n"; - pr "guestfs_free_%s_list (struct guestfs_%s_list *x)\n" typ typ; - pr "{\n"; - pr " xdr_free ((xdrproc_t) xdr_guestfs_int_%s_list, (char *) x);\n" typ; - pr " free (x);\n"; - pr "}\n"; - pr "\n"; - - ) structs; - (* Functions which have optional arguments have two or three * generated variants. *) diff --git a/generator/main.ml b/generator/main.ml index 4cb3c7c..8d60850 100644 --- a/generator/main.ml +++ b/generator/main.ml @@ -84,6 +84,7 @@ Run it from the top source directory using the command output_to "src/guestfs.h" generate_guestfs_h; output_to "src/guestfs-internal-actions.h" generate_internal_actions_h; output_to "src/actions.c" generate_client_actions; + output_to "src/free-structs.c" generate_client_free_structs; output_to "src/bindtests.c" generate_bindtests; output_to "src/guestfs-structs.pod" generate_structs_pod; output_to "src/guestfs-actions.pod" generate_actions_pod; diff --git a/po/POTFILES b/po/POTFILES index a73377d..3f49a05 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -225,6 +225,7 @@ src/errnostring.c src/events.c src/file.c src/filearch.c +src/free-structs.c src/fuse.c src/guestfs.c src/info.c diff --git a/src/Makefile.am b/src/Makefile.am index 5f80bc1..082c122 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -28,6 +28,7 @@ generator_built = \ errnostring-gperf.gperf \ errnostring.c \ errnostring.h \ + free-structs.c \ guestfs-actions.pod \ guestfs-availability.pod \ guestfs-structs.pod \ @@ -130,6 +131,7 @@ libguestfs_la_SOURCES = \ events.c \ file.c \ filearch.c \ + free-structs.c \ fuse.c \ info.c \ inspect.c \ -- 1.7.11.4
Richard W.M. Jones
2012-Oct-30 11:57 UTC
[Libguestfs] [PATCH v2 2/7] lib: Force visibility default on public actions.
From: "Richard W.M. Jones" <rjones at redhat.com> This is currently done implicitly because of the linker script. However in order to do symbol versioning, we will have to do this explicitly at each definition instead. --- generator/c.ml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/generator/c.ml b/generator/c.ml index 484b4f9..798a3a3 100644 --- a/generator/c.ml +++ b/generator/c.ml @@ -711,7 +711,7 @@ and generate_client_free_structs () List.iter ( fun (typ, _) -> - pr "void\n"; + pr "GUESTFS_DLL_PUBLIC void\n"; pr "guestfs_free_%s (struct guestfs_%s *x)\n" typ typ; pr "{\n"; pr " xdr_free ((xdrproc_t) xdr_guestfs_int_%s, (char *) x);\n" typ; @@ -719,7 +719,7 @@ and generate_client_free_structs () pr "}\n"; pr "\n"; - pr "void\n"; + pr "GUESTFS_DLL_PUBLIC void\n"; pr "guestfs_free_%s_list (struct guestfs_%s_list *x)\n" typ typ; pr "{\n"; pr " xdr_free ((xdrproc_t) xdr_guestfs_int_%s_list, (char *) x);\n" typ; @@ -1115,10 +1115,12 @@ trace_send_line (guestfs_h *g) if optargs = [] then generate_prototype ~extern:false ~semicolon:false ~newline:true ~handle:"g" ~prefix:"guestfs_" + ~dll_public:true c_name style else generate_prototype ~extern:false ~semicolon:false ~newline:true ~handle:"g" ~prefix:"guestfs_" ~suffix:"_argv" ~optarg_proto:Argv + ~dll_public:true c_name style; pr "{\n"; @@ -1191,11 +1193,15 @@ trace_send_line (guestfs_h *g) (* Generate the action stub. *) if optargs = [] then generate_prototype ~extern:false ~semicolon:false ~newline:true - ~handle:"g" ~prefix:"guestfs_" c_name style + ~handle:"g" ~prefix:"guestfs_" + ~dll_public:true + c_name style else generate_prototype ~extern:false ~semicolon:false ~newline:true ~handle:"g" ~prefix:"guestfs_" ~suffix:"_argv" - ~optarg_proto:Argv c_name style; + ~optarg_proto:Argv + ~dll_public:true + c_name style; pr "{\n"; -- 1.7.11.4
Richard W.M. Jones
2012-Oct-30 11:57 UTC
[Libguestfs] [PATCH v2 3/7] Temporarily disable OCaml warning 23.
From: "Richard W.M. Jones" <rjones at redhat.com> --- generator/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generator/Makefile.am b/generator/Makefile.am index e218ffa..276c2cf 100644 --- a/generator/Makefile.am +++ b/generator/Makefile.am @@ -57,7 +57,7 @@ OBJECTS = $(SOURCES_ML:.ml=.cmo) EXTRA_DIST = $(SOURCES) files-generated.txt -OCAMLCFLAGS = -warn-error CDEFLMPSUVYZX +OCAMLCFLAGS = -warn-error CDEFLMPSUVYZ+14+15+16+17+18+19+20+21+22+24+25+30-23 OCAMLCLIBS = unix.cma str.cma noinst_PROGRAM = generator -- 1.7.11.4
Richard W.M. Jones
2012-Oct-30 11:57 UTC
[Libguestfs] [PATCH v2 4/7] generator: Use an OCaml struct to store the structs.
From: "Richard W.M. Jones" <rjones at redhat.com> This just makes it simpler to add extra fields to each struct. This is code motion, although the output of the generator changes very slightly: the camel-cased structs are no longer stored sorted, so the generated lists in java/Makefile.in and java/com/redhat/et/libguestfs/.gitignore change order. --- generator/c.ml | 8 +- generator/csharp.ml | 2 +- generator/erlang.ml | 2 +- generator/fish.ml | 2 +- generator/gobject.ml | 2 +- generator/java.ml | 6 +- generator/main.ml | 6 +- generator/ocaml.ml | 4 +- generator/python.ml | 2 +- generator/structs.ml | 165 ++++++++++++++++++------------- generator/structs.mli | 18 ++-- generator/xdr.ml | 3 +- java/Makefile.inc | 24 ++--- java/com/redhat/et/libguestfs/.gitignore | 24 ++--- 14 files changed, 153 insertions(+), 115 deletions(-) diff --git a/generator/c.ml b/generator/c.ml index 798a3a3..54f35b5 100644 --- a/generator/c.ml +++ b/generator/c.ml @@ -311,7 +311,7 @@ and generate_actions_pod_back_compat_entry { name = name; and generate_structs_pod () (* Structs documentation. *) List.iter ( - fun (typ, cols) -> + fun { s_name = typ; s_cols = cols } -> pr "=head2 guestfs_%s\n" typ; pr "\n"; pr " struct guestfs_%s {\n" typ; @@ -542,7 +542,7 @@ extern GUESTFS_DLL_PUBLIC void *guestfs_next_private (guestfs_h *g, const char * (* Public structures. *) List.iter ( - fun (typ, cols) -> + fun { s_name = typ; s_cols = cols } -> pr "struct guestfs_%s {\n" typ; List.iter ( function @@ -710,7 +710,7 @@ and generate_client_free_structs () pr "\n"; List.iter ( - fun (typ, _) -> + fun { s_name = typ } -> pr "GUESTFS_DLL_PUBLIC void\n"; pr "guestfs_free_%s (struct guestfs_%s *x)\n" typ typ; pr "{\n"; @@ -1661,7 +1661,7 @@ and generate_linker_script () ) in let structs List.concat ( - List.map (fun (typ, _) -> + List.map (fun { s_name = typ } -> ["guestfs_free_" ^ typ; "guestfs_free_" ^ typ ^ "_list"]) structs ) in diff --git a/generator/csharp.ml b/generator/csharp.ml index 9f86f48..803a4a5 100644 --- a/generator/csharp.ml +++ b/generator/csharp.ml @@ -110,7 +110,7 @@ namespace Guestfs * method names (eg. "class stat" and "stat"). *) List.iter ( - fun (typ, cols) -> + fun { s_name = typ; s_cols = cols } -> pr " [StructLayout (LayoutKind.Sequential)]\n"; pr " public class _%s {\n" typ; List.iter ( diff --git a/generator/erlang.ml b/generator/erlang.ml index 673394e..6c7eb70 100644 --- a/generator/erlang.ml +++ b/generator/erlang.ml @@ -237,7 +237,7 @@ extern void free_strings (char **r); in List.iter ( - fun (typ, cols) -> + fun { s_name = typ; s_cols = cols } -> pr "static ETERM *\n"; pr "make_%s (const struct guestfs_%s *%s)\n" typ typ typ; pr "{\n"; diff --git a/generator/fish.ml b/generator/fish.ml index 76377a2..59c1114 100644 --- a/generator/fish.ml +++ b/generator/fish.ml @@ -227,7 +227,7 @@ Guestfish will prompt for these separately." (* print_* functions *) List.iter ( - fun (typ, cols) -> + fun { s_name = typ; s_cols = cols } -> let needs_i List.exists (function (_, (FUUID|FBuffer)) -> true | _ -> false) cols in diff --git a/generator/gobject.ml b/generator/gobject.ml index 2cd1809..6c35e02 100644 --- a/generator/gobject.ml +++ b/generator/gobject.ml @@ -107,7 +107,7 @@ let filenames "session" :: "tristate" :: (* structs *) - List.map (function typ, cols -> "struct-" ^ typ) structs @ + List.map (fun { s_name = typ } -> "struct-" ^ typ) structs @ (* optargs *) List.map (function { name = name } -> "optargs-" ^ name) ( diff --git a/generator/java.ml b/generator/java.ml index 1e06c62..bffe077 100644 --- a/generator/java.ml +++ b/generator/java.ml @@ -875,10 +875,10 @@ and generate_java_makefile_inc () pr "java_built_sources = \\\n"; List.iter ( - fun (typ, jtyp) -> + fun { s_name = typ; s_camel_name = jtyp } -> pr "\tcom/redhat/et/libguestfs/%s.java \\\n" jtyp; - ) camel_structs; + ) structs; pr "\tcom/redhat/et/libguestfs/GuestFS.java\n" and generate_java_gitignore () - List.iter (fun (_, jtyp) -> pr "%s.java\n" jtyp) camel_structs + List.iter (fun { s_camel_name = jtyp } -> pr "%s.java\n" jtyp) structs diff --git a/generator/main.ml b/generator/main.ml index 8d60850..98f4b31 100644 --- a/generator/main.ml +++ b/generator/main.ml @@ -124,11 +124,11 @@ Run it from the top source directory using the command output_to "java/com/redhat/et/libguestfs/GuestFS.java" generate_java_java; List.iter ( - fun (typ, jtyp) -> + fun { s_name = typ; s_camel_name = jtyp } -> let cols = cols_of_struct typ in let filename = sprintf "java/com/redhat/et/libguestfs/%s.java" jtyp in output_to filename (generate_java_struct jtyp cols) - ) camel_structs; + ) structs; delete_except_generated ~skip:["java/com/redhat/et/libguestfs/LibGuestFSException.java"] "java/com/redhat/et/libguestfs/*.java"; @@ -152,7 +152,7 @@ Run it from the top source directory using the command output_to "gobject/docs/guestfs-title.sgml" generate_gobject_doc_title; List.iter ( - fun (typ, cols) -> + fun { s_name = typ; s_cols = cols } -> let short = sprintf "struct-%s" typ in let filename sprintf "gobject/include/guestfs-gobject/%s.h" short in diff --git a/generator/ocaml.ml b/generator/ocaml.ml index b90aeb8..f9ac5ca 100644 --- a/generator/ocaml.ml +++ b/generator/ocaml.ml @@ -377,7 +377,7 @@ copy_table (char * const * argv) in List.iter ( - fun (typ, cols) -> + fun { s_name = typ; s_cols = cols } -> let has_optpercent_col List.exists (function (_, FOptPercent) -> true | _ -> false) cols in @@ -672,7 +672,7 @@ copy_table (char * const * argv) and generate_ocaml_structure_decls () List.iter ( - fun (typ, cols) -> + fun { s_name = typ; s_cols = cols } -> pr "type %s = {\n" typ; List.iter ( function diff --git a/generator/python.ml b/generator/python.ml index 3975055..0e754db 100644 --- a/generator/python.ml +++ b/generator/python.ml @@ -160,7 +160,7 @@ free_strings (char **argv) (* Structures, turned into Python dictionaries. *) List.iter ( - fun (typ, cols) -> + fun { s_name = typ; s_cols = cols } -> pr "static PyObject *\n"; pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ; pr "{\n"; diff --git a/generator/structs.ml b/generator/structs.ml index d62fcc5..4c8e2ef 100644 --- a/generator/structs.ml +++ b/generator/structs.ml @@ -22,6 +22,11 @@ open Types open Utils type cols = (string * field) list +type struc = { + s_name : string; + s_cols : cols; + s_camel_name : string; +} (* Because we generate extra parsing code for LVM command line tools, * we have to pull out the LVM columns separately here. @@ -88,6 +93,8 @@ let lvm_lv_cols = [ "modules", FString; ] +let defaults = { s_name = ""; s_cols = []; s_camel_name = "" } + (* Names and fields in all structures (in RStruct and RStructList) * that we support. *) @@ -95,21 +102,29 @@ let structs = [ (* The old RIntBool return type, only ever used for aug_defnode. Do * not use this struct in any new code. *) - "int_bool", [ + { defaults with + s_name = "int_bool"; + s_cols = [ "i", FInt32; (* for historical compatibility *) "b", FInt32; (* for historical compatibility *) - ]; + ]; + s_camel_name = "IntBool" }; (* LVM PVs, VGs, LVs. *) - "lvm_pv", lvm_pv_cols; - "lvm_vg", lvm_vg_cols; - "lvm_lv", lvm_lv_cols; + { defaults with + s_name = "lvm_pv"; s_cols = lvm_pv_cols; s_camel_name = "PV" }; + { defaults with + s_name = "lvm_vg"; s_cols = lvm_vg_cols; s_camel_name = "VG" }; + { defaults with + s_name = "lvm_lv"; s_cols = lvm_lv_cols; s_camel_name = "LV" }; (* Column names and types from stat structures. * NB. Can't use things like 'st_atime' because glibc header files * define some of these as macros. Ugh. *) - "stat", [ + { defaults with + s_name = "stat"; + s_cols = [ "dev", FInt64; "ino", FInt64; "mode", FInt64; @@ -123,8 +138,11 @@ let structs = [ "atime", FInt64; "mtime", FInt64; "ctime", FInt64; - ]; - "statvfs", [ + ]; + s_camel_name = "Stat" }; + { defaults with + s_name = "statvfs"; + s_cols = [ "bsize", FInt64; "frsize", FInt64; "blocks", FInt64; @@ -136,48 +154,66 @@ let structs = [ "fsid", FInt64; "flag", FInt64; "namemax", FInt64; - ]; + ]; + s_camel_name = "StatVFS" }; (* Column names in dirent structure. *) - "dirent", [ + { defaults with + s_name = "dirent"; + s_cols = [ "ino", FInt64; (* 'b' 'c' 'd' 'f' (FIFO) 'l' 'r' (regular file) 's' 'u' '?' *) "ftyp", FChar; "name", FString; - ]; + ]; + s_camel_name = "Dirent" }; (* Version numbers. *) - "version", [ + { defaults with + s_name = "version"; + s_cols = [ "major", FInt64; "minor", FInt64; "release", FInt64; "extra", FString; - ]; + ]; + s_camel_name = "Version" }; (* Extended attribute. *) - "xattr", [ + { defaults with + s_name = "xattr"; + s_cols = [ "attrname", FString; "attrval", FBuffer; - ]; + ]; + s_camel_name = "XAttr" }; (* Inotify events. *) - "inotify_event", [ + { defaults with + s_name = "inotify_event"; + s_cols = [ "in_wd", FInt64; "in_mask", FUInt32; "in_cookie", FUInt32; "in_name", FString; - ]; + ]; + s_camel_name = "INotifyEvent" }; (* Partition table entry. *) - "partition", [ + { defaults with + s_name = "partition"; + s_cols = [ "part_num", FInt32; "part_start", FBytes; "part_end", FBytes; "part_size", FBytes; - ]; + ]; + s_camel_name = "Partition" }; (* Application. *) - "application", [ + { defaults with + s_name = "application"; + s_cols = [ "app_name", FString; "app_display_name", FString; "app_epoch", FInt32; @@ -190,10 +226,13 @@ let structs = [ "app_source_package", FString; "app_summary", FString; "app_description", FString; - ]; + ]; + s_camel_name = "Application" }; (* ISO primary volume descriptor. *) - "isoinfo", [ + { defaults with + s_name = "isoinfo"; + s_cols = [ "iso_system_id", FString; "iso_volume_id", FString; "iso_volume_space_size", FUInt32; @@ -211,24 +250,33 @@ let structs = [ "iso_volume_modification_t", FInt64; "iso_volume_expiration_t", FInt64; "iso_volume_effective_t", FInt64; - ]; + ]; + s_camel_name = "ISOInfo" }; (* /proc/mdstat information. See linux.git/drivers/md/md.c *) - "mdstat", [ + { defaults with + s_name = "mdstat"; + s_cols = [ "mdstat_device", FString; "mdstat_index", FInt32; "mdstat_flags", FString; - ]; + ]; + s_camel_name = "MDStat" }; (* btrfs subvolume list output *) - "btrfssubvolume", [ + { defaults with + s_name = "btrfssubvolume"; + s_cols = [ "btrfssubvolume_id", FUInt64; "btrfssubvolume_top_level_id", FUInt64; "btrfssubvolume_path", FString; - ]; + ]; + s_camel_name = "BTRFSSubvolume" }; (* XFS info descriptor. *) - "xfsinfo", [ + { defaults with + s_name = "xfsinfo"; + s_cols = [ "xfs_mntpoint", FString; "xfs_inodesize", FUInt32; "xfs_agcount", FUInt32; @@ -254,60 +302,45 @@ let structs = [ "xfs_rtextsize", FUInt32; "xfs_rtblocks", FUInt64; "xfs_rtextents", FUInt64; - ]; + ]; + s_camel_name = "XFSInfo" }; (* utsname *) - "utsname", [ + { defaults with + s_name = "utsname"; + s_cols = [ "uts_sysname", FString; "uts_release", FString; "uts_version", FString; "uts_machine", FString; - ]; + ]; + s_camel_name = "UTSName" }; (* Used by hivex_* APIs to return a list of int64 handles (node * handles and value handles). Note that we can't add a putative * 'RInt64List' type to the generator because we need to return * length and size, and RStructList does this already. *) - "hivex_node", [ + { defaults with + s_name = "hivex_node"; + s_cols = [ "hivex_node_h", FInt64; - ]; - "hivex_value", [ + ]; + s_camel_name = "HivexNode" }; + { defaults with + s_name = "hivex_value"; + s_cols = [ "hivex_value_h", FInt64; - ]; + ]; + s_camel_name = "HivexValue" }; ] (* end of structs *) -(* For bindings which want camel case *) -let camel_structs = [ - "int_bool", "IntBool"; - "lvm_pv", "PV"; - "lvm_vg", "VG"; - "lvm_lv", "LV"; - "stat", "Stat"; - "statvfs", "StatVFS"; - "dirent", "Dirent"; - "version", "Version"; - "xattr", "XAttr"; - "inotify_event", "INotifyEvent"; - "partition", "Partition"; - "application", "Application"; - "isoinfo", "ISOInfo"; - "xfsinfo", "XFSInfo"; - "mdstat", "MDStat"; - "btrfssubvolume", "BTRFSSubvolume"; - "utsname", "UTSName"; - "hivex_node", "HivexNode"; - "hivex_value", "HivexValue"; -] -let camel_structs = List.sort (fun (_,a) (_,b) -> compare a b) camel_structs - -let camel_name_of_struct typ - try List.assoc typ camel_structs +let lookup_struct name + try List.find (fun { s_name = n } -> n = name) structs with Not_found -> failwithf - "camel_name_of_struct: no camel_structs entry corresponding to %s" typ + "lookup_struct: no structs entry corresponding to %s" name -let cols_of_struct typ - try List.assoc typ structs - with Not_found -> - failwithf "cols_of_struct: unknown struct %s" typ +let camel_name_of_struct name = (lookup_struct name).s_camel_name + +let cols_of_struct name = (lookup_struct name).s_cols diff --git a/generator/structs.mli b/generator/structs.mli index 56987e0..05df115 100644 --- a/generator/structs.mli +++ b/generator/structs.mli @@ -23,11 +23,14 @@ type cols = (string * Types.field) list (** List of structure fields (called "columns"). *) -val structs : (string * cols) list -(** List of structures. *) +type struc = { + s_name : string; (** Regular name. *) + s_cols : cols; (** Columns. *) + s_camel_name : string; (** Camel-cased name. *) +} -val camel_structs : (string * string) list -(** For bindings which want camel case struct names *) +val structs : struc list +(** List of structures. *) val lvm_pv_cols : cols val lvm_vg_cols : cols @@ -36,8 +39,11 @@ val lvm_lv_cols : cols used to generate code for parsing the output of commands like [lvs]. One day replace this with liblvm API calls. *) +val lookup_struct : string -> struc +(** Lookup a struct by name. *) + val camel_name_of_struct : string -> string -(** Camel case name of struct. *) +(** Lookup struct by name, return the s_camel_name field. *) val cols_of_struct : string -> cols -(** Extract columns of a struct. *) +(** Lookup struct by name, return the s_cols field. *) diff --git a/generator/xdr.ml b/generator/xdr.ml index b45f2c4..46b1c90 100644 --- a/generator/xdr.ml +++ b/generator/xdr.ml @@ -70,8 +70,7 @@ let generate_xdr () pr "/* Internal structures. */\n"; pr "\n"; List.iter ( - function - | typ, cols -> + fun { s_name = typ; s_cols = cols } -> pr "struct guestfs_int_%s {\n" typ; List.iter (function | name, FChar -> pr " char %s;\n" name diff --git a/java/Makefile.inc b/java/Makefile.inc index 64b533a..aa9f96c 100644 --- a/java/Makefile.inc +++ b/java/Makefile.inc @@ -20,23 +20,23 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. java_built_sources = \ - com/redhat/et/libguestfs/Application.java \ - com/redhat/et/libguestfs/BTRFSSubvolume.java \ - com/redhat/et/libguestfs/Dirent.java \ - com/redhat/et/libguestfs/HivexNode.java \ - com/redhat/et/libguestfs/HivexValue.java \ - com/redhat/et/libguestfs/INotifyEvent.java \ - com/redhat/et/libguestfs/ISOInfo.java \ com/redhat/et/libguestfs/IntBool.java \ - com/redhat/et/libguestfs/LV.java \ - com/redhat/et/libguestfs/MDStat.java \ com/redhat/et/libguestfs/PV.java \ - com/redhat/et/libguestfs/Partition.java \ + com/redhat/et/libguestfs/VG.java \ + com/redhat/et/libguestfs/LV.java \ com/redhat/et/libguestfs/Stat.java \ com/redhat/et/libguestfs/StatVFS.java \ - com/redhat/et/libguestfs/UTSName.java \ - com/redhat/et/libguestfs/VG.java \ + com/redhat/et/libguestfs/Dirent.java \ com/redhat/et/libguestfs/Version.java \ com/redhat/et/libguestfs/XAttr.java \ + com/redhat/et/libguestfs/INotifyEvent.java \ + com/redhat/et/libguestfs/Partition.java \ + com/redhat/et/libguestfs/Application.java \ + com/redhat/et/libguestfs/ISOInfo.java \ + com/redhat/et/libguestfs/MDStat.java \ + com/redhat/et/libguestfs/BTRFSSubvolume.java \ com/redhat/et/libguestfs/XFSInfo.java \ + com/redhat/et/libguestfs/UTSName.java \ + com/redhat/et/libguestfs/HivexNode.java \ + com/redhat/et/libguestfs/HivexValue.java \ com/redhat/et/libguestfs/GuestFS.java diff --git a/java/com/redhat/et/libguestfs/.gitignore b/java/com/redhat/et/libguestfs/.gitignore index 72a1144..eb332a8 100644 --- a/java/com/redhat/et/libguestfs/.gitignore +++ b/java/com/redhat/et/libguestfs/.gitignore @@ -1,19 +1,19 @@ -Application.java -BTRFSSubvolume.java -Dirent.java -HivexNode.java -HivexValue.java -INotifyEvent.java -ISOInfo.java IntBool.java -LV.java -MDStat.java PV.java -Partition.java +VG.java +LV.java Stat.java StatVFS.java -UTSName.java -VG.java +Dirent.java Version.java XAttr.java +INotifyEvent.java +Partition.java +Application.java +ISOInfo.java +MDStat.java +BTRFSSubvolume.java XFSInfo.java +UTSName.java +HivexNode.java +HivexValue.java -- 1.7.11.4
Richard W.M. Jones
2012-Oct-30 11:57 UTC
[Libguestfs] [PATCH v2 5/7] generator: Add symbol versioning.
From: "Richard W.M. Jones" <rjones at redhat.com> --- generator/actions.ml | 1 + generator/c.ml | 132 +++++++++++++++++++++++++++++++++++++++++++++----- generator/checks.ml | 10 ++++ generator/structs.ml | 4 +- generator/structs.mli | 2 + generator/types.ml | 2 + po/POTFILES | 1 + src/Makefile.am | 3 ++ src/compat.c | 26 ++++++++++ src/guestfs.pod | 26 ++++++++++ 10 files changed, 195 insertions(+), 12 deletions(-) create mode 100644 src/compat.c diff --git a/generator/actions.ml b/generator/actions.ml index 71aee37..e1db3db 100644 --- a/generator/actions.ml +++ b/generator/actions.ml @@ -32,6 +32,7 @@ let defaults = { name = ""; style = RErr, [], []; proc_nr = None; progress = false; camel_name = ""; cancellable = false; config_only = false; once_had_no_optargs = false; blocking = true; + symbol_version = None; c_name = ""; c_function = ""; c_optarg_prefix = ""; non_c_aliases = [] } diff --git a/generator/c.ml b/generator/c.ml index 54f35b5..5e75be1 100644 --- a/generator/c.ml +++ b/generator/c.ml @@ -710,7 +710,8 @@ and generate_client_free_structs () pr "\n"; List.iter ( - fun { s_name = typ } -> + function + | { s_name = typ; s_symbol_version = None } -> pr "GUESTFS_DLL_PUBLIC void\n"; pr "guestfs_free_%s (struct guestfs_%s *x)\n" typ typ; pr "{\n"; @@ -727,7 +728,38 @@ and generate_client_free_structs () pr "}\n"; pr "\n"; - ) structs + | { s_name = typ; s_symbol_version = Some v } -> + let suffix = "__" ^ replace_char v '.' '_' in + + pr "extern GUESTFS_DLL_PUBLIC void guestfs_free_%s%s (struct guestfs_%s *x);\n" + typ suffix typ; + pr "\n"; + pr "GUESTFS_DLL_PUBLIC void\n"; + pr "guestfs_free_%s%s (struct guestfs_%s *x)\n" typ suffix typ; + pr "{\n"; + pr " xdr_free ((xdrproc_t) xdr_guestfs_int_%s, (char *) x);\n" typ; + pr " free (x);\n"; + pr "}\n"; + pr "\n"; + + pr "extern GUESTFS_DLL_PUBLIC void guestfs_free_%s_list%s (struct guestfs_%s_list *x);\n" + typ suffix typ; + pr "\n"; + pr "GUESTFS_DLL_PUBLIC void\n"; + pr "guestfs_free_%s_list%s (struct guestfs_%s_list *x)\n" typ suffix typ; + pr "{\n"; + pr " xdr_free ((xdrproc_t) xdr_guestfs_int_%s_list, (char *) x);\n" typ; + pr " free (x);\n"; + pr "}\n"; + pr "\n"; + + ) structs; + + pr "/* Include backwards compatibility code for old ABIs. */\n"; + pr "#define COMPAT_STRUCTS 1\n"; + pr "#include \"compat.c\"\n"; + pr "\n"; + pr "/* EOF */\n" (* Generate the client-side dispatch stubs. *) and generate_client_actions () @@ -1108,18 +1140,53 @@ trace_send_line (guestfs_h *g) ) in + (* GCC symver won't let us just use the external name of the + * function if the function has multiple versions. Instead we + * have to give the function a unique, non-exported name + * ('guestfs_...__<VERSION>'). + *) + let suffix_for_symbol_versions c_name style = function + | None -> "" + | Some v -> + let suffix = "__" ^ replace_char v '.' '_' in + + pr "/* This symbol has multiple versions, resolved by the linker\n"; + pr " * at run time. This is the latest version used for new code.\n"; + pr " * See src/compat.c for old compatibility versions.\n"; + pr " */\n"; + let _, _, optargs = style in + if optargs = [] then + generate_prototype ~extern:true ~single_line:true ~newline:true + ~handle:"g" ~prefix:"guestfs_" ~suffix + ~dll_public:true + c_name style + else + generate_prototype ~extern:true ~single_line:true ~newline:true + ~handle:"g" ~prefix:"guestfs_" ~suffix:("_argv" ^ suffix) + ~optarg_proto:Argv + ~dll_public:true + c_name style; + pr "\n"; + + suffix + in + (* For non-daemon functions, generate a wrapper around each function. *) let generate_non_daemon_wrapper { name = name; c_name = c_name; style = ret, _, optargs as style; - config_only = config_only } + config_only = config_only; + symbol_version = symbol_version } + let suffix = suffix_for_symbol_versions c_name style symbol_version in + if optargs = [] then generate_prototype ~extern:false ~semicolon:false ~newline:true - ~handle:"g" ~prefix:"guestfs_" + ~handle:"g" ~prefix:"guestfs_" ~suffix ~dll_public:true c_name style else generate_prototype ~extern:false ~semicolon:false ~newline:true - ~handle:"g" ~prefix:"guestfs_" ~suffix:"_argv" ~optarg_proto:Argv + ~handle:"g" ~prefix:"guestfs_" ~suffix:("_argv" ^ suffix) + ~optarg_proto:Argv ~dll_public:true c_name style; pr "{\n"; @@ -1184,21 +1251,24 @@ trace_send_line (guestfs_h *g) (* Client-side stubs for each function. *) let generate_daemon_stub { name = name; c_name = c_name; - style = ret, args, optargs as style } + style = ret, args, optargs as style; + symbol_version = symbol_version } let errcode match errcode_of_ret ret with | `CannotReturnError -> assert false | (`ErrorIsMinusOne | `ErrorIsNULL) as e -> e in + let suffix = suffix_for_symbol_versions c_name style symbol_version in + (* Generate the action stub. *) if optargs = [] then generate_prototype ~extern:false ~semicolon:false ~newline:true - ~handle:"g" ~prefix:"guestfs_" + ~handle:"g" ~prefix:"guestfs_" ~suffix ~dll_public:true c_name style else generate_prototype ~extern:false ~semicolon:false ~newline:true - ~handle:"g" ~prefix:"guestfs_" ~suffix:"_argv" + ~handle:"g" ~prefix:"guestfs_" ~suffix:("_argv" ^ suffix) ~optarg_proto:Argv ~dll_public:true c_name style; @@ -1599,7 +1669,13 @@ trace_send_line (guestfs_h *g) | ({ style = _, _, (_::_); once_had_no_optargs = true } as f) -> generate_va_variants f; generate_back_compat_wrapper f - ) all_functions_sorted + ) all_functions_sorted; + + pr "/* Include backwards compatibility code for old ABIs. */\n"; + pr "#define COMPAT_ACTIONS 1\n"; + pr "#include \"compat.c\"\n"; + pr "\n"; + pr "/* EOF */\n" (* Generate the linker script which controls the visibility of * symbols in the public ABI and ensures no other symbols get @@ -1667,14 +1743,48 @@ and generate_linker_script () ) in let globals = List.sort compare (globals @ functions @ structs) in - pr "{\n"; + pr "GUESTFS_0.0 {\n"; pr " global:\n"; List.iter (pr " %s;\n") globals; pr "\n"; pr " local:\n"; pr " *;\n"; - pr "};\n" + pr "};\n"; + + (* Explicitly versioned symbols. *) + let h = Hashtbl.create 13 in + List.iter ( + function + | { symbol_version = None } -> () + | { name = name; symbol_version = Some ver } -> + let names = try Hashtbl.find h ver with Not_found -> [] in + Hashtbl.replace h ver (name :: names) + ) all_functions; + List.iter ( + function + | { s_symbol_version = None } -> () + | { s_name = name; s_symbol_version = Some ver } -> + let names = try Hashtbl.find h ver with Not_found -> [] in + Hashtbl.replace h ver + (sprintf "free_%s" name :: sprintf "free_%s_list" name :: names) + ) Structs.structs; + let vers = Hashtbl.fold (fun k _ ks -> k :: ks) h [] in + let vers = List.sort compare vers in + let prev = ref "GUESTFS_0.0" in + List.iter ( + fun ver -> + let names = Hashtbl.find h ver in + let names = List.sort compare names in + + pr "\n"; + pr "%s {\n" ver; + pr " global:\n"; + List.iter (pr " guestfs_%s;\n") names; + pr "} %s;\n" !prev; + + prev := ver + ) vers and generate_max_proc_nr () pr "%d\n" max_proc_nr diff --git a/generator/checks.ml b/generator/checks.ml index 2cccf26..f813fbf 100644 --- a/generator/checks.ml +++ b/generator/checks.ml @@ -243,6 +243,16 @@ let () | { blocking = true } -> () ) daemon_functions; + (* Check symbol version string is sane. *) + List.iter ( + function + | { name = name; symbol_version = Some ver } -> + let len = String.length ver in + if len < 12 || String.sub ver 0 10 <> "GUESTFS_1." then + failwithf "%s: invalid symbol_version (%s)" name ver + | { symbol_version = None } -> () + ) all_functions; + (* Non-fish functions must have correct camel_name. *) List.iter ( fun { name = name; camel_name = camel_name } -> diff --git a/generator/structs.ml b/generator/structs.ml index 4c8e2ef..499f825 100644 --- a/generator/structs.ml +++ b/generator/structs.ml @@ -26,6 +26,7 @@ type struc = { s_name : string; s_cols : cols; s_camel_name : string; + s_symbol_version : string option; } (* Because we generate extra parsing code for LVM command line tools, @@ -93,7 +94,8 @@ let lvm_lv_cols = [ "modules", FString; ] -let defaults = { s_name = ""; s_cols = []; s_camel_name = "" } +let defaults = { s_name = ""; s_cols = []; s_camel_name = ""; + s_symbol_version = None } (* Names and fields in all structures (in RStruct and RStructList) * that we support. diff --git a/generator/structs.mli b/generator/structs.mli index 05df115..4e1044d 100644 --- a/generator/structs.mli +++ b/generator/structs.mli @@ -27,6 +27,8 @@ type struc = { s_name : string; (** Regular name. *) s_cols : cols; (** Columns. *) s_camel_name : string; (** Camel-cased name. *) + s_symbol_version : string option; (** C symbol version. + See guestfs(3)/SYMBOL VERSIONING *) } val structs : struc list diff --git a/generator/types.ml b/generator/types.ml index cff3c6d..df019e8 100644 --- a/generator/types.ml +++ b/generator/types.ml @@ -399,6 +399,8 @@ type action = { set flags in the handle are marked non-blocking so that we don't add machinery in various bindings. *) + symbol_version : string option; (* C symbol version. + See guestfs(3)/SYMBOL VERSIONING *) (* "Internal" data attached by the generator at various stages. This * doesn't need to (and shouldn't) be set when defining actions. diff --git a/po/POTFILES b/po/POTFILES index 3f49a05..8cc71fe 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -219,6 +219,7 @@ src/actions.c src/appliance.c src/bindtests.c src/command.c +src/compat.c src/dbdump.c src/errnostring-gperf.c src/errnostring.c diff --git a/src/Makefile.am b/src/Makefile.am index 082c122..c567fe2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -46,6 +46,7 @@ EXTRA_DIST = \ libguestfs.3 \ libguestfs.pc libguestfs.pc.in \ guestfs.pod \ + compat.c \ api-support/added \ api-support/README \ api-support/update-from-tarballs.sh @@ -152,6 +153,8 @@ libguestfs_la_SOURCES = \ proto.c \ libguestfs.syms +actions.c: compat.c + libguestfs_la_LIBADD = \ $(PCRE_LIBS) $(MAGIC_LIBS) \ $(LIBVIRT_LIBS) $(LIBXML2_LIBS) \ diff --git a/src/compat.c b/src/compat.c new file mode 100644 index 0000000..27ffd05 --- /dev/null +++ b/src/compat.c @@ -0,0 +1,26 @@ +/* libguestfs + * Copyright (C) 2012 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* This is used for symbol versioning. See guestfs(3)/SYMBOL VERSIONING. + * + * XXX Symbol versioning only seems to work if all the related + * functions are compiled into a single file, so this file is + * #included directly into src/actions.c and src/free-structs.c, + * instead of being compiled as a separate unit. The cpp symbols + * COMPAT_ACTIONS or COMPAT_STRUCTS are defined as appropriate. + */ diff --git a/src/guestfs.pod b/src/guestfs.pod index 60664e7..04d8b6b 100644 --- a/src/guestfs.pod +++ b/src/guestfs.pod @@ -3499,6 +3499,32 @@ into the appliance. Debugging messages are never translated, since they are intended for the programmers. +=head2 SYMBOL VERSIONING + +The generator supports symbol versioning. This is used +B<as a last resort only> when we need to modify an API and we +cannot possibly make the change ABI compatible. Using symbol +versioning allows us to get older applications to transparently use a +compatibility function (preserving ABI) while newly compiled +applications get the new API. + +First, familiarize yourself with symbol versioning by reading the +relevant sections of the GNU ld documentation and this document by +Ulrich Drepper: L<http://www.akkadia.org/drepper/dsohowto.pdf> + +The modified API should have a C<symbol_version> added. This has the +form C<GUESTFS_1.X> where C<1.X> is the first stable version of +libguestfs where the new, incompatible API will appear. + +Next edit C<src/compat.c> and add the relevant C<.symver> directives +so that old libraries call a translation function that is backwards +compatible with the old ABI, and to make the new symbol the default +for newly compiled code. There are examples in this file. + +Finally check that old binaries do not crash and still return the same +data. It's a good idea to add a C<debug> call to the translation +function so you can be sure it is being called. + =head2 SOURCE CODE SUBDIRECTORIES =over 4 -- 1.7.11.4
Richard W.M. Jones
2012-Oct-30 11:57 UTC
[Libguestfs] [PATCH v2 6/7] Revert "Temporarily disable OCaml warning 23."
From: "Richard W.M. Jones" <rjones at redhat.com> --- generator/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generator/Makefile.am b/generator/Makefile.am index 276c2cf..e218ffa 100644 --- a/generator/Makefile.am +++ b/generator/Makefile.am @@ -57,7 +57,7 @@ OBJECTS = $(SOURCES_ML:.ml=.cmo) EXTRA_DIST = $(SOURCES) files-generated.txt -OCAMLCFLAGS = -warn-error CDEFLMPSUVYZ+14+15+16+17+18+19+20+21+22+24+25+30-23 +OCAMLCFLAGS = -warn-error CDEFLMPSUVYZX OCAMLCLIBS = unix.cma str.cma noinst_PROGRAM = generator -- 1.7.11.4
Richard W.M. Jones
2012-Oct-30 11:57 UTC
[Libguestfs] [PATCH v2 7/7] Add extra field(s) to guestfs_application struct.
From: "Richard W.M. Jones" <rjones at redhat.com> This breaks the ABI, but by using symbol versioning existing callers will not be affected. Also this change is source compatible, so existing code does not need to be modified. --- generator/actions.ml | 1 + generator/structs.ml | 11 ++++-- src/compat.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/inspect-apps.c | 5 +++ 4 files changed, 118 insertions(+), 3 deletions(-) diff --git a/generator/actions.ml b/generator/actions.ml index e1db3db..3b0806a 100644 --- a/generator/actions.ml +++ b/generator/actions.ml @@ -1522,6 +1522,7 @@ Please read L<guestfs(3)/INSPECTION> for more details." }; { defaults with name = "inspect_list_applications"; style = RStructList ("applications", "application"), [Device "root"], []; + symbol_version = Some "GUESTFS_1.20"; shortdesc = "get list of applications installed in the operating system"; longdesc = "\ Return the list of applications installed in the operating system. diff --git a/generator/structs.ml b/generator/structs.ml index 499f825..fd77654 100644 --- a/generator/structs.ml +++ b/generator/structs.ml @@ -213,14 +213,14 @@ let structs = [ s_camel_name = "Partition" }; (* Application. *) - { defaults with - s_name = "application"; + { s_name = "application"; s_cols = [ "app_name", FString; "app_display_name", FString; "app_epoch", FInt32; "app_version", FString; "app_release", FString; + "app_arch", FString; "app_install_path", FString; "app_trans_path", FString; "app_publisher", FString; @@ -228,8 +228,13 @@ let structs = [ "app_source_package", FString; "app_summary", FString; "app_description", FString; + "app_spare1", FString; + "app_spare2", FString; + "app_spare3", FString; + "app_spare4", FString; ]; - s_camel_name = "Application" }; + s_camel_name = "Application"; + s_symbol_version = Some "GUESTFS_1.20" }; (* ISO primary volume descriptor. *) { defaults with diff --git a/src/compat.c b/src/compat.c index 27ffd05..520400b 100644 --- a/src/compat.c +++ b/src/compat.c @@ -24,3 +24,107 @@ * instead of being compiled as a separate unit. The cpp symbols * COMPAT_ACTIONS or COMPAT_STRUCTS are defined as appropriate. */ + +#define DEBUG_COMPAT debug (g, "%s: compatibility wrapper invoked", __func__) + +/* guestfs_inspect_list_applications did not return the C<app_arch> + * field in libguestfs < 1.20. We cannot add fields to structs + * without breaking compatibility. + */ +struct guestfs_application__v1 { + char *app_name; + char *app_display_name; + int32_t app_epoch; + char *app_version; + char *app_release; + char *app_install_path; + char *app_trans_path; + char *app_publisher; + char *app_url; + char *app_source_package; + char *app_summary; + char *app_description; +}; + +struct guestfs_application_list__v1 { + uint32_t len; + struct guestfs_application__v1 *val; +}; + +#if COMPAT_ACTIONS + +/* Declare a prototype to make GCC happy. */ +GUESTFS_DLL_PUBLIC struct guestfs_application_list__v1 *guestfs_inspect_list_applications__v1 (guestfs_h *g, const char *root); + +GUESTFS_DLL_PUBLIC +struct guestfs_application_list__v1 * +guestfs_inspect_list_applications__v1 (guestfs_h *g, const char *root) +{ + struct guestfs_application_list__v1 *ret; + struct guestfs_application_list *r; + size_t i; + + DEBUG_COMPAT; + + /* Call the new function. */ + r = guestfs_inspect_list_applications (g, root); + if (!r) + return NULL; + + /* Translate the structures from the new format to the old format. */ + ret = safe_malloc (g, sizeof (struct guestfs_application_list__v1)); + ret->len = r->len; + ret->val + safe_malloc (g, sizeof (struct guestfs_application__v1) * r->len); + for (i = 0; i < r->len; ++i) { + ret->val[i].app_name = r->val[i].app_name; + ret->val[i].app_display_name = r->val[i].app_display_name; + ret->val[i].app_epoch = r->val[i].app_epoch; + ret->val[i].app_version = r->val[i].app_version; + ret->val[i].app_release = r->val[i].app_release; + ret->val[i].app_install_path = r->val[i].app_install_path; + ret->val[i].app_trans_path = r->val[i].app_trans_path; + ret->val[i].app_publisher = r->val[i].app_publisher; + ret->val[i].app_url = r->val[i].app_url; + ret->val[i].app_source_package = r->val[i].app_source_package; + ret->val[i].app_summary = r->val[i].app_summary; + ret->val[i].app_description = r->val[i].app_description; + } + free (r->val); /* Must not free the strings. */ + free (r); + + return ret; +} + +__asm__(".symver guestfs_inspect_list_applications__v1,guestfs_inspect_list_applications@"); +__asm__(".symver guestfs_inspect_list_applications__GUESTFS_1_20,guestfs_inspect_list_applications@@GUESTFS_1.20"); + +#endif /* COMPAT_ACTIONS */ + +#if COMPAT_STRUCTS + +GUESTFS_DLL_PUBLIC void guestfs_free_application__v1 (struct guestfs_application__v1 *x); + +GUESTFS_DLL_PUBLIC void +guestfs_free_application__v1 (struct guestfs_application__v1 *x) +{ + /* XXX */ + free (x); +} + +__asm__(".symver guestfs_free_application__v1,guestfs_free_application@"); +__asm__(".symver guestfs_free_application__GUESTFS_1_20,guestfs_free_application@@GUESTFS_1.20"); + +GUESTFS_DLL_PUBLIC void guestfs_free_application_list__v1 (struct guestfs_application_list__v1 *x); + +GUESTFS_DLL_PUBLIC void +guestfs_free_application_list__v1 (struct guestfs_application_list__v1 *x) +{ + /* XXX */ + free (x); +} + +__asm__(".symver guestfs_free_application_list__v1,guestfs_free_application_list@"); +__asm__(".symver guestfs_free_application_list__GUESTFS_1_20,guestfs_free_application_list@@GUESTFS_1.20"); + +#endif /* COMPAT_STRUCTS */ diff --git a/src/inspect-apps.c b/src/inspect-apps.c index 23e68e4..e5db4b3 100644 --- a/src/inspect-apps.c +++ b/src/inspect-apps.c @@ -580,6 +580,7 @@ add_application (guestfs_h *g, struct guestfs_application_list *apps, apps->val[apps->len-1].app_epoch = epoch; apps->val[apps->len-1].app_version = safe_strdup (g, version); apps->val[apps->len-1].app_release = safe_strdup (g, release); + apps->val[apps->len-1].app_arch = safe_strdup (g, ""); apps->val[apps->len-1].app_install_path = safe_strdup (g, install_path); /* XXX Translated path is not implemented yet. */ apps->val[apps->len-1].app_trans_path = safe_strdup (g, ""); @@ -591,6 +592,10 @@ add_application (guestfs_h *g, struct guestfs_application_list *apps, apps->val[apps->len-1].app_source_package = safe_strdup (g, ""); apps->val[apps->len-1].app_summary = safe_strdup (g, ""); apps->val[apps->len-1].app_description = safe_strdup (g, description); + apps->val[apps->len-1].app_spare1 = safe_strdup (g, ""); + apps->val[apps->len-1].app_spare2 = safe_strdup (g, ""); + apps->val[apps->len-1].app_spare3 = safe_strdup (g, ""); + apps->val[apps->len-1].app_spare4 = safe_strdup (g, ""); } /* Sort applications by name before returning the list. */ -- 1.7.11.4
Seemingly Similar Threads
- [PATCH v3 0/5] Add symbol versioning.
- [PATCH 1/3] src: generate code for printing contents of structs
- Re: [PATCH v8 1/3] New API: internal_filesystem_walk
- Re: [PATCH v3 1/5] generator: Added tsk_dirent struct
- [PATCH 3/3] python: Allow bindings to be compiled with different version of libguestfs (RHBZ#1262983).