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<--expr EXPR> | B<-e EXPR>
127 Instead of launching the external editor, non-interactively
128 apply the Perl expression C<EXPR> to each line in the file.
129 See L</NON-INTERACTIVE EDITING> below.
131 Be careful to properly quote the expression to prevent it from
132 being altered by the shell.
138 GetOptions ("help|?" => \$help,
139 "version" => \$version,
140 "connect|c=s" => \$uri,
141 "expr|e=s" => \$expr,
142 "backup|b=s" => \$backup,
144 pod2usage (1) if $help;
146 my $g = Sys::Guestfs->new ();
147 my %h = $g->version ();
148 print "$h{major}.$h{minor}.$h{release}$h{extra}\n";
152 pod2usage (__"virt-edit: no image, VM names or filenames to edit given")
155 my $filename = pop @ARGV;
159 $g = open_guest (\@ARGV, address => $uri, rw => 1);
161 $g = open_guest (\@ARGV, rw => 1);
166 # List of possible filesystems.
167 my @partitions = get_partitions ($g);
169 # Now query each one to build up a picture of what's in it.
171 inspect_all_partitions ($g, \@partitions,
172 use_windows_registry => 0);
174 my $oses = inspect_operating_systems ($g, \%fses);
176 my @roots = keys %$oses;
177 die __"multiboot operating systems are not supported by virt-edit" if @roots > 1;
178 my $root_dev = $roots[0];
180 my $os = $oses->{$root_dev};
181 mount_operating_system ($g, $os, 0);
183 my ($fh_not_used, $tempname) = tempfile (UNLINK => 1);
185 # Allow this to fail in case eg. the file does not exist.
186 $g->download($filename, $tempname);
188 my $do_upload = $tempname;
190 if (!defined $expr) {
191 # Interactively edit the file.
192 my $oldctime = (stat ($tempname))[10];
194 my $editor = $ENV{EDITOR};
196 system ("$editor $tempname") == 0
197 or die "edit failed: $editor: $?";
199 my $newctime = (stat ($tempname))[10];
201 if ($oldctime == $newctime) {
203 print __"File not changed.\n";
206 my ($fh, $tempout) = tempfile (UNLINK => 1);
208 # Apply a Perl expression to the lines of the file.
209 open IFILE, $tempname or die "$tempname: $!";
215 print $fh $_ or die "print: $!";
219 $do_upload = $tempout;
222 if (defined $do_upload) {
223 # Upload to a new file, so if it fails we don't end up with
224 # a partially written file. Give the new file a completely
225 # random name so we have only a tiny chance of overwriting
226 # some existing file.
227 my $dirname = $filename;
228 $dirname =~ s{/[^/]+$}{/};
230 my @chars = ('a'..'z', 'A'..'Z', '0'..'9');
231 my $newname = $dirname;
233 $newname .= $chars[rand @chars];
236 $g->upload ($do_upload, $newname);
238 # Backup or overwrite?
239 $g->mv ($filename, "$filename$backup") if defined $backup;
240 $g->mv ($newname, $filename);
250 =head1 NON-INTERACTIVE EDITING
252 C<virt-edit> normally calls out to C<$EDITOR> (or vi) so
253 the system administrator can interactively edit the file.
255 There are two ways also to use C<virt-edit> from scripts in order to
256 make automated edits to files. (Note that although you I<can> use
257 C<virt-edit> like this, it's less error-prone to write scripts
258 directly using the libguestfs API and Augeas for configuration file
261 The first method is to temporarily set C<$EDITOR> to any script or
262 program you want to run. The script is invoked as C<$EDITOR tmpfile>
263 and it should update C<tmpfile> in place however it likes.
265 The second method is to use the C<-e> parameter of C<virt-edit> to run
266 a short Perl snippet in the style of L<sed(1)>. For example to
267 replace all instances of C<foo> with C<bar> in a file:
269 virt-edit domname filename -e 's/foo/bar/'
271 The full power of Perl regular expressions can be used (see
272 L<perlre(1)>). For example to delete root's password you could do:
274 virt-edit domname /etc/passwd -e 's/^root:.*?:/root::/'
276 What really happens is that the snippet is evaluated as a Perl
277 expression for each line of the file. The line, including the final
278 C<\n>, is passed in C<$_> and the expression should update C<$_> or
281 To delete a line, set C<$_> to the empty string. For example, to
282 delete the C<apache> user account from the password file you can do:
284 virt-edit mydomain /etc/passwd -e '$_ = "" if /^apache:/'
286 To insert a line, prepend or append it to C<$_>. However appending
287 lines to the end of the file is rather difficult this way since there
288 is no concept of "last line of the file" - your expression just
289 doesn't get called again. You might want to use the first method
290 (setting C<$EDITOR>) if you want to do this.
292 The variable C<$lineno> contains the current line number.
293 As is traditional, the first line in the file is number C<1>.
295 The return value from the expression is ignored, but the expression
296 may call C<die> in order to abort the whole program, leaving the
297 original file untouched.
299 Remember when matching the end of a line that C<$_> may contain the
300 final C<\n>, or (for DOS files) C<\r\n>, or if the file does not end
301 with a newline then neither of these. Thus to match or substitute
302 some text at the end of a line, use this regular expression:
306 Alternately, use the perl C<chomp> function, being careful not to
307 chomp C<$_> itself (since that would remove all newlines from the
310 my $m = $_; chomp $m; $m =~ /some text$/
312 =head1 ENVIRONMENT VARIABLES
318 If set, this string is used as the editor. It may contain arguments,
321 If not set, C<vi> is used.
331 L<Sys::Guestfs::Lib(3)>,
333 L<http://libguestfs.org/>,
339 Richard W.M. Jones L<http://people.redhat.com/~rjones/>
343 Copyright (C) 2009-2010 Red Hat Inc.
345 This program is free software; you can redistribute it and/or modify
346 it under the terms of the GNU General Public License as published by
347 the Free Software Foundation; either version 2 of the License, or
348 (at your option) any later version.
350 This program is distributed in the hope that it will be useful,
351 but WITHOUT ANY WARRANTY; without even the implied warranty of
352 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
353 GNU General Public License for more details.
355 You should have received a copy of the GNU General Public License
356 along with this program; if not, write to the Free Software
357 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.