mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-21 22:53:37 +00:00
v2v: Move the shell_unquote function to src/utils.c.
This function is useful outside virt-v2v so move it into the core utilities library. The function has been rewritten from OCaml into C, but it should be functionally identical.
This commit is contained in:
@@ -90,6 +90,7 @@ extern void guestfs_int_fadvise_random (int fd);
|
||||
extern void guestfs_int_fadvise_noreuse (int fd);
|
||||
//extern void guestfs_int_fadvise_dontneed (int fd);
|
||||
//extern void guestfs_int_fadvise_willneed (int fd);
|
||||
extern char *guestfs_int_shell_unquote (const char *str);
|
||||
|
||||
struct uefi_firmware {
|
||||
const char *code; /* code file (NULL = end of list) */
|
||||
|
||||
60
src/utils.c
60
src/utils.c
@@ -539,3 +539,63 @@ guestfs_int_fadvise_willneed (int fd)
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Unquote a shell-quoted string.
|
||||
*
|
||||
* Augeas passes strings to us which may be quoted, eg. if they come
|
||||
* from files in F</etc/sysconfig>. This function can do simple
|
||||
* unquoting of these strings.
|
||||
*
|
||||
* Note this function does not do variable substitution, since that is
|
||||
* impossible without knowing the file context and indeed the
|
||||
* environment under which the shell script is run. Configuration
|
||||
* files should not use complex quoting.
|
||||
*
|
||||
* C<str> is the input string from Augeas, a string that may be
|
||||
* single- or double-quoted or may not be quoted. The returned string
|
||||
* is unquoted, and must be freed by the caller. C<NULL> is returned
|
||||
* on error and C<errno> is set accordingly.
|
||||
*
|
||||
* For information on double-quoting in bash, see
|
||||
* L<https://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html>
|
||||
*/
|
||||
char *
|
||||
guestfs_int_shell_unquote (const char *str)
|
||||
{
|
||||
size_t len = strlen (str);
|
||||
char *ret;
|
||||
|
||||
if (len >= 2) {
|
||||
if (str[0] == '\'' && str[len-1] == '\'') {
|
||||
/* single quoting */
|
||||
ret = strndup (&str[1], len-2);
|
||||
if (ret == NULL)
|
||||
return NULL;
|
||||
return ret;
|
||||
}
|
||||
else if (str[0] == '"' && str[len-1] == '"') {
|
||||
/* double quoting */
|
||||
size_t i, j;
|
||||
|
||||
ret = malloc (len + 1); /* strings always get smaller */
|
||||
if (ret == NULL)
|
||||
return NULL;
|
||||
|
||||
for (i = 1, j = 0; i < len-1 /* ignore final quote */; ++i, ++j) {
|
||||
if (i < len-2 /* ignore final char before final quote */ &&
|
||||
str[i] == '\\' &&
|
||||
(str[i+1] == '$' || str[i+1] == '`' || str[i+1] == '"' ||
|
||||
str[i+1] == '\\' || str[i+1] == '\n'))
|
||||
++i;
|
||||
ret[j] = str[i];
|
||||
}
|
||||
|
||||
ret[j] = '\0';
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return strdup (str);
|
||||
}
|
||||
|
||||
@@ -516,7 +516,7 @@ let rec convert ~keep_serial_console (g : G.guestfs) inspect source rcaps =
|
||||
fun line ->
|
||||
if Str.string_match rex line 0 then (
|
||||
let path = Str.matched_group 1 line in
|
||||
let path = Linux.shell_unquote path in
|
||||
let path = Utils.shell_unquote path in
|
||||
if String.length path >= 1 && path.[0] = '/' then (
|
||||
let vboxuninstall = path ^ "/uninstall.sh" in
|
||||
Some vboxuninstall
|
||||
|
||||
44
v2v/linux.ml
44
v2v/linux.ml
@@ -178,47 +178,3 @@ let rec file_owner g inspect path =
|
||||
and is_file_owned g inspect path =
|
||||
try file_owner g inspect path; true
|
||||
with Not_found -> false
|
||||
|
||||
let rec shell_unquote str =
|
||||
let len = String.length str in
|
||||
if len >= 2 then (
|
||||
if String.is_prefix str "'" && String.is_suffix str "'" then
|
||||
String.sub str 1 (len-2)
|
||||
else if String.is_prefix str "\"" && String.is_suffix str "\"" then
|
||||
shell_unquote_double str len
|
||||
else
|
||||
str
|
||||
)
|
||||
else str
|
||||
|
||||
(* https://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html
|
||||
* but note we don't do any variable expansion etc so really we just
|
||||
* handle backslash here.
|
||||
*)
|
||||
and shell_unquote_double str len =
|
||||
let i = ref 1 and j = ref 0 in
|
||||
while !i < len-1 (* ignore final quote *) do
|
||||
if is_backslash_sequence str !i len then
|
||||
incr i;
|
||||
incr i;
|
||||
incr j
|
||||
done;
|
||||
|
||||
let outlen = !j in
|
||||
let outstr = String.create outlen in
|
||||
let i = ref 1 and j = ref 0 in
|
||||
while !i < len-1 do
|
||||
if is_backslash_sequence str !i len then
|
||||
incr i;
|
||||
outstr.[!j] <- str.[!i];
|
||||
incr i;
|
||||
incr j
|
||||
done;
|
||||
|
||||
outstr
|
||||
|
||||
and is_backslash_sequence str i len =
|
||||
i < len-2 (* ignore final character before the final quote *) &&
|
||||
str.[i] = '\\' &&
|
||||
(str.[i+1] = '$' || str.[i+1] = '`' || str.[i+1] = '"'
|
||||
|| str.[i+1] = '\\' || str.[i+1] = '\n')
|
||||
|
||||
@@ -39,11 +39,3 @@ val file_owner : Guestfs.guestfs -> Types.inspect -> string -> string
|
||||
|
||||
val is_file_owned : Guestfs.guestfs -> Types.inspect -> string -> bool
|
||||
(** Returns true if the file is owned by an installed package. *)
|
||||
|
||||
val shell_unquote : string -> string
|
||||
(** If the string looks like a shell quoted string, then attempt to
|
||||
unquote it.
|
||||
|
||||
This is just intended to deal with quoting in configuration files
|
||||
(like ones under /etc/sysconfig), and it doesn't deal with some
|
||||
situations such as $variable interpolation. *)
|
||||
|
||||
@@ -21,12 +21,20 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <caml/alloc.h>
|
||||
#include <caml/fail.h>
|
||||
#include <caml/memory.h>
|
||||
#include <caml/mlvalues.h>
|
||||
|
||||
#ifdef HAVE_CAML_UNIXSUPPORT_H
|
||||
#include <caml/unixsupport.h>
|
||||
#else
|
||||
#define Nothing ((value) 0)
|
||||
extern void unix_error (int errcode, char * cmdname, value arg) Noreturn;
|
||||
#endif
|
||||
|
||||
#include "guestfs.h"
|
||||
#include "guestfs-internal-frontend.h"
|
||||
|
||||
@@ -104,3 +112,19 @@ v2v_utils_aavmf_firmware (value unitv)
|
||||
{
|
||||
return get_firmware (guestfs_int_aavmf_firmware);
|
||||
}
|
||||
|
||||
value
|
||||
v2v_utils_shell_unquote (value strv)
|
||||
{
|
||||
CAMLparam1 (strv);
|
||||
CAMLlocal1 (retv);
|
||||
char *ret;
|
||||
|
||||
ret = guestfs_int_shell_unquote (String_val (strv));
|
||||
if (ret == NULL)
|
||||
unix_error (errno, (char *) "guestfs_int_shell_unquote", Nothing);
|
||||
|
||||
retv = caml_copy_string (ret);
|
||||
free (ret);
|
||||
CAMLreturn (retv);
|
||||
}
|
||||
|
||||
@@ -142,6 +142,8 @@ let du filename =
|
||||
| line::_ -> Int64.of_string line
|
||||
| [] -> invalid_arg filename
|
||||
|
||||
external shell_unquote : string -> string = "v2v_utils_shell_unquote"
|
||||
|
||||
(* The following functions are only exported for unit tests. *)
|
||||
module UNIT_TESTS = struct
|
||||
let ovmf_i386_firmware = ovmf_i386_firmware
|
||||
|
||||
@@ -66,6 +66,14 @@ val du : string -> int64
|
||||
This can raise either [Failure] or [Invalid_argument] in case
|
||||
of errors. *)
|
||||
|
||||
val shell_unquote : string -> string
|
||||
(** If the string looks like a shell quoted string, then attempt to
|
||||
unquote it.
|
||||
|
||||
This is just intended to deal with quoting in configuration files
|
||||
(like ones under /etc/sysconfig), and it doesn't deal with some
|
||||
situations such as $variable interpolation. *)
|
||||
|
||||
(**/**)
|
||||
|
||||
(* The following functions are only exported for unit tests. *)
|
||||
|
||||
@@ -767,16 +767,16 @@ let test_virtio_iso_path_matches_guest_os ctx =
|
||||
|
||||
let test_shell_unquote ctx =
|
||||
let printer = identity in
|
||||
assert_equal ~printer "a" (Linux.shell_unquote "a");
|
||||
assert_equal ~printer "b" (Linux.shell_unquote "'b'");
|
||||
assert_equal ~printer "c" (Linux.shell_unquote "\"c\"");
|
||||
assert_equal ~printer "dd" (Linux.shell_unquote "\"dd\"");
|
||||
assert_equal ~printer "e\\e" (Linux.shell_unquote "\"e\\\\e\"");
|
||||
assert_equal ~printer "f\\" (Linux.shell_unquote "\"f\\\\\"");
|
||||
assert_equal ~printer "\\g" (Linux.shell_unquote "\"\\\\g\"");
|
||||
assert_equal ~printer "h\\-h" (Linux.shell_unquote "\"h\\-h\"");
|
||||
assert_equal ~printer "i`" (Linux.shell_unquote "\"i\\`\"");
|
||||
assert_equal ~printer "j\"" (Linux.shell_unquote "\"j\\\"\"")
|
||||
assert_equal ~printer "a" (Utils.shell_unquote "a");
|
||||
assert_equal ~printer "b" (Utils.shell_unquote "'b'");
|
||||
assert_equal ~printer "c" (Utils.shell_unquote "\"c\"");
|
||||
assert_equal ~printer "dd" (Utils.shell_unquote "\"dd\"");
|
||||
assert_equal ~printer "e\\e" (Utils.shell_unquote "\"e\\\\e\"");
|
||||
assert_equal ~printer "f\\" (Utils.shell_unquote "\"f\\\\\"");
|
||||
assert_equal ~printer "\\g" (Utils.shell_unquote "\"\\\\g\"");
|
||||
assert_equal ~printer "h\\-h" (Utils.shell_unquote "\"h\\-h\"");
|
||||
assert_equal ~printer "i`" (Utils.shell_unquote "\"i\\`\"");
|
||||
assert_equal ~printer "j\"" (Utils.shell_unquote "\"j\\\"\"")
|
||||
|
||||
let test_find_uefi_firmware ctx =
|
||||
let rec printer = function
|
||||
@@ -815,7 +815,7 @@ let suite =
|
||||
"Utils.drive_index" >:: test_drive_index;
|
||||
"Windows_virtio.virtio_iso_path_matches_guest_os" >::
|
||||
test_virtio_iso_path_matches_guest_os;
|
||||
"Linux.shell_unquote" >:: test_shell_unquote;
|
||||
"Utils.shell_unquote" >:: test_shell_unquote;
|
||||
"Utils.find_uefi_firmware" >:: test_find_uefi_firmware;
|
||||
]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user