diff --git a/.gitignore b/.gitignore index 79ef7c017..bb78b2789 100644 --- a/.gitignore +++ b/.gitignore @@ -431,10 +431,12 @@ Makefile.in /ocaml/t/*.bc /ocaml/t/*.opt /p2v/about-authors.c +/p2v/config.c /p2v/dependencies.archlinux /p2v/dependencies.debian /p2v/dependencies.redhat /p2v/dependencies.suse +/p2v/p2v-config.h /p2v/stamp-test-virt-p2v-pxe-data-files /p2v/stamp-test-virt-p2v-pxe-hostkey /p2v/stamp-test-virt-p2v-pxe-kernel diff --git a/generator/Makefile.am b/generator/Makefile.am index c2d10966a..d026e9558 100644 --- a/generator/Makefile.am +++ b/generator/Makefile.am @@ -101,6 +101,8 @@ sources = \ proc_nr.mli \ python.ml \ python.mli \ + p2v_config.ml \ + p2v_config.mli \ ruby.ml \ ruby.mli \ structs.ml \ @@ -165,6 +167,7 @@ objects = \ errnostring.cmo \ customize.cmo \ UEFI.cmo \ + p2v_config.cmo \ main.cmo EXTRA_DIST = $(sources) files-generated.txt diff --git a/generator/main.ml b/generator/main.ml index e51313779..ecc551f72 100644 --- a/generator/main.ml +++ b/generator/main.ml @@ -363,6 +363,11 @@ Run it from the top source directory using the command output_to "customize/customize-options.pod" Customize.generate_customize_options_pod; + output_to "p2v/p2v-config.h" + P2v_config.generate_p2v_config_h; + output_to "p2v/config.c" + P2v_config.generate_p2v_config_c; + (* Generate the list of files generated -- last. *) printf "generated %d lines of code\n" (get_lines_generated ()); let files = List.sort compare (get_files_generated ()) in diff --git a/generator/p2v_config.ml b/generator/p2v_config.ml new file mode 100644 index 000000000..1f998fd7c --- /dev/null +++ b/generator/p2v_config.ml @@ -0,0 +1,389 @@ +(* libguestfs + * Copyright (C) 2018 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 + *) + +(* Please read generator/README first. *) + +open Printf + +open Std_utils +open Docstrings +open Pr + +let generate_header = generate_header ~inputs:["generator/p2v_config.ml"] + +type enum_choice = string * string (* name, comment *) +type enum = string * enum_choice list + +type config_entry = + | ConfigString of string + | ConfigInt of string * int (* field name, initial value *) + | ConfigUnsigned of string + | ConfigUInt64 of string + | ConfigEnum of string + | ConfigBool of string + | ConfigStringList of string + | ConfigSection of string * config_entry list + +(* Enums. *) +let enums = [ + "basis", [ + "BASIS_UNKNOWN", "RTC could not be read"; + "BASIS_UTC", "RTC is either UTC or an offset from UTC"; + "BASIS_LOCALTIME", "RTC is localtime"; + ]; + "output_allocation", [ + "OUTPUT_ALLOCATION_NONE", "output allocation not set"; + "OUTPUT_ALLOCATION_SPARSE", "sparse"; + "OUTPUT_ALLOCATION_PREALLOCATED", "preallocated"; + ]; +] + +(* Configuration fields. *) +let fields = [ + ConfigString "server"; + ConfigInt ("port", 22); + ConfigString "username"; + ConfigString "password"; + ConfigString "identity_url"; + ConfigString "identity_file"; + ConfigBool "identity_file_needs_update"; + ConfigBool "sudo"; + ConfigString "guestname"; + ConfigInt ("vcpus", 0); + ConfigUInt64 "memory"; + ConfigSection ("cpu", [ + ConfigString "vendor"; + ConfigString "model"; + ConfigUnsigned "sockets"; + ConfigUnsigned "cores"; + ConfigUnsigned "threads"; + ConfigBool "acpi"; + ConfigBool "apic"; + ConfigBool "pae"; + ]); + ConfigSection ("rtc", [ + ConfigEnum "basis"; + ConfigInt ("offset", 0); + ]); + ConfigStringList "disks"; + ConfigStringList "removable"; + ConfigStringList "interfaces"; + ConfigStringList "network_map"; + ConfigString "output"; + ConfigEnum "output_allocation"; + ConfigString "output_connection"; + ConfigString "output_format"; + ConfigString "output_storage"; +] + +let name_of_config_entry = function + | ConfigString n + | ConfigInt (n, _) + | ConfigUnsigned n + | ConfigUInt64 n + | ConfigEnum n + | ConfigBool n + | ConfigStringList n + | ConfigSection (n, _) -> n + +let rec generate_p2v_config_h () = + generate_header CStyle GPLv2plus; + + pr "\ +#ifndef GUESTFS_P2V_CONFIG_H +#define GUESTFS_P2V_CONFIG_H + +#include +#include + +"; + + (* Generate enums. *) + List.iter ( + fun (name, fields) -> + pr "enum %s {\n" name; + List.iter ( + fun (n, comment) -> + pr " %-25s /* %s */\n" (n ^ ",") comment + ) fields; + pr "};\n"; + pr "\n" + ) enums; + + (* Generate struct config. *) + generate_config_struct "config" fields; + + pr "\ +extern struct config *new_config (void); +extern struct config *copy_config (struct config *); +extern void free_config (struct config *); +extern void print_config (struct config *, FILE *); + +#endif /* GUESTFS_P2V_CONFIG_H */ +" + +and generate_config_struct name fields = + (* If there are any ConfigSection (sub-structs) in any of the + * fields then output those first. + *) + List.iter ( + function + | ConfigSection (name, fields) -> + generate_config_struct (name ^ "_config") fields + | _ -> () + ) fields; + + (* Now generate this struct. *) + pr "struct %s {\n" name; + List.iter ( + function + | ConfigString n -> pr " char *%s;\n" n + | ConfigInt (n, _) -> pr " int %s;\n" n + | ConfigUnsigned n -> pr " unsigned %s;\n" n + | ConfigUInt64 n -> pr " uint64_t %s;\n" n + | ConfigEnum n -> pr " enum %s %s;\n" n n + | ConfigBool n -> pr " bool %s;\n" n + | ConfigStringList n -> pr " char **%s;\n" n + | ConfigSection (n, _) -> pr " struct %s_config %s;\n" n n + ) fields; + pr "};\n"; + pr "\n" + +let rec generate_p2v_config_c () = + generate_header CStyle GPLv2plus; + + pr "\ +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include \"p2v.h\" +#include \"p2v-config.h\" + +/** + * Allocate a new config struct. + */ +struct config * +new_config (void) +{ + struct config *c; + + c = calloc (1, sizeof *c); + if (c == NULL) + error (EXIT_FAILURE, errno, \"calloc\"); + +"; + + generate_field_initialization "c->" fields; + + pr "\ + + return c; +} + +/** + * Copy a config struct. + */ +struct config * +copy_config (struct config *old) +{ + struct config *c = new_config (); + + memcpy (c, old, sizeof *c); + + /* Need to deep copy strings and string lists. */ +"; + + generate_field_copy "c->" fields; + + pr "\ + + return c; +} + +/** + * Free a config struct. + */ +void +free_config (struct config *c) +{ + if (c == NULL) + return; + +"; + + generate_field_free "c->" fields; + +pr "\ +} + +"; + + List.iter ( + fun (name, fields) -> + pr "static void\n"; + pr "print_%s (enum %s v, FILE *fp)\n" name name; + pr "{\n"; + pr " switch (v) {\n"; + List.iter ( + fun (n, comment) -> + pr " case %s:\n" n; + pr " fprintf (fp, \"%s\");\n" comment; + pr " break;\n"; + ) fields; + pr " }\n"; + pr "}\n"; + pr "\n"; + ) enums; + + pr "\ +/** + * Print the conversion parameters and other important information. + */ +void +print_config (struct config *c, FILE *fp) +{ + size_t i; + + fprintf (fp, \"%%-20s %%s\\n\", \"local version\", PACKAGE_VERSION_FULL); + fprintf (fp, \"%%-20s %%s\\n\", \"remote version\", + v2v_version ? v2v_version : \"unknown\"); +"; + + generate_field_print None "c->" fields; + +pr "\ +} +" + +and generate_field_initialization v fields = + List.iter ( + function + | ConfigInt (_, 0) -> () + | ConfigInt (n, i) -> + pr " %s%s = %d;\n" v n i + + | ConfigString _ + | ConfigUnsigned _ + | ConfigUInt64 _ + | ConfigEnum _ + | ConfigBool _ + | ConfigStringList _ -> () + + | ConfigSection (n, fields) -> + let v = sprintf "%s%s." v n in + generate_field_initialization v fields + ) fields + +and generate_field_copy v fields = + List.iter ( + function + | ConfigString n -> + pr " if (%s%s) {\n" v n; + pr " %s%s = strdup (%s%s);\n" v n v n; + pr " if (%s%s == NULL)\n" v n; + pr " error (EXIT_FAILURE, errno, \"strdup: %%s\", \"%s\");\n" n; + pr " }\n"; + | ConfigStringList n -> + pr " if (%s%s) {\n" v n; + pr " %s%s = guestfs_int_copy_string_list (%s%s);\n" v n v n; + pr " if (%s%s == NULL)\n" v n; + pr " error (EXIT_FAILURE, errno, \"copy string list: %%s\", \"%s\");\n" n; + pr " }\n"; + + | ConfigInt _ + | ConfigUnsigned _ + | ConfigUInt64 _ + | ConfigEnum _ + | ConfigBool _ -> () + + | ConfigSection (n, fields) -> + let v = sprintf "%s%s." v n in + generate_field_copy v fields + ) fields + +and generate_field_free v fields = + List.iter ( + function + | ConfigString n -> + pr " free (%s%s);\n" v n + | ConfigStringList n -> + pr " guestfs_int_free_string_list (%s%s);\n" v n + + | ConfigInt _ + | ConfigUnsigned _ + | ConfigUInt64 _ + | ConfigEnum _ + | ConfigBool _ -> () + + | ConfigSection (n, fields) -> + let v = sprintf "%s%s." v n in + generate_field_free v fields + ) fields + +and generate_field_print prefix v fields = + List.iter ( + fun field -> + let printable_name = + match prefix with + | None -> name_of_config_entry field + | Some prefix -> prefix ^ "." ^ name_of_config_entry field in + + match field with + | ConfigString n -> + pr " fprintf (fp, \"%%-20s %%s\\n\",\n"; + pr " \"%s\", %s%s ? %s%s : \"(none)\");\n" + printable_name v n v n + | ConfigInt (n, _) -> + pr " fprintf (fp, \"%%-20s %%d\\n\",\n"; + pr " \"%s\", %s%s);\n" printable_name v n + | ConfigUnsigned n -> + pr " fprintf (fp, \"%%-20s %%u\\n\",\n"; + pr " \"%s\", %s%s);\n" printable_name v n + | ConfigUInt64 n -> + pr " fprintf (fp, \"%%-20s %%\" PRIu64 \"\\n\",\n"; + pr " \"%s\", %s%s);\n" printable_name v n + | ConfigEnum n -> + pr " fprintf (fp, \"%%-20s \", \"%s\");\n" printable_name; + pr " print_%s (%s%s, fp);\n" n v n; + pr " fprintf (fp, \"\\n\");\n" + | ConfigBool n -> + pr " fprintf (fp, \"%%-20s %%s\\n\",\n"; + pr " \"%s\", %s%s ? \"true\" : \"false\");\n" + printable_name v n + | ConfigStringList n -> + pr " fprintf (fp, \"%%-20s\", \"%s\");\n" printable_name; + pr " if (%s%s) {\n" v n; + pr " for (i = 0; %s%s[i] != NULL; ++i)\n" v n; + pr " fprintf (fp, \" %%s\", %s%s[i]);\n" v n; + pr " }\n"; + pr " else\n"; + pr " fprintf (fp, \" (none)\\n\");\n"; + pr " fprintf (fp, \"\\n\");\n" + + | ConfigSection (n, fields) -> + let v = sprintf "%s%s." v n in + generate_field_print (Some printable_name) v fields + ) fields diff --git a/generator/p2v_config.mli b/generator/p2v_config.mli new file mode 100644 index 000000000..55d0363a3 --- /dev/null +++ b/generator/p2v_config.mli @@ -0,0 +1,20 @@ +(* libguestfs + * Copyright (C) 2009-2018 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 + *) + +val generate_p2v_config_h : unit -> unit +val generate_p2v_config_c : unit -> unit diff --git a/p2v/Makefile.am b/p2v/Makefile.am index 12b944a2f..f66c2a09b 100644 --- a/p2v/Makefile.am +++ b/p2v/Makefile.am @@ -18,7 +18,9 @@ include $(top_srcdir)/subdir-rules.mk generator_built = \ - about-authors.c + about-authors.c \ + config.c \ + p2v-config.h BUILT_SOURCES = \ $(generator_built) @@ -90,6 +92,7 @@ virt_p2v_SOURCES = \ main.c \ nbd.c \ p2v.h \ + p2v-config.h \ physical-xml.c \ rtc.c \ ssh.c \ diff --git a/p2v/config.c b/p2v/config.c deleted file mode 100644 index 49e0343d1..000000000 --- a/p2v/config.c +++ /dev/null @@ -1,208 +0,0 @@ -/* virt-p2v - * Copyright (C) 2009-2018 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. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "p2v.h" - -struct config * -new_config (void) -{ - struct config *c; - - c = calloc (1, sizeof *c); - if (c == NULL) - error (EXIT_FAILURE, errno, "calloc"); - - c->port = 22; - - c->output_allocation = OUTPUT_ALLOCATION_NONE; - - return c; -} - -struct config * -copy_config (struct config *old) -{ - struct config *c = new_config (); - - memcpy (c, old, sizeof *c); - - /* Need to deep copy strings and string lists. */ - if (c->server) - c->server = strdup (c->server); - if (c->username) - c->username = strdup (c->username); - if (c->password) - c->password = strdup (c->password); - if (c->identity_url) - c->identity_url = strdup (c->identity_url); - if (c->identity_file) - c->identity_file = strdup (c->identity_file); - if (c->guestname) - c->guestname = strdup (c->guestname); - if (c->cpu.vendor) - c->cpu.vendor = strdup (c->cpu.vendor); - if (c->cpu.model) - c->cpu.model = strdup (c->cpu.model); - if (c->disks) - c->disks = guestfs_int_copy_string_list (c->disks); - if (c->removable) - c->removable = guestfs_int_copy_string_list (c->removable); - if (c->interfaces) - c->interfaces = guestfs_int_copy_string_list (c->interfaces); - if (c->network_map) - c->network_map = guestfs_int_copy_string_list (c->network_map); - if (c->output) - c->output = strdup (c->output); - if (c->output_connection) - c->output_connection = strdup (c->output_connection); - if (c->output_format) - c->output_format = strdup (c->output_format); - if (c->output_storage) - c->output_storage = strdup (c->output_storage); - - return c; -} - -void -free_config (struct config *c) -{ - free (c->server); - free (c->username); - free (c->password); - free (c->identity_url); - free (c->identity_file); - free (c->guestname); - free (c->cpu.vendor); - free (c->cpu.model); - guestfs_int_free_string_list (c->disks); - guestfs_int_free_string_list (c->removable); - guestfs_int_free_string_list (c->interfaces); - guestfs_int_free_string_list (c->network_map); - free (c->output); - free (c->output_connection); - free (c->output_format); - free (c->output_storage); - free (c); -} - -/** - * Print the conversion parameters and other important information. - */ -void -print_config (struct config *config, FILE *fp) -{ - size_t i; - - fprintf (fp, "local version . %s\n", PACKAGE_VERSION_FULL); - fprintf (fp, "remote version . %s\n", - v2v_version ? v2v_version : "unknown"); - fprintf (fp, "conversion server %s\n", - config->server ? config->server : "none"); - fprintf (fp, "port . . . . . . %d\n", config->port); - fprintf (fp, "username . . . . %s\n", - config->username ? config->username : "none"); - fprintf (fp, "password . . . . %s\n", - config->password && strlen (config->password) > 0 ? "***" : "none"); - fprintf (fp, "identity URL . . %s\n", - config->identity_url ? config->identity_url : "none"); - fprintf (fp, "sudo . . . . . . %s\n", - config->sudo ? "true" : "false"); - fprintf (fp, "guest name . . . %s\n", - config->guestname ? config->guestname : "none"); - fprintf (fp, "vcpus . . . . . %d\n", config->vcpus); - fprintf (fp, "memory . . . . . %" PRIu64 "\n", config->memory); - if (config->cpu.vendor) - fprintf (fp, "cpu vendor . . . %s\n", config->cpu.vendor); - if (config->cpu.model) - fprintf (fp, "cpu model . . . %s\n", config->cpu.model); - if (config->cpu.sockets > 0) - fprintf (fp, "cpu sockets . . %u\n", config->cpu.sockets); - if (config->cpu.cores > 0) - fprintf (fp, "cpu cores . . . %u\n", config->cpu.cores); - if (config->cpu.threads > 0) - fprintf (fp, "cpu threads . . %u\n", config->cpu.threads); - fprintf (fp, "flags . . . . . %s%s%s\n", - config->cpu.acpi ? " acpi" : "", - config->cpu.apic ? " apic" : "", - config->cpu.pae ? " pae" : ""); - fprintf (fp, "rtc offset . . . "); - switch (config->rtc.basis) { - case BASIS_UNKNOWN: - fprintf (fp, "unknown"); - break; - case BASIS_UTC: - fprintf (fp, "%d seconds from UTC", config->rtc.offset); - break; - case BASIS_LOCALTIME: - fprintf (fp, "%d seconds from localtime", config->rtc.offset); - break; - } - fprintf (fp, "\n"); - fprintf (fp, "disks . . . . . "); - if (config->disks != NULL) { - for (i = 0; config->disks[i] != NULL; ++i) - fprintf (fp, " %s", config->disks[i]); - } - fprintf (fp, "\n"); - fprintf (fp, "removable . . . "); - if (config->removable != NULL) { - for (i = 0; config->removable[i] != NULL; ++i) - fprintf (fp, " %s", config->removable[i]); - } - fprintf (fp, "\n"); - fprintf (fp, "interfaces . . . "); - if (config->interfaces != NULL) { - for (i = 0; config->interfaces[i] != NULL; ++i) - fprintf (fp, " %s", config->interfaces[i]); - } - fprintf (fp, "\n"); - fprintf (fp, "network map . . "); - if (config->network_map != NULL) { - for (i = 0; config->network_map[i] != NULL; ++i) - fprintf (fp, " %s", config->network_map[i]); - } - fprintf (fp, "\n"); - fprintf (fp, "output . . . . . %s\n", - config->output ? config->output : "none"); - fprintf (fp, "output alloc . . "); - switch (config->output_allocation) { - case OUTPUT_ALLOCATION_NONE: fprintf (fp, "none"); break; - case OUTPUT_ALLOCATION_SPARSE: fprintf (fp, "sparse"); break; - case OUTPUT_ALLOCATION_PREALLOCATED: fprintf (fp, "preallocated"); break; - default: fprintf (fp, "unknown? (%d)", config->output_allocation); - } - fprintf (fp, "\n"); - fprintf (fp, "output conn . . %s\n", - config->output_connection ? config->output_connection : "none"); - fprintf (fp, "output format . %s\n", - config->output_format ? config->output_format : "none"); - fprintf (fp, "output storage . %s\n", - config->output_storage ? config->output_storage : "none"); -} diff --git a/p2v/p2v.h b/p2v/p2v.h index b72a4832d..021ea2946 100644 --- a/p2v/p2v.h +++ b/p2v/p2v.h @@ -28,6 +28,7 @@ #define DEBUG_STDERR 1 #include "miniexpect.h" +#include "p2v-config.h" /* We don't use libguestfs directly here, and we don't link to it * either (in fact, we don't want libguestfs on the ISO). However @@ -59,61 +60,6 @@ extern int feature_colours_option; /* virt-p2v --colours option (used by ansi_* macros). */ extern int force_colour; -/* config.c */ -struct cpu_config { - char *vendor; /* eg. "Intel" */ - char *model; /* eg. "Broadwell" */ - unsigned sockets; /* number of sockets */ - unsigned cores; /* number of cores per socket */ - unsigned threads; /* number of hyperthreads per core */ - bool acpi; - bool apic; - bool pae; -}; - -struct rtc_config { - enum { - BASIS_UNKNOWN, /* RTC could not be read. */ - BASIS_UTC, /* RTC is either UTC or an offset from UTC. */ - BASIS_LOCALTIME, /* RTC is localtime. */ - } basis; - int offset; /* RTC seconds offset from basis. */ -}; - -struct config { - char *server; - int port; - char *username; - char *password; - char *identity_url; - char *identity_file; /* Used to cache the downloaded identity_url. */ - int identity_file_needs_update; - int sudo; - char *guestname; - int vcpus; - uint64_t memory; - struct cpu_config cpu; - struct rtc_config rtc; - char **disks; - char **removable; - char **interfaces; - char **network_map; - char *output; - int output_allocation; - char *output_connection; - char *output_format; - char *output_storage; -}; - -#define OUTPUT_ALLOCATION_NONE 0 -#define OUTPUT_ALLOCATION_SPARSE 1 -#define OUTPUT_ALLOCATION_PREALLOCATED 2 - -extern struct config *new_config (void); -extern struct config *copy_config (struct config *); -extern void free_config (struct config *); -extern void print_config (struct config *, FILE *); - /* cpuid.c */ extern void get_cpu_config (struct cpu_config *); diff --git a/p2v/test-virt-p2v-cmdline.sh b/p2v/test-virt-p2v-cmdline.sh index 770b7a825..f0077f750 100755 --- a/p2v/test-virt-p2v-cmdline.sh +++ b/p2v/test-virt-p2v-cmdline.sh @@ -33,21 +33,21 @@ $VG virt-p2v --cmdline='p2v.server=localhost p2v.port=123 p2v.username=user p2v. cat $out # Check the output contains what we expect. -grep "^conversion server.*localhost" $out +grep "^server.*localhost" $out grep "^port.*123" $out grep "^username.*user" $out grep "^sudo.*false" $out -grep "^guest name.*test" $out +grep "^guestname.*test" $out grep "^vcpus.*4" $out grep "^memory.*"$((1024*1024*1024)) $out grep "^disks.*sda sdb sdc" $out grep "^removable.*sdd" $out grep "^interfaces.*eth0 eth1" $out -grep "^network map.*em1:wired other" $out +grep "^network_map.*em1:wired other" $out grep "^output.*local" $out -grep "^output alloc.*sparse" $out -grep "^output conn.*qemu:///session" $out -grep "^output format.*raw" $out -grep "^output storage.*/var/tmp" $out +grep "^output_allocation.*sparse" $out +grep "^output_connection.*qemu:///session" $out +grep "^output_format.*raw" $out +grep "^output_storage.*/var/tmp" $out rm $out