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<--connect URI> | B<-c URI>
99 If using libvirt, connect to the given I<URI>. If omitted, then we
100 connect to the default libvirt hypervisor.
102 If you specify guest block devices directly, then libvirt is not used
109 =item B<--expr EXPR> | B<-e EXPR>
111 Instead of launching the external editor, non-interactively
112 apply the Perl expression C<EXPR> to each line in the file.
113 See L</NON-INTERACTIVE EDITING> below.
115 Be careful to properly quote the expression to prevent it from
116 being altered by the shell.
122 GetOptions ("help|?" => \$help,
123 "version" => \$version,
124 "connect|c=s" => \$uri,
125 "expr|e=s" => \$expr,
127 pod2usage (1) if $help;
129 my $g = Sys::Guestfs->new ();
130 my %h = $g->version ();
131 print "$h{major}.$h{minor}.$h{release}$h{extra}\n";
135 pod2usage (__"virt-edit: no image, VM names or filenames to edit given")
138 my $filename = pop @ARGV;
142 $g = open_guest (\@ARGV, address => $uri, rw => 1);
144 $g = open_guest (\@ARGV, rw => 1);
149 # List of possible filesystems.
150 my @partitions = get_partitions ($g);
152 # Now query each one to build up a picture of what's in it.
154 inspect_all_partitions ($g, \@partitions,
155 use_windows_registry => 0);
157 my $oses = inspect_operating_systems ($g, \%fses);
159 my @roots = keys %$oses;
160 die __"multiboot operating systems are not supported by virt-edit" if @roots > 1;
161 my $root_dev = $roots[0];
163 my $os = $oses->{$root_dev};
164 mount_operating_system ($g, $os, 0);
166 my ($fh_not_used, $tempname) = tempfile ();
168 # Allow this to fail in case eg. the file does not exist.
169 $g->download($filename, $tempname);
171 my $do_upload = $tempname;
173 if (!defined $expr) {
174 # Interactively edit the file.
175 my $oldctime = (stat ($tempname))[10];
177 my $editor = $ENV{EDITOR};
179 system ("$editor $tempname") == 0
180 or die "edit failed: $editor: $?";
182 my $newctime = (stat ($tempname))[10];
184 if ($oldctime == $newctime) {
186 print __"File not changed.\n";
189 my ($fh, $tempout) = tempfile ();
191 # Apply a Perl expression to the lines of the file.
192 open IFILE, $tempname or die "$tempname: $!";
198 print $fh $_ or die "print: $!";
202 $do_upload = $tempout;
205 if (defined $do_upload) {
206 $g->upload ($do_upload, $filename);
215 =head1 NON-INTERACTIVE EDITING
217 C<virt-edit> normally calls out to C<$EDITOR> (or vi) so
218 the system administrator can interactively edit the file.
220 There are two ways also to use C<virt-edit> from scripts in order to
221 make automated edits to files. (Note that although you I<can> use
222 C<virt-edit> like this, it's less error-prone to write scripts
223 directly using the libguestfs API and Augeas for configuration file
226 The first method is to temporarily set C<$EDITOR> to any script or
227 program you want to run. The script is invoked as C<$EDITOR tmpfile>
228 and it should update C<tmpfile> in place however it likes.
230 The second method is to use the C<-e> parameter of C<virt-edit> to run
231 a short Perl snippet in the style of L<sed(1)>. For example to
232 replace all instances of C<foo> with C<bar> in a file:
234 virt-edit domname filename -e 's/foo/bar/'
236 The full power of Perl regular expressions can be used (see
237 L<perlre(1)>). For example to delete root's password you could do:
239 virt-edit domname /etc/passwd -e 's/^root:.*?:/root::/'
241 What really happens is that the snippet is evaluated as a Perl
242 expression for each line of the file. The line, including the final
243 C<\n>, is passed in C<$_> and the expression should update C<$_> or
246 To delete a line, set C<$_> to the empty string. For example, to
247 delete the C<apache> user account from the password file you can do:
249 virt-edit mydomain /etc/passwd -e '$_ = "" if /^apache:/'
251 To insert a line, prepend or append it to C<$_>. However appending
252 lines to the end of the file is rather difficult this way since there
253 is no concept of "last line of the file" - your expression just
254 doesn't get called again. You might want to use the first method
255 (setting C<$EDITOR>) if you want to do this.
257 The variable C<$lineno> contains the current line number.
258 As is traditional, the first line in the file is number C<1>.
260 The return value from the expression is ignored, but the expression
261 may call C<die> in order to abort the whole program, leaving the
262 original file untouched.
264 Remember when matching the end of a line that C<$_> may contain the
265 final C<\n>, or (for DOS files) C<\r\n>, or if the file does not end
266 with a newline then neither of these. Thus to match or substitute
267 some text at the end of a line, use this regular expression:
271 Alternately, use the perl C<chomp> function, being careful not to
272 chomp C<$_> itself (since that would remove all newlines from the
275 my $m = $_; chomp $m; $m =~ /some text$/
277 =head1 ENVIRONMENT VARIABLES
283 If set, this string is used as the editor. It may contain arguments,
286 If not set, C<vi> is used.
296 L<Sys::Guestfs::Lib(3)>,
298 L<http://libguestfs.org/>,
304 Richard W.M. Jones L<http://people.redhat.com/~rjones/>
308 Copyright (C) 2009-2010 Red Hat Inc.
310 This program is free software; you can redistribute it and/or modify
311 it under the terms of the GNU General Public License as published by
312 the Free Software Foundation; either version 2 of the License, or
313 (at your option) any later version.
315 This program is distributed in the hope that it will be useful,
316 but WITHOUT ANY WARRANTY; without even the implied warranty of
317 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
318 GNU General Public License for more details.
320 You should have received a copy of the GNU General Public License
321 along with this program; if not, write to the Free Software
322 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.