[PATCH] builder: add an arch field to sources read from indexes
by Pino Toscano
Add an architecture field for all the entries in each index, so we know
which architecture they are (not used right now, but will be in the
future).
The problematic part here is properly marking with the correct
architecture: since we only know the current index on libguestfs.org
contains x86_64/amd64 images, entries coming from it are marked that
way; images in all the other indexes (user-provided ones) are not known
to us, so assume they are using the same architecture as virt-builder,
hence the special "@same".
---
builder/builder.ml | 5 +++--
builder/cmdline.ml | 16 +++++++++-------
builder/index_parser.ml | 6 +++++-
builder/index_parser.mli | 3 ++-
4 files changed, 19 insertions(+), 11 deletions(-)
diff --git a/builder/builder.ml b/builder/builder.ml
index 80ccef7..d6d7570 100644
--- a/builder/builder.ml
+++ b/builder/builder.ml
@@ -42,7 +42,7 @@ let main () =
edit, firstboot, run, format, gpg, hostname, install, list_format, links,
memsize, mkdirs,
network, output, password_crypto, quiet, root_password, scrub,
- scrub_logfile, selinux_relabel, size, smp, sources, sync, timezone,
+ scrub_logfile, selinux_relabel, size, smp, sources, indexarch, sync, timezone,
update, upload, writes =
parse_cmdline () in
@@ -143,7 +143,8 @@ let main () =
let sigchecker =
Sigchecker.create ~debug ~gpg ~check_signature
~gpgkey:(Sigchecker.Fingerprint fingerprint) in
- Index_parser.get_index ~prog ~debug ~downloader ~sigchecker source
+ Index_parser.get_index ~prog ~debug ~downloader ~sigchecker
+ ~arch:indexarch source
) sources
) in
diff --git a/builder/cmdline.ml b/builder/cmdline.ml
index e9e47ae..8959429 100644
--- a/builder/cmdline.ml
+++ b/builder/cmdline.ml
@@ -31,6 +31,8 @@ open Printf
let prog = Filename.basename Sys.executable_name
let default_source = "http://libguestfs.org/download/builder/index.asc"
+(* So far images in the "default_source" index were x86_64/amd64. *)
+let default_source_architecture = "x86_64"
let parse_cmdline () =
let display_version () =
@@ -408,18 +410,18 @@ read the man page virt-builder(1).
) in
(* Check source(s) and fingerprint(s), or use environment or default. *)
- let sources =
+ let sources, indexarch =
let list_split = function "" -> [] | str -> string_nsplit "," str in
let rec repeat x = function
| 0 -> [] | 1 -> [x]
| n -> x :: repeat x (n-1)
in
- let sources =
- if sources <> [] then sources
+ let sources, indexarch =
+ if sources <> [] then sources, "@same"
else (
- try list_split (Sys.getenv "VIRT_BUILDER_SOURCE")
- with Not_found -> [ default_source ]
+ try list_split (Sys.getenv "VIRT_BUILDER_SOURCE"), "@same"
+ with Not_found -> [ default_source ], default_source_architecture
) in
let fingerprints =
if fingerprints <> [] then fingerprints
@@ -447,12 +449,12 @@ read the man page virt-builder(1).
assert (nr_sources > 0);
(* Combine the sources and fingerprints into a single list of pairs. *)
- List.combine sources fingerprints in
+ List.combine sources fingerprints, indexarch in
mode, arg,
attach, cache, check_signature, curl, debug, delete, delete_on_failure,
edit, firstboot, run, format, gpg, hostname, install, list_format, links,
memsize, mkdirs,
network, output, password_crypto, quiet, root_password, scrub,
- scrub_logfile, selinux_relabel, size, smp, sources, sync, timezone,
+ scrub_logfile, selinux_relabel, size, smp, sources, indexarch, sync, timezone,
update, upload, writes
diff --git a/builder/index_parser.ml b/builder/index_parser.ml
index 2d4a642..0b9a1b9 100644
--- a/builder/index_parser.ml
+++ b/builder/index_parser.ml
@@ -37,6 +37,7 @@ and entry = {
lvexpand : string option;
notes : (string * string) list;
hidden : bool;
+ arch : string;
sigchecker : Sigchecker.t;
}
@@ -53,6 +54,7 @@ let print_entry chan (name, { printable_name = printable_name;
expand = expand;
lvexpand = lvexpand;
notes = notes;
+ arch = arch;
hidden = hidden }) =
let fp fs = fprintf chan fs in
fp "[%s]\n" name;
@@ -91,6 +93,7 @@ let print_entry chan (name, { printable_name = printable_name;
| None -> ()
| Some lvexpand -> fp "lvexpand=%s\n" lvexpand
);
+ fp "arch=%s\n" arch;
List.iter (
fun (lang, notes) ->
match lang with
@@ -108,7 +111,7 @@ and field = string * string option * string (* key + subkey + value *)
(* Calls yyparse in the C code. *)
external parse_index : string -> sections = "virt_builder_parse_index"
-let get_index ~prog ~debug ~downloader ~sigchecker source =
+let get_index ~prog ~debug ~downloader ~sigchecker ~arch source =
let corrupt_file () =
eprintf (f_"\nThe index file downloaded from '%s' is corrupt.\nYou need to ask the supplier of this file to fix it and upload a fixed version.\n")
source;
@@ -255,6 +258,7 @@ let get_index ~prog ~debug ~downloader ~sigchecker source =
lvexpand = lvexpand;
notes = notes;
hidden = hidden;
+ arch = arch;
sigchecker = sigchecker } in
n, entry
) sections in
diff --git a/builder/index_parser.mli b/builder/index_parser.mli
index 3c679b3..4fe9a8a 100644
--- a/builder/index_parser.mli
+++ b/builder/index_parser.mli
@@ -31,8 +31,9 @@ and entry = {
lvexpand : string option;
notes : (string * string) list;
hidden : bool;
+ arch : string;
sigchecker : Sigchecker.t;
}
-val get_index : prog:string -> debug:bool -> downloader:Downloader.t -> sigchecker:Sigchecker.t -> string -> index
+val get_index : prog:string -> debug:bool -> downloader:Downloader.t -> sigchecker:Sigchecker.t -> arch:string -> string -> index
--
1.8.3.1
10 years, 8 months
[PATCH] builder: allow Sigchecker to import keys from file
by Pino Toscano
Extend Sigchecker so it allows both fingerprints (to be imported from
user's keyring, as before) and keys stored in files. To simplify this
process (and have the fingerprint always around), the key is imported
on Sigchecker.create time, instead of lazily at the first verification.
---
builder/builder.ml | 3 +-
builder/sigchecker.ml | 120 ++++++++++++++++++++++++++++---------------------
builder/sigchecker.mli | 6 ++-
3 files changed, 76 insertions(+), 53 deletions(-)
diff --git a/builder/builder.ml b/builder/builder.ml
index 7fa3cc7..80ccef7 100644
--- a/builder/builder.ml
+++ b/builder/builder.ml
@@ -141,7 +141,8 @@ let main () =
List.map (
fun (source, fingerprint) ->
let sigchecker =
- Sigchecker.create ~debug ~gpg ~fingerprint ~check_signature in
+ Sigchecker.create ~debug ~gpg ~check_signature
+ ~gpgkey:(Sigchecker.Fingerprint fingerprint) in
Index_parser.get_index ~prog ~debug ~downloader ~sigchecker source
) sources
) in
diff --git a/builder/sigchecker.ml b/builder/sigchecker.ml
index 10e342e..7459e4b 100644
--- a/builder/sigchecker.ml
+++ b/builder/sigchecker.ml
@@ -96,41 +96,97 @@ ZvXkQ3FVJwZoLmHw47vvlVpLD/4gi1SuHWieRvZ+UdDq00E348pm
-----END PGP PUBLIC KEY BLOCK-----
"
+type gpgkey_type =
+ | Fingerprint of string
+ | KeyFile of string
+
type t = {
debug : bool;
gpg : string;
fingerprint : string;
check_signature : bool;
gpghome : string;
- mutable key_imported : bool;
}
-let create ~debug ~gpg ~fingerprint ~check_signature =
- (* Create a temporary directory for gnupg. *)
- let tmpdir = Mkdtemp.mkdtemp (Filename.temp_dir_name // "vb.gpghome.XXXXXX") in
- rmdir_on_exit tmpdir;
- (* Run gpg once, so it can setup its own home directory, failing
- * if it cannot.
- *)
- let cmd = sprintf "%s --homedir %s --list-keys%s"
- gpg tmpdir (if debug then "" else " >/dev/null 2>&1") in
+(* Import the specified key file. *)
+let import_keyfile ~gpg ~gpghome ~debug keyfile =
+ let status_file = Filename.temp_file "vbstat" ".txt" in
+ unlink_on_exit status_file;
+ let cmd = sprintf "%s --homedir %s --status-file %s --import %s%s"
+ gpg gpghome (quote status_file) (quote keyfile)
+ (if debug then "" else " >/dev/null 2>&1") in
if debug then eprintf "%s\n%!" cmd;
let r = Sys.command cmd in
if r <> 0 then (
- eprintf (f_"virt-builder: error: GPG failure: could not run GPG the first time\nUse the '-v' option and look for earlier error messages.\n");
+ eprintf (f_"virt-builder: error: could not import public key\nUse the '-v' option and look for earlier error messages.\n");
exit 1
);
+ status_file
+
+let rec create ~debug ~gpg ~gpgkey ~check_signature =
+ (* Create a temporary directory for gnupg. *)
+ let tmpdir = Mkdtemp.mkdtemp (Filename.temp_dir_name // "vb.gpghome.XXXXXX") in
+ rmdir_on_exit tmpdir;
+ let fingerprint =
+ if check_signature then (
+ (* Run gpg so it can setup its own home directory, failing if it
+ * cannot.
+ *)
+ let cmd = sprintf "%s --homedir %s --list-keys%s"
+ gpg tmpdir (if debug then "" else " >/dev/null 2>&1") in
+ if debug then eprintf "%s\n%!" cmd;
+ let r = Sys.command cmd in
+ if r <> 0 then (
+ eprintf (f_"virt-builder: error: GPG failure: could not run GPG the first time\nUse the '-v' option and look for earlier error messages.\n");
+ exit 1
+ );
+ match gpgkey with
+ | KeyFile kf ->
+ let status_file = import_keyfile gpg tmpdir debug kf in
+ let status = read_whole_file status_file in
+ let status = string_nsplit "\n" status in
+ let fingerprint = ref "" in
+ List.iter (
+ fun line ->
+ let line = string_nsplit " " line in
+ match line with
+ | "[GNUPG:]" :: "IMPORT_OK" :: _ :: fp :: _ -> fingerprint := fp
+ | _ -> ()
+ ) status;
+ !fingerprint
+ | Fingerprint fp when equal_fingerprints default_fingerprint fp ->
+ let filename, chan = Filename.open_temp_file "vbpubkey" ".asc" in
+ unlink_on_exit filename;
+ output_string chan default_pubkey;
+ close_out chan;
+ ignore (import_keyfile gpg tmpdir debug filename);
+ fp
+ | Fingerprint fp ->
+ let filename = Filename.temp_file "vbpubkey" ".asc" in
+ unlink_on_exit filename;
+ let cmd = sprintf "%s --yes --armor --output %s --export %s%s"
+ gpg (quote filename) (quote fp)
+ (if debug then "" else " >/dev/null 2>&1") in
+ if debug then eprintf "%s\n%!" cmd;
+ let r = Sys.command cmd in
+ if r <> 0 then (
+ eprintf (f_"virt-builder: error: could not export public key\nUse the '-v' option and look for earlier error messages.\n");
+ exit 1
+ );
+ ignore (import_keyfile gpg tmpdir debug filename);
+ fp
+ ) else
+ "" in
{
debug = debug;
gpg = gpg;
fingerprint = fingerprint;
check_signature = check_signature;
gpghome = tmpdir;
- key_imported = false;
}
(* Compare two strings of hex digits ignoring whitespace and case. *)
-let rec equal_fingerprints fp1 fp2 =
+and equal_fingerprints fp1 fp2 =
let len1 = String.length fp1 and len2 = String.length fp2 in
let rec loop i j =
if i = len1 && j = len2 then true (* match! *)
@@ -171,8 +227,6 @@ and verify_detached t filename sigfile =
)
and do_verify t args =
- import_key t;
-
let status_file = Filename.temp_file "vbstat" ".txt" in
unlink_on_exit status_file;
let cmd =
@@ -206,42 +260,6 @@ and do_verify t args =
exit 1
)
-(* Import the requested public key. *)
-and import_key t =
- if not t.key_imported then (
- let keyfile = ref "" in
- if equal_fingerprints default_fingerprint t.fingerprint then (
- let filename, chan = Filename.open_temp_file "vbpubkey" ".asc" in
- unlink_on_exit filename;
- output_string chan default_pubkey;
- close_out chan;
- keyfile := filename
- ) else (
- let filename = Filename.temp_file "vbpubkey" ".asc" in
- unlink_on_exit filename;
- let cmd = sprintf "%s --yes --armor --output %s --export %s%s"
- t.gpg (quote filename) (quote t.fingerprint)
- (if t.debug then "" else " >/dev/null 2>&1") in
- if t.debug then eprintf "%s\n%!" cmd;
- let r = Sys.command cmd in
- if r <> 0 then (
- eprintf (f_"virt-builder: error: could not export public key\nUse the '-v' option and look for earlier error messages.\n");
- exit 1
- );
- keyfile := filename
- );
-
- let cmd = sprintf "%s --homedir %s --import %s%s"
- t.gpg t.gpghome (quote !keyfile)
- (if t.debug then "" else " >/dev/null 2>&1") in
- let r = Sys.command cmd in
- if r <> 0 then (
- eprintf (f_"virt-builder: error: could not import public key\nUse the '-v' option and look for earlier error messages.\n");
- exit 1
- );
- t.key_imported <- true
- )
-
type csum_t = SHA512 of string
let verify_checksum t (SHA512 csum) filename =
diff --git a/builder/sigchecker.mli b/builder/sigchecker.mli
index cdd800e..f4e817e 100644
--- a/builder/sigchecker.mli
+++ b/builder/sigchecker.mli
@@ -20,7 +20,11 @@ val default_fingerprint : string
type t
-val create : debug:bool -> gpg:string -> fingerprint:string -> check_signature:bool -> t
+type gpgkey_type =
+ | Fingerprint of string
+ | KeyFile of string
+
+val create : debug:bool -> gpg:string -> gpgkey:gpgkey_type -> check_signature:bool -> t
val verify : t -> string -> unit
(** Verify the file is signed (if check_signature is true). *)
--
1.8.3.1
10 years, 8 months
[PATCH 1/2] mllib: add an hook to cleanup directories on exit
by Pino Toscano
Much similar to unlink_on_exit, but recursively cleaning directories.
---
mllib/common_utils.ml | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/mllib/common_utils.ml b/mllib/common_utils.ml
index 3943417..f49ede6 100644
--- a/mllib/common_utils.ml
+++ b/mllib/common_utils.ml
@@ -386,6 +386,35 @@ let unlink_on_exit =
registered_handlers := true
)
+(* Remove a temporary directory on exit. *)
+let rmdir_on_exit =
+ let dirs = ref [] in
+ let registered_handlers = ref false in
+
+ let rec unlink_dirs () =
+ let rec recursive_rmdir fn =
+ if Sys.is_directory fn then (
+ let names = Array.map (fun d -> fn // d) (Sys.readdir fn) in
+ Array.iter recursive_rmdir names;
+ Unix.rmdir fn
+ ) else
+ Unix.unlink fn
+ in
+ List.iter (
+ fun dir -> try recursive_rmdir dir with _ -> ()
+ ) !dirs
+ and register_handlers () =
+ (* Remove on exit. *)
+ at_exit unlink_dirs
+ in
+
+ fun dir ->
+ dirs := dir :: !dirs;
+ if not !registered_handlers then (
+ register_handlers ();
+ registered_handlers := true
+ )
+
(* Using the libguestfs API, recursively remove only files from the
* given directory. Useful for cleaning /var/cache etc in sysprep
* without removing the actual directory structure. Also if 'dir' is
--
1.8.3.1
10 years, 8 months
[PATCH 1/2] mllib: add an hook to cleanup directories on exit
by Pino Toscano
Much similar to unlink_on_exit, but recursively cleaning directories.
---
mllib/common_utils.ml | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/mllib/common_utils.ml b/mllib/common_utils.ml
index 3943417..de3bd40 100644
--- a/mllib/common_utils.ml
+++ b/mllib/common_utils.ml
@@ -386,6 +386,29 @@ let unlink_on_exit =
registered_handlers := true
)
+(* Remove a temporary directory on exit. *)
+let rmdir_on_exit =
+ let dirs = ref [] in
+ let registered_handlers = ref false in
+
+ let rec rmdirs () =
+ List.iter (
+ fun dir ->
+ let cmd = sprintf "rm -rf %s" (Filename.quote dir) in
+ ignore (Sys.command cmd)
+ ) !dirs
+ and register_handlers () =
+ (* Remove on exit. *)
+ at_exit rmdirs
+ in
+
+ fun dir ->
+ dirs := dir :: !dirs;
+ if not !registered_handlers then (
+ register_handlers ();
+ registered_handlers := true
+ )
+
(* Using the libguestfs API, recursively remove only files from the
* given directory. Useful for cleaning /var/cache etc in sysprep
* without removing the actual directory structure. Also if 'dir' is
--
1.8.3.1
10 years, 8 months
Re: [Libguestfs] [PATCH 1/2] mllib: add an hook to cleanup directories on exit
by Richard W.M. Jones
[Adding libguestfs CC this time]
On Thu, Feb 20, 2014 at 03:04:19PM +0100, Pino Toscano wrote:
> Much similar to unlink_on_exit, but recursively cleaning directories.
> ---
> mllib/common_utils.ml | 35 +++++++++++++++++++++++++++++++++++
> 1 file changed, 35 insertions(+)
>
> diff --git a/mllib/common_utils.ml b/mllib/common_utils.ml
> index 3943417..d02a2d3 100644
> --- a/mllib/common_utils.ml
> +++ b/mllib/common_utils.ml
> @@ -386,6 +386,41 @@ let unlink_on_exit =
> registered_handlers := true
> )
>
> +(* Remove a temporary directory on exit. *)
> +let rmdir_on_exit =
> + let dirs = ref [] in
> + let registered_handlers = ref false in
> +
> + let rec unlink_dirs () =
> + let rec recursive_rmdir fn =
> + match (Unix.lstat fn).Unix.st_kind with
> + | Unix.S_DIR ->
> + let names = Array.map (fun d -> fn // d) (Sys.readdir fn) in
> + Array.iter recursive_rmdir names;
> + Unix.rmdir fn
> + | Unix.S_REG
> + | Unix.S_CHR
> + | Unix.S_BLK
> + | Unix.S_LNK
> + | Unix.S_FIFO
> + | Unix.S_SOCK ->
> + Unix.unlink fn
> + in
> + List.iter (
> + fun dir -> try recursive_rmdir dir with _ -> ()
> + ) !dirs
> + and register_handlers () =
> + (* Remove on exit. *)
> + at_exit unlink_dirs
> + in
> +
> + fun dir ->
> + dirs := dir :: !dirs;
> + if not !registered_handlers then (
> + register_handlers ();
> + registered_handlers := true
> + )
> +
This is really very complicated compared to:
let cmd = sprintf "rm -rf %s" (Filename.quote tmpdir) in
ignore (Sys.command cmd));
It's also not likely to be as well debugged as coreutils, which has
been working on multiple platforms for 25 years or so.
Rich.
--
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming blog: http://rwmj.wordpress.com
Fedora now supports 80 OCaml packages (the OPEN alternative to F#)
10 years, 8 months
[PATCH] builder: accept also '_' in group names
by Pino Toscano
---
builder/index-scan.l | 2 +-
builder/index-validate.c | 8 ++++++++
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/builder/index-scan.l b/builder/index-scan.l
index b120590..832ea51 100644
--- a/builder/index-scan.l
+++ b/builder/index-scan.l
@@ -52,7 +52,7 @@ extern void yyerror (const char *);
^\n { return EMPTY_LINE; }
/* [...] marks beginning of a section. */
-^"["[-A-Za-z0-9.]+"]"\n {
+^"["[-A-Za-z0-9._]+"]"\n {
yylval.str = strndup (yytext+1, yyleng-3);
return SECTION_HEADER;
}
diff --git a/builder/index-validate.c b/builder/index-validate.c
index 26abaa8..7f02ffb 100644
--- a/builder/index-validate.c
+++ b/builder/index-validate.c
@@ -128,6 +128,14 @@ main (int argc, char *argv[])
int seen_sig = 0;
struct field *fields;
+ if (compat_1_24_0) {
+ if (strchr (sections->name, '_')) {
+ fprintf (stderr, _("%s: %s: section [%s] has invalid characters which will not work with virt-builder 1.24.0\n"),
+ program_name, input, sections->name);
+ exit (EXIT_FAILURE);
+ }
+ }
+
for (fields = sections->fields; fields != NULL; fields = fields->next) {
if (compat_1_24_0) {
if (strchr (fields->key, '[') ||
--
1.8.3.1
10 years, 8 months
Openstack, libguestfs, Ubuntu 12.04 (precise)
by Richard W.M. Jones
Clark, thanks for the report about Openstack + the testing you did.
As my IRC proxy died (quite literally) today it's easier for me to
continue this on email. I have CC'd this email to the libguestfs
mailing list, which does not require subscription, however the first
time you send an email it will require me to manually approve the
message.
I would suggest to debug this further, the best thing is to run the
following command on the Ubuntu host, capturing all the output.
libguestfs-test-tool
Nova runs libguestfs as root (which is a bad thing, we prefer never to
run anything as root). So you could try it both as root and as a
non-root ordinary user.
Another test would be actual file injection:
guestfish -i -a somedisk.img
><fs> edit /some/file
Use -v -x to get a lot of extra debugging from guestfish.
Rich.
--
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
virt-p2v converts physical machines to virtual machines. Boot with a
live CD or over the network (PXE) and turn machines into KVM guests.
http://libguestfs.org/virt-v2v
10 years, 8 months
[PATCH] builder: move the XDG path handling in an own file
by Pino Toscano
Just code motion and renaming, no actual behaviour changes.
---
builder/Makefile.am | 2 ++
builder/cmdline.ml | 9 +--------
builder/paths.ml | 26 ++++++++++++++++++++++++++
po/POTFILES-ml | 1 +
4 files changed, 30 insertions(+), 8 deletions(-)
create mode 100644 builder/paths.ml
diff --git a/builder/Makefile.am b/builder/Makefile.am
index 6313bad..23336c0 100644
--- a/builder/Makefile.am
+++ b/builder/Makefile.am
@@ -48,6 +48,7 @@ SOURCES = \
index-parser-c.c \
list_entries.mli \
list_entries.ml \
+ paths.ml \
pxzcat.ml \
pxzcat.mli \
pxzcat-c.c \
@@ -91,6 +92,7 @@ OBJECTS = \
pxzcat.cmx \
setlocale-c.o \
setlocale.cmx \
+ paths.cmx \
get_kernel.cmx \
downloader.cmx \
sigchecker.cmx \
diff --git a/builder/cmdline.ml b/builder/cmdline.ml
index a6cb6c5..e9e47ae 100644
--- a/builder/cmdline.ml
+++ b/builder/cmdline.ml
@@ -30,13 +30,6 @@ open Printf
let prog = Filename.basename Sys.executable_name
-let default_cachedir =
- try Some (Sys.getenv "XDG_CACHE_HOME" // "virt-builder")
- with Not_found ->
- try Some (Sys.getenv "HOME" // ".cache" // "virt-builder")
- with Not_found ->
- None (* no cache directory *)
-
let default_source = "http://libguestfs.org/download/builder/index.asc"
let parse_cmdline () =
@@ -61,7 +54,7 @@ let parse_cmdline () =
in
let attach_disk s = attach := (!attach_format, s) :: !attach in
- let cache = ref default_cachedir in
+ let cache = ref Paths.xdg_cache_home in
let set_cache arg = cache := Some arg in
let no_cache () = cache := None in
diff --git a/builder/paths.ml b/builder/paths.ml
new file mode 100644
index 0000000..66e8922
--- /dev/null
+++ b/builder/paths.ml
@@ -0,0 +1,26 @@
+(* virt-builder
+ * Copyright (C) 2014 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *)
+
+open Common_utils
+
+let xdg_cache_home =
+ try Some (Sys.getenv "XDG_CACHE_HOME" // "virt-builder")
+ with Not_found ->
+ try Some (Sys.getenv "HOME" // ".cache" // "virt-builder")
+ with Not_found ->
+ None (* no cache directory *)
diff --git a/po/POTFILES-ml b/po/POTFILES-ml
index 7937728..301fe81 100644
--- a/po/POTFILES-ml
+++ b/po/POTFILES-ml
@@ -4,6 +4,7 @@ builder/downloader.ml
builder/get_kernel.ml
builder/index_parser.ml
builder/list_entries.ml
+builder/paths.ml
builder/pxzcat.ml
builder/setlocale.ml
builder/sigchecker.ml
--
1.8.3.1
10 years, 8 months
[PATCH] fish: use XDG paths for the config file
by Pino Toscano
Read the configuration file from XDG paths for both global and
user-local locations, keeping the old paths as fallback.
---
fish/config.c | 68 ++++++++++++++++++++++++++++++++++++++----
fish/guestfish.pod | 9 ++++--
fish/libguestfs-tools.conf.pod | 52 ++++++++++++++++++++++++++------
fuse/guestmount.pod | 4 +++
rescue/virt-rescue.pod | 4 +++
5 files changed, 119 insertions(+), 18 deletions(-)
diff --git a/fish/config.c b/fish/config.c
index 9e5da87..7d319ad 100644
--- a/fish/config.c
+++ b/fish/config.c
@@ -34,8 +34,9 @@
#ifdef HAVE_LIBCONFIG
+#define GLOBAL_CONFIG_FILENAME "libguestfs-tools.conf"
static const char *home_filename = /* $HOME/ */ ".libguestfs-tools.rc";
-static const char *etc_filename = "/etc/libguestfs-tools.conf";
+static const char *etc_filename = "/etc/" GLOBAL_CONFIG_FILENAME;
/* Note that parse_config is called very early, before command line
* parsing, before the verbose flag has been set, even before the
@@ -86,17 +87,72 @@ parse_config (void)
/* Try the global configuration first. */
read_config_from_file (etc_filename);
+ {
+ /* Then read the configuration from XDG system paths. */
+ const char *xdg_env, *var;
+ CLEANUP_FREE_STRING_LIST char **xdg_config_dirs = NULL;
+ size_t xdg_config_dirs_count;
+
+ xdg_env = getenv ("XDG_CONFIG_DIRS");
+ var = xdg_env != NULL && xdg_env[0] != 0 ? xdg_env : "/etc/xdg";
+ xdg_config_dirs = guestfs___split_string (':', var);
+ xdg_config_dirs_count = guestfs___count_strings (xdg_config_dirs);
+ for (size_t i = xdg_config_dirs_count; i > 0; --i) {
+ CLEANUP_FREE char *path = NULL;
+ const char *dir = xdg_config_dirs[i - 1];
+
+ if (asprintf (&path, "%s/libguestfs/" GLOBAL_CONFIG_FILENAME, dir) == -1) {
+ perror ("asprintf");
+ exit (EXIT_FAILURE);
+ }
+
+ read_config_from_file (path);
+ }
+ }
+
/* Read the configuration from $HOME, to override system settings. */
home = getenv ("HOME");
if (home != NULL) {
- CLEANUP_FREE char *path = NULL;
+ {
+ /* Old-style configuration file first. */
+ CLEANUP_FREE char *path = NULL;
- if (asprintf (&path, "%s/%s", home, home_filename) == -1) {
- perror ("asprintf");
- exit (EXIT_FAILURE);
+ if (asprintf (&path, "%s/%s", home, home_filename) == -1) {
+ perror ("asprintf");
+ exit (EXIT_FAILURE);
+ }
+
+ read_config_from_file (path);
}
- read_config_from_file (path);
+ {
+ /* Then, XDG_CONFIG_HOME path. */
+ CLEANUP_FREE char *path = NULL;
+ CLEANUP_FREE char *home_copy = strdup (home);
+ const char *xdg_env;
+
+ if (home_copy == NULL) {
+ perror ("strdup");
+ exit (EXIT_FAILURE);
+ }
+
+ xdg_env = getenv ("XDG_CONFIG_HOME");
+ if (xdg_env == NULL) {
+ if (asprintf (&path, "%s/.config/libguestfs/" GLOBAL_CONFIG_FILENAME,
+ home_copy) == -1) {
+ perror ("asprintf");
+ exit (EXIT_FAILURE);
+ }
+ } else {
+ if (asprintf (&path, "%s/libguestfs/" GLOBAL_CONFIG_FILENAME,
+ xdg_env) == -1) {
+ perror ("asprintf");
+ exit (EXIT_FAILURE);
+ }
+ }
+
+ read_config_from_file (path);
+ }
}
}
diff --git a/fish/guestfish.pod b/fish/guestfish.pod
index bdfe64b..31add50 100644
--- a/fish/guestfish.pod
+++ b/fish/guestfish.pod
@@ -516,9 +516,8 @@ then you will cause irreversible disk corruption.
In a future libguestfs we intend to change the default the other way.
Disk images will be opened read-only. You will have to either specify
I<guestfish --rw>, I<guestmount --rw>, I<virt-rescue --rw>, or change
-the configuration file C</etc/libguestfs-tools.conf> in order to get
-write access for disk images specified by those other command line
-options.
+the configuration file in order to get write access for disk images
+specified by those other command line options.
This version of guestfish, guestmount and virt-rescue has a I<--rw>
option which does nothing (it is already the default). However it is
@@ -1541,8 +1540,12 @@ See L</LIBGUESTFS_CACHEDIR>, L</LIBGUESTFS_TMPDIR>.
=over 4
+=item $XDG_CONFIG_HOME/libguestfs/libguestfs-tools.conf
+
=item $HOME/.libguestfs-tools.rc
+=item $XDG_CONFIG_DIRS/libguestfs/libguestfs-tools.conf
+
=item /etc/libguestfs-tools.conf
This configuration file controls the default read-only or read-write
diff --git a/fish/libguestfs-tools.conf.pod b/fish/libguestfs-tools.conf.pod
index 771eb50..bba00e3 100644
--- a/fish/libguestfs-tools.conf.pod
+++ b/fish/libguestfs-tools.conf.pod
@@ -2,18 +2,22 @@
=head1 NAME
-/etc/libguestfs-tools.conf - configuration file for guestfish, guestmount, virt-rescue
+libguestfs-tools.conf - configuration file for guestfish, guestmount, virt-rescue
=head1 SYNOPSIS
/etc/libguestfs-tools.conf
+ $XDG_CONFIG_DIRS/libguestfs/libguestfs-tools.conf
+
$HOME/.libguestfs-tools.rc
+ $XDG_CONFIG_HOME/libguestfs/libguestfs-tools.conf
+
=head1 DESCRIPTION
-C</etc/libguestfs-tools.conf> or C<$HOME/.libguestfs-tools.rc> changes
-the defaults for the following programs only:
+C<libguestfs-tools.conf> (or C<$HOME/.libguestfs-tools.rc>) changes the
+defaults for the following programs only:
=over 4
@@ -45,21 +49,51 @@ See also L<guestfish(1)/OPENING DISKS FOR READ AND WRITE>.
Note that B<the semicolon is required>.
-C</etc/libguestfs-tools.conf> is the global configuration file for all
-of the above programs. Local users can override the global
-configuration by copying this file into C<.libguestfs-tools.rc> in
-their home directory and modifying it accordingly.
-
This file is parsed by the libconfig library. For more information
about the format, see:
L<http://www.hyperrealm.com/libconfig/libconfig_manual.html>
+=head1 FILE LOCATION
+
+The order of the configuration files being read is, by importance:
+
+=over 4
+
+=item *
+
+$XDG_CONFIG_HOME/libguestfs/libguestfs-tools.conf (C<$XDG_CONFIG_HOME> is
+C<$HOME/.config> if not set).
+
+=item *
+
+$HOME/.libguestfs-tools.rc
+
+=item *
+
+$XDG_CONFIG_DIRS/libguestfs/libguestfs-tools.conf (where C<$XDG_CONFIG_DIRS>
+means any of the directories in that environment variable, or just C</etc/xdg>
+if not set)
+
+=item *
+
+/etc/libguestfs-tools.conf
+
+=back
+
+This means local users can override the system configuration by copying
+the configuration file (or creating it anew) into
+C<$XDG_CONFIG_HOME/libguestfs/libguestfs-tools.conf>.
+
+C</etc/libguestfs-tools.conf> and C<$HOME/.libguestfs-tools.rc> are the old
+non-XDG paths which are read for compatibility.
+
=head1 SEE ALSO
L<guestfish(1)/OPENING DISKS FOR READ AND WRITE>,
L<guestmount(1)>,
L<virt-rescue(1)>,
-L<http://libguestfs.org/>.
+L<http://libguestfs.org/>,
+L<http://standards.freedesktop.org/basedir-spec/latest/>.
=head1 AUTHORS
diff --git a/fuse/guestmount.pod b/fuse/guestmount.pod
index 9586a76..6ebf51f 100644
--- a/fuse/guestmount.pod
+++ b/fuse/guestmount.pod
@@ -387,8 +387,12 @@ This also stops the daemon from forking into the background
=over 4
+=item $XDG_CONFIG_HOME/libguestfs/libguestfs-tools.conf
+
=item $HOME/.libguestfs-tools.rc
+=item $XDG_CONFIG_DIRS/libguestfs/libguestfs-tools.conf
+
=item /etc/libguestfs-tools.conf
This configuration file controls the default read-only or read-write
diff --git a/rescue/virt-rescue.pod b/rescue/virt-rescue.pod
index 9a55d48..c295bda 100644
--- a/rescue/virt-rescue.pod
+++ b/rescue/virt-rescue.pod
@@ -403,8 +403,12 @@ manual page L<sh(1)> for details.
=over 4
+=item $XDG_CONFIG_HOME/libguestfs/libguestfs-tools.conf
+
=item $HOME/.libguestfs-tools.rc
+=item $XDG_CONFIG_DIRS/libguestfs/libguestfs-tools.conf
+
=item /etc/libguestfs-tools.conf
This configuration file controls the default read-only or read-write
--
1.8.3.1
10 years, 8 months
[PATCH 1/2] fish: small refactor of config reading code
by Pino Toscano
Even though so far there is just one possible setting to read, isolate
in an own function the code to parse a configuration file and read the
settings out of it.
Now there's a new config_t handle used every time, but since config_read
would reset an handle completely, there is no behaviour change.
---
fish/config.c | 88 +++++++++++++++++++++--------------------------------------
1 file changed, 31 insertions(+), 57 deletions(-)
diff --git a/fish/config.c b/fish/config.c
index e9f437a..02d850b 100644
--- a/fish/config.c
+++ b/fish/config.c
@@ -42,87 +42,61 @@ static const char *etc_filename = "/etc/libguestfs-tools.conf";
* global handle 'g' is opened.
*/
-void
-parse_config (void)
+static void
+read_config_from_file (const char *filename)
{
- const char *home;
FILE *fp;
- config_t conf;
-
- config_init (&conf);
-
- /* Try $HOME first. */
- home = getenv ("HOME");
- if (home != NULL) {
- CLEANUP_FREE char *path = NULL;
- if (asprintf (&path, "%s/%s", home, home_filename) == -1) {
- perror ("asprintf");
- exit (EXIT_FAILURE);
- }
+ fp = fopen (filename, "r");
+ if (fp != NULL) {
+ config_t conf;
- fp = fopen (path, "r");
- if (fp != NULL) {
- /*
- if (verbose)
- fprintf (stderr, "%s: reading configuration from %s\n",
- program_name, path);
- */
-
- if (config_read (&conf, fp) == CONFIG_FALSE) {
- fprintf (stderr,
- _("%s: %s: line %d: error parsing configuration file: %s\n"),
- program_name, path, config_error_line (&conf),
- config_error_text (&conf));
- exit (EXIT_FAILURE);
- }
-
- if (fclose (fp) == -1) {
- perror (path);
- exit (EXIT_FAILURE);
- }
-
- /* Notes:
- *
- * (1) It's not obvious from the documentation, that config_read
- * completely resets the 'conf' structure. This means we cannot
- * call config_read twice on the two possible configuration
- * files, but instead have to copy out settings into our
- * variables between calls.
- *
- * (2) If the next call fails then 'read_only' variable is not
- * updated. Failure could happen just because the setting is
- * missing from the configuration file, so we ignore it here.
- */
- config_lookup_bool (&conf, "read_only", &read_only);
- }
- }
+ config_init (&conf);
- fp = fopen (etc_filename, "r");
- if (fp != NULL) {
/*
if (verbose)
fprintf (stderr, "%s: reading configuration from %s\n",
- program_name, etc_filename);
+ program_name, filename);
*/
if (config_read (&conf, fp) == CONFIG_FALSE) {
fprintf (stderr,
_("%s: %s: line %d: error parsing configuration file: %s\n"),
- program_name, etc_filename, config_error_line (&conf),
+ program_name, filename, config_error_line (&conf),
config_error_text (&conf));
exit (EXIT_FAILURE);
}
if (fclose (fp) == -1) {
- perror (etc_filename);
+ perror (filename);
exit (EXIT_FAILURE);
}
config_lookup_bool (&conf, "read_only", &read_only);
+
+ config_destroy (&conf);
+ }
+}
+
+void
+parse_config (void)
+{
+ const char *home;
+
+ /* Try $HOME first. */
+ home = getenv ("HOME");
+ if (home != NULL) {
+ CLEANUP_FREE char *path = NULL;
+
+ if (asprintf (&path, "%s/%s", home, home_filename) == -1) {
+ perror ("asprintf");
+ exit (EXIT_FAILURE);
+ }
+
+ read_config_from_file (path);
}
- config_destroy (&conf);
+ read_config_from_file (etc_filename);
}
#else /* !HAVE_LIBCONFIG */
--
1.8.3.1
10 years, 8 months