Richard W.M. Jones
2012-Oct-30 12:34 UTC
[Libguestfs] [PATCH v3 0/5] Add symbol versioning.
This is a simpler patch series to add symbol versioning. I have pushed patches 1-3 upstream. Rich.
Richard W.M. Jones
2012-Oct-30 12:34 UTC
[Libguestfs] [PATCH v3 1/5] 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 12:34 UTC
[Libguestfs] [PATCH v3 2/5] 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 12:34 UTC
[Libguestfs] [PATCH v3 3/5] 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.
---
generator/c.ml | 8 +--
generator/csharp.ml | 2 +-
generator/erlang.ml | 2 +-
generator/fish.ml | 2 +-
generator/gobject.ml | 2 +-
generator/java.ml | 13 ++--
generator/main.ml | 6 +-
generator/ocaml.ml | 4 +-
generator/python.ml | 2 +-
generator/structs.ml | 166 ++++++++++++++++++++++++++++++--------------------
generator/structs.mli | 19 ++++--
generator/xdr.ml | 3 +-
12 files changed, 137 insertions(+), 92 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..a8eea1a 100644
--- a/generator/java.ml
+++ b/generator/java.ml
@@ -873,12 +873,17 @@ and generate_java_struct_list_return typ jtyp cols and
generate_java_makefile_inc () generate_header HashStyle GPLv2plus;
+ let jtyps = List.map (fun { s_camel_name = jtyp } -> jtyp) structs in
+ let jtyps = List.sort compare jtyps in
+
pr "java_built_sources = \\\n";
List.iter (
- fun (typ, jtyp) ->
- pr "\tcom/redhat/et/libguestfs/%s.java \\\n" jtyp;
- ) camel_structs;
+ pr "\tcom/redhat/et/libguestfs/%s.java \\\n"
+ ) jtyps;
pr "\tcom/redhat/et/libguestfs/GuestFS.java\n"
and generate_java_gitignore () - List.iter (fun (_, jtyp) -> pr
"%s.java\n" jtyp) camel_structs
+ let jtyps = List.map (fun { s_camel_name = jtyp } -> jtyp) structs in
+ let jtyps = List.sort compare jtyps in
+
+ List.iter (pr "%s.java\n") jtyps
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..4dcb2c9 100644
--- a/generator/structs.ml
+++ b/generator/structs.ml
@@ -22,6 +22,12 @@ open Types
open Utils
type cols = (string * field) list
+type struc = {
+ s_name : string;
+ s_cols : cols;
+ s_camel_name : string;
+ s_unused : unit; (* Silences warning 23 when using 'defaults with
...' *)
+}
(* Because we generate extra parsing code for LVM command line tools,
* we have to pull out the LVM columns separately here.
@@ -88,6 +94,8 @@ let lvm_lv_cols = [
"modules", FString;
]
+let defaults = { s_name = ""; s_cols = []; s_camel_name =
""; s_unused = () }
+
(* Names and fields in all structures (in RStruct and RStructList)
* that we support.
*)
@@ -95,21 +103,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 +139,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 +155,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 +227,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 +251,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 +303,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..f0c2ba6 100644
--- a/generator/structs.mli
+++ b/generator/structs.mli
@@ -23,12 +23,16 @@
type cols = (string * Types.field) list
(** List of structure fields (called "columns"). *)
-val structs : (string * cols) list
+type struc = {
+ s_name : string; (** Regular name. *)
+ s_cols : cols; (** Columns. *)
+ s_camel_name : string; (** Camel-cased name. *)
+ s_unused : unit;
+}
+
+val structs : struc list
(** List of structures. *)
-val camel_structs : (string * string) list
-(** For bindings which want camel case struct names *)
-
val lvm_pv_cols : cols
val lvm_vg_cols : cols
val lvm_lv_cols : cols
@@ -36,8 +40,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
--
1.7.11.4
Richard W.M. Jones
2012-Oct-30 12:34 UTC
[Libguestfs] [PATCH v3 4/5] generator: Add symbol versioning.
From: "Richard W.M. Jones" <rjones at redhat.com>
---
generator/actions.ml | 1 +
generator/c.ml | 132 +++++++++++++++++++++++++++++++++++++++++++++-----
generator/checks.ml | 18 +++++++
generator/structs.ml | 4 +-
generator/structs.mli | 2 +
generator/types.ml | 2 +
po/POTFILES | 1 +
src/Makefile.am | 4 ++
src/compat.c | 26 ++++++++++
src/guestfs.pod | 26 ++++++++++
10 files changed, 204 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..9ecb2a3 100644
--- a/generator/checks.ml
+++ b/generator/checks.ml
@@ -20,6 +20,7 @@
open Types
open Utils
+open Structs
open Actions
(* Check function names etc. for consistency. *)
@@ -243,6 +244,23 @@ let () | { blocking = true } -> ()
) daemon_functions;
+ (* Check symbol version string is sane. *)
+ let symbol_version_is_sane name = function
+ | None -> ()
+ | 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
+ in
+ List.iter (
+ fun { name = name; symbol_version = symbol_version } ->
+ symbol_version_is_sane name symbol_version
+ ) all_functions;
+ List.iter (
+ fun { s_name = name; s_symbol_version = symbol_version } ->
+ symbol_version_is_sane name symbol_version
+ ) structs;
+
(* 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 4dcb2c9..e378224 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;
s_unused : unit; (* Silences warning 23 when using 'defaults with
...' *)
}
@@ -94,7 +95,8 @@ let lvm_lv_cols = [
"modules", FString;
]
-let defaults = { s_name = ""; s_cols = []; s_camel_name =
""; s_unused = () }
+let defaults = { s_name = ""; s_cols = []; s_camel_name =
"";
+ s_symbol_version = None; s_unused = () }
(* Names and fields in all structures (in RStruct and RStructList)
* that we support.
diff --git a/generator/structs.mli b/generator/structs.mli
index f0c2ba6..38bee6a 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 *)
s_unused : unit;
}
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..e6e6c83 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,9 @@ libguestfs_la_SOURCES = \
proto.c \
libguestfs.syms
+# These files #include "compat.c". Express that dependency.
+actions.c free-structs.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 12:34 UTC
[Libguestfs] [PATCH v3 5/5] 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 | 8 +++-
src/compat.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++
src/inspect-apps.c | 5 +++
4 files changed, 117 insertions(+), 1 deletion(-)
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 e378224..a75388c 100644
--- a/generator/structs.ml
+++ b/generator/structs.ml
@@ -222,6 +222,7 @@ let structs = [
"app_epoch", FInt32;
"app_version", FString;
"app_release", FString;
+ "app_arch", FString;
"app_install_path", FString;
"app_trans_path", FString;
"app_publisher", FString;
@@ -229,8 +230,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 v2 0/7] Add symbol versioning (now working).
- Re: [PATCH v3 1/5] generator: Added tsk_dirent struct
- Re: [PATCH v8 1/3] New API: internal_filesystem_walk
- [PATCH 3/3] python: Allow bindings to be compiled with different version of libguestfs (RHBZ#1262983).
- [PATCH 1/3] src: generate code for printing contents of structs