3 # Copyright (C) 2009-2011 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);
26 use File::Temp qw/tempfile/;
28 use Locale::TextDomain 'libguestfs';
34 virt-edit - Edit a file in a virtual machine
38 virt-edit [--options] domname file
40 virt-edit [--options] disk.img [disk.img ...] file
42 virt-edit [domname|disk.img] file -e 'expr'
46 You must I<not> use C<virt-edit> on live virtual machines. If you do
47 this, you risk disk corruption in the VM. C<virt-edit> tries to stop
48 you from doing this, but doesn't catch all cases.
52 C<virt-edit> is a command line tool to edit C<file> where C<file>
53 exists in the named virtual machine (or disk image).
55 If you want to just view a file, use L<virt-cat(1)>.
57 For more complex cases you should look at the L<guestfish(1)> tool
58 (see L</USING GUESTFISH> below).
60 C<virt-edit> cannot be used to create a new file, nor to edit
61 multiple files. L<guestfish(1)> can do that and much more.
65 Edit the named files interactively:
67 virt-edit mydomain /boot/grub/grub.conf
69 virt-edit mydomain /etc/passwd
71 You can also edit files non-interactively (see
72 L</NON-INTERACTIVE EDITING> below).
73 To change the init default level to 5:
75 virt-edit mydomain /etc/inittab -e 's/^id:.*/id:5:initdefault:/'
95 Display version number and exit.
101 =item B<--backup extension> | B<-b extension>
103 Create a backup of the original file I<in the guest disk image>.
104 The backup has the original filename with C<extension> added.
106 Usually the first character of C<extension> would be a dot C<.>
109 virt-edit -b .orig [etc]
111 By default, no backup file is made.
117 =item B<--connect URI> | B<-c URI>
119 If using libvirt, connect to the given I<URI>. If omitted, then we
120 connect to the default libvirt hypervisor.
122 If you specify guest block devices directly, then libvirt is not used
129 =item B<--format> raw
131 Specify the format of disk images given on the command line. If this
132 is omitted then the format is autodetected from the content of the
135 If disk images are requested from libvirt, then this program asks
136 libvirt for this information. In this case, the value of the format
137 parameter is ignored.
139 If working with untrusted raw-format guest disk images, you should
140 ensure the format is always specified.
146 =item B<--expr EXPR> | B<-e EXPR>
148 Instead of launching the external editor, non-interactively
149 apply the Perl expression C<EXPR> to each line in the file.
150 See L</NON-INTERACTIVE EDITING> below.
152 Be careful to properly quote the expression to prevent it from
153 being altered by the shell.
159 GetOptions ("help|?" => \$help,
160 "version" => \$version,
161 "connect|c=s" => \$uri,
162 "format=s" => \$format,
163 "expr|e=s" => \$expr,
164 "backup|b=s" => \$backup,
166 pod2usage (1) if $help;
168 my $g = Sys::Guestfs->new ();
169 my %h = $g->version ();
170 print "$h{major}.$h{minor}.$h{release}$h{extra}\n";
174 pod2usage (__"virt-edit: no image, VM names or filenames to edit given")
177 my $filename = pop @ARGV;
181 $g = open_guest (\@ARGV, address => $uri, rw => 1, format => $format);
183 $g = open_guest (\@ARGV, rw => 1, format => $format);
188 my @roots = $g->inspect_os ();
190 die __x("{prog}: No operating system could be detected inside this disk image.\n\nThis may be because the file is not a disk image, or is not a virtual machine\nimage, or because the OS type is not understood by libguestfs.\n\nIf you feel this is an error, please file a bug report including as much\ninformation about the disk image as possible.\n",
191 prog => basename ($0));
194 die __x("{prog}: multiboot operating systems are not supported.\n",
195 prog => basename ($0))
197 my %fses = $g->inspect_get_mountpoints ($roots[0]);
198 my @fses = sort { length $a <=> length $b } keys %fses;
200 $g->mount_options ("", $fses{$_}, $_);
203 my ($fh, $tempname) = tempfile (UNLINK => 1);
204 my $fddev = "/dev/fd/" . fileno ($fh);
206 # Allow this to fail in case eg. the file does not exist.
207 $g->download ($filename, $fddev);
209 close $fh or die "close: $!";
211 my $do_upload = $tempname;
213 if (!defined $expr) {
214 # Interactively edit the file.
215 my $oldctime = (stat ($tempname))[10];
217 my $editor = $ENV{EDITOR};
219 system ("$editor $tempname") == 0
220 or die "edit failed: $editor: $?";
222 my $newctime = (stat ($tempname))[10];
224 if ($oldctime == $newctime) {
226 print __"File not changed.\n";
229 my ($fh, $tempout) = tempfile (UNLINK => 1);
231 # Apply a Perl expression to the lines of the file.
232 open IFILE, $tempname or die "$tempname: $!";
238 print $fh $_ or die "print: $!";
240 close $fh or die "close: $!";
242 $do_upload = $tempout;
245 if (defined $do_upload) {
246 # Upload to a new file, so if it fails we don't end up with
247 # a partially written file. Give the new file a completely
248 # random name so we have only a tiny chance of overwriting
249 # some existing file.
250 my $dirname = $filename;
251 $dirname =~ s{/[^/]+$}{/};
253 my @chars = ('a'..'z', 'A'..'Z', '0'..'9');
254 my $newname = $dirname;
256 $newname .= $chars[rand @chars];
259 $g->upload ($do_upload, $newname);
261 # Backup or overwrite?
262 $g->mv ($filename, "$filename$backup") if defined $backup;
263 $g->mv ($newname, $filename);
273 =head1 NON-INTERACTIVE EDITING
275 C<virt-edit> normally calls out to C<$EDITOR> (or vi) so
276 the system administrator can interactively edit the file.
278 There are two ways also to use C<virt-edit> from scripts in order to
279 make automated edits to files. (Note that although you I<can> use
280 C<virt-edit> like this, it's less error-prone to write scripts
281 directly using the libguestfs API and Augeas for configuration file
284 The first method is to temporarily set C<$EDITOR> to any script or
285 program you want to run. The script is invoked as C<$EDITOR tmpfile>
286 and it should update C<tmpfile> in place however it likes.
288 The second method is to use the C<-e> parameter of C<virt-edit> to run
289 a short Perl snippet in the style of L<sed(1)>. For example to
290 replace all instances of C<foo> with C<bar> in a file:
292 virt-edit domname filename -e 's/foo/bar/'
294 The full power of Perl regular expressions can be used (see
295 L<perlre(1)>). For example to delete root's password you could do:
297 virt-edit domname /etc/passwd -e 's/^root:.*?:/root::/'
299 What really happens is that the snippet is evaluated as a Perl
300 expression for each line of the file. The line, including the final
301 C<\n>, is passed in C<$_> and the expression should update C<$_> or
304 To delete a line, set C<$_> to the empty string. For example, to
305 delete the C<apache> user account from the password file you can do:
307 virt-edit mydomain /etc/passwd -e '$_ = "" if /^apache:/'
309 To insert a line, prepend or append it to C<$_>. However appending
310 lines to the end of the file is rather difficult this way since there
311 is no concept of "last line of the file" - your expression just
312 doesn't get called again. You might want to use the first method
313 (setting C<$EDITOR>) if you want to do this.
315 The variable C<$lineno> contains the current line number.
316 As is traditional, the first line in the file is number C<1>.
318 The return value from the expression is ignored, but the expression
319 may call C<die> in order to abort the whole program, leaving the
320 original file untouched.
322 Remember when matching the end of a line that C<$_> may contain the
323 final C<\n>, or (for DOS files) C<\r\n>, or if the file does not end
324 with a newline then neither of these. Thus to match or substitute
325 some text at the end of a line, use this regular expression:
329 Alternately, use the perl C<chomp> function, being careful not to
330 chomp C<$_> itself (since that would remove all newlines from the
333 my $m = $_; chomp $m; $m =~ /some text$/
335 =head1 USING GUESTFISH
337 L<guestfish(1)> is a more powerful, lower level tool which you can use
338 when C<virt-edit> doesn't work.
340 Using C<virt-edit> is approximately equivalent to doing:
342 guestfish --rw -i -d domname edit /file
344 where C<domname> is the name of the libvirt guest, and C</file> is the
345 full path to the file.
347 The command above uses libguestfs's guest inspection feature and so
348 does not work on guests that libguestfs cannot inspect, or on things
349 like arbitrary disk images that don't contain guests. To edit a file
350 on a disk image directly, use:
352 guestfish --rw -a disk.img -m /dev/sda1 edit /file
354 where C<disk.img> is the disk image, C</dev/sda1> is the filesystem
355 within the disk image to edit, and C</file> is the full path to the
358 C<virt-edit> cannot create new files. Use the guestfish commands
359 C<touch>, C<write> or C<upload> instead:
361 guestfish --rw -i -d domname touch /newfile
363 guestfish --rw -i -d domname write /newfile "new content"
365 guestfish --rw -i -d domname upload localfile /newfile
367 C<virt-edit> cannot edit multiple files, but guestfish can
370 guestfish --rw -i -d domname edit /file1 : edit /file2
372 =head1 ENVIRONMENT VARIABLES
378 If set, this string is used as the editor. It may contain arguments,
381 If not set, C<vi> is used.
387 Libvirt guest names can contain arbitrary characters, some of which
388 have meaning to the shell such as C<#> and space. You may need to
389 quote or escape these characters on the command line. See the shell
390 manual page L<sh(1)> for details.
398 L<Sys::Guestfs::Lib(3)>,
400 L<http://libguestfs.org/>,
406 Richard W.M. Jones L<http://people.redhat.com/~rjones/>
410 Copyright (C) 2009-2011 Red Hat Inc.
412 This program is free software; you can redistribute it and/or modify
413 it under the terms of the GNU General Public License as published by
414 the Free Software Foundation; either version 2 of the License, or
415 (at your option) any later version.
417 This program is distributed in the hope that it will be useful,
418 but WITHOUT ANY WARRANTY; without even the implied warranty of
419 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
420 GNU General Public License for more details.
422 You should have received a copy of the GNU General Public License
423 along with this program; if not, write to the Free Software
424 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.