3 # Copyright (C) 2009-2010 Red Hat Inc.
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 use Sys::Guestfs::Lib qw(open_guest get_partitions resolve_windows_path
24 inspect_all_partitions inspect_partition
25 inspect_operating_systems mount_operating_system);
28 use File::Temp qw/tempfile/;
29 use Locale::TextDomain 'libguestfs';
35 virt-edit - Edit a file in a virtual machine
39 virt-edit [--options] domname file
41 virt-edit [--options] disk.img [disk.img ...] file
43 virt-edit [domname|disk.img] file -e 'expr'
47 You must I<not> use C<virt-edit> on live virtual machines. If you do
48 this, you risk disk corruption in the VM. C<virt-edit> tries to stop
49 you from doing this, but doesn't catch all cases.
53 C<virt-edit> is a command line tool to edit C<file> where C<file>
54 exists in the named virtual machine (or disk image).
56 If you want to just view a file, use L<virt-cat(1)>. For more complex
57 cases you should look at the L<guestfish(1)> tool.
61 Edit the named files interactively:
63 virt-edit mydomain /boot/grub/grub.conf
65 virt-edit mydomain /etc/passwd
67 You can also edit files non-interactively (see
68 L</NON-INTERACTIVE EDITING> below).
69 To change the init default level to 5:
71 virt-edit mydomain /etc/inittab -e 's/^id:.*/id:5:initdefault:/'
91 Display version number and exit.
97 =item B<--backup extension> | B<-b extension>
99 Create a backup of the original file I<in the guest disk image>.
100 The backup has the original filename with C<extension> added.
102 Usually the first character of C<extension> would be a dot C<.>
105 virt-edit -b .orig [etc]
107 By default, no backup file is made.
113 =item B<--connect URI> | B<-c URI>
115 If using libvirt, connect to the given I<URI>. If omitted, then we
116 connect to the default libvirt hypervisor.
118 If you specify guest block devices directly, then libvirt is not used
125 =item B<--format> raw
127 Specify the format of disk images given on the command line. If this
128 is omitted then the format is autodetected from the content of the
131 If disk images are requested from libvirt, then this program asks
132 libvirt for this information. In this case, the value of the format
133 parameter is ignored.
135 If working with untrusted raw-format guest disk images, you should
136 ensure the format is always specified.
142 =item B<--expr EXPR> | B<-e EXPR>
144 Instead of launching the external editor, non-interactively
145 apply the Perl expression C<EXPR> to each line in the file.
146 See L</NON-INTERACTIVE EDITING> below.
148 Be careful to properly quote the expression to prevent it from
149 being altered by the shell.
155 GetOptions ("help|?" => \$help,
156 "version" => \$version,
157 "connect|c=s" => \$uri,
158 "format=s" => \$format,
159 "expr|e=s" => \$expr,
160 "backup|b=s" => \$backup,
162 pod2usage (1) if $help;
164 my $g = Sys::Guestfs->new ();
165 my %h = $g->version ();
166 print "$h{major}.$h{minor}.$h{release}$h{extra}\n";
170 pod2usage (__"virt-edit: no image, VM names or filenames to edit given")
173 my $filename = pop @ARGV;
177 $g = open_guest (\@ARGV, address => $uri, rw => 1, format => $format);
179 $g = open_guest (\@ARGV, rw => 1, format => $format);
184 # List of possible filesystems.
185 my @partitions = get_partitions ($g);
187 # Now query each one to build up a picture of what's in it.
189 inspect_all_partitions ($g, \@partitions,
190 use_windows_registry => 0);
192 my $oses = inspect_operating_systems ($g, \%fses);
194 my @roots = keys %$oses;
195 die __"multiboot operating systems are not supported by virt-edit" if @roots > 1;
196 my $root_dev = $roots[0];
198 my $os = $oses->{$root_dev};
199 mount_operating_system ($g, $os, 0);
201 my ($fh, $tempname) = tempfile (UNLINK => 1);
202 my $fddev = "/dev/fd/" . fileno ($fh);
204 # Allow this to fail in case eg. the file does not exist.
205 $g->download ($filename, $fddev);
207 close $fh or die "close: $!";
209 my $do_upload = $tempname;
211 if (!defined $expr) {
212 # Interactively edit the file.
213 my $oldctime = (stat ($tempname))[10];
215 my $editor = $ENV{EDITOR};
217 system ("$editor $tempname") == 0
218 or die "edit failed: $editor: $?";
220 my $newctime = (stat ($tempname))[10];
222 if ($oldctime == $newctime) {
224 print __"File not changed.\n";
227 my ($fh, $tempout) = tempfile (UNLINK => 1);
229 # Apply a Perl expression to the lines of the file.
230 open IFILE, $tempname or die "$tempname: $!";
236 print $fh $_ or die "print: $!";
238 close $fh or die "close: $!";
240 $do_upload = $tempout;
243 if (defined $do_upload) {
244 # Upload to a new file, so if it fails we don't end up with
245 # a partially written file. Give the new file a completely
246 # random name so we have only a tiny chance of overwriting
247 # some existing file.
248 my $dirname = $filename;
249 $dirname =~ s{/[^/]+$}{/};
251 my @chars = ('a'..'z', 'A'..'Z', '0'..'9');
252 my $newname = $dirname;
254 $newname .= $chars[rand @chars];
257 $g->upload ($do_upload, $newname);
259 # Backup or overwrite?
260 $g->mv ($filename, "$filename$backup") if defined $backup;
261 $g->mv ($newname, $filename);
271 =head1 NON-INTERACTIVE EDITING
273 C<virt-edit> normally calls out to C<$EDITOR> (or vi) so
274 the system administrator can interactively edit the file.
276 There are two ways also to use C<virt-edit> from scripts in order to
277 make automated edits to files. (Note that although you I<can> use
278 C<virt-edit> like this, it's less error-prone to write scripts
279 directly using the libguestfs API and Augeas for configuration file
282 The first method is to temporarily set C<$EDITOR> to any script or
283 program you want to run. The script is invoked as C<$EDITOR tmpfile>
284 and it should update C<tmpfile> in place however it likes.
286 The second method is to use the C<-e> parameter of C<virt-edit> to run
287 a short Perl snippet in the style of L<sed(1)>. For example to
288 replace all instances of C<foo> with C<bar> in a file:
290 virt-edit domname filename -e 's/foo/bar/'
292 The full power of Perl regular expressions can be used (see
293 L<perlre(1)>). For example to delete root's password you could do:
295 virt-edit domname /etc/passwd -e 's/^root:.*?:/root::/'
297 What really happens is that the snippet is evaluated as a Perl
298 expression for each line of the file. The line, including the final
299 C<\n>, is passed in C<$_> and the expression should update C<$_> or
302 To delete a line, set C<$_> to the empty string. For example, to
303 delete the C<apache> user account from the password file you can do:
305 virt-edit mydomain /etc/passwd -e '$_ = "" if /^apache:/'
307 To insert a line, prepend or append it to C<$_>. However appending
308 lines to the end of the file is rather difficult this way since there
309 is no concept of "last line of the file" - your expression just
310 doesn't get called again. You might want to use the first method
311 (setting C<$EDITOR>) if you want to do this.
313 The variable C<$lineno> contains the current line number.
314 As is traditional, the first line in the file is number C<1>.
316 The return value from the expression is ignored, but the expression
317 may call C<die> in order to abort the whole program, leaving the
318 original file untouched.
320 Remember when matching the end of a line that C<$_> may contain the
321 final C<\n>, or (for DOS files) C<\r\n>, or if the file does not end
322 with a newline then neither of these. Thus to match or substitute
323 some text at the end of a line, use this regular expression:
327 Alternately, use the perl C<chomp> function, being careful not to
328 chomp C<$_> itself (since that would remove all newlines from the
331 my $m = $_; chomp $m; $m =~ /some text$/
333 =head1 ENVIRONMENT VARIABLES
339 If set, this string is used as the editor. It may contain arguments,
342 If not set, C<vi> is used.
348 Libvirt guest names can contain arbitrary characters, some of which
349 have meaning to the shell such as C<#> and space. You may need to
350 quote or escape these characters on the command line. See the shell
351 manual page L<sh(1)> for details.
359 L<Sys::Guestfs::Lib(3)>,
361 L<http://libguestfs.org/>,
367 Richard W.M. Jones L<http://people.redhat.com/~rjones/>
371 Copyright (C) 2009-2010 Red Hat Inc.
373 This program is free software; you can redistribute it and/or modify
374 it under the terms of the GNU General Public License as published by
375 the Free Software Foundation; either version 2 of the License, or
376 (at your option) any later version.
378 This program is distributed in the hope that it will be useful,
379 but WITHOUT ANY WARRANTY; without even the implied warranty of
380 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
381 GNU General Public License for more details.
383 You should have received a copy of the GNU General Public License
384 along with this program; if not, write to the Free Software
385 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.