daemon: debug segv correct use of dereferencing NULL.
[libguestfs.git] / fish / edit.c
1 /* guestfish - the filesystem interactive shell
2  * Copyright (C) 2009-2011 Red Hat Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18
19 #include <config.h>
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <fcntl.h>
26 #include <inttypes.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29
30 #include "fish.h"
31
32 /* guestfish edit command, suggested by Ján Ondrej, implemented by RWMJ */
33
34 int
35 run_edit (const char *cmd, size_t argc, char *argv[])
36 {
37   TMP_TEMPLATE_ON_STACK (filename);
38   char buf[256];
39   const char *editor;
40   char *remotefilename;
41   struct stat oldstat, newstat;
42   int r, fd;
43
44   if (argc != 1) {
45     fprintf (stderr, _("use '%s filename' to edit a file\n"), cmd);
46     return -1;
47   }
48
49   /* Choose an editor. */
50   if (STRCASEEQ (cmd, "vi"))
51     editor = "vi";
52   else if (STRCASEEQ (cmd, "emacs"))
53     editor = "emacs -nw";
54   else {
55     editor = getenv ("EDITOR");
56     if (editor == NULL)
57       editor = "vi"; /* could be cruel here and choose ed(1) */
58   }
59
60   /* Handle 'win:...' prefix. */
61   remotefilename = win_prefix (argv[0]);
62   if (remotefilename == NULL)
63     return -1;
64
65   /* Download the file and write it to a temporary. */
66   fd = mkstemp (filename);
67   if (fd == -1) {
68     perror ("mkstemp");
69     free (remotefilename);
70     return -1;
71   }
72
73   snprintf (buf, sizeof buf, "/dev/fd/%d", fd);
74
75   if (guestfs_download (g, remotefilename, buf) == -1) {
76     close (fd);
77     unlink (filename);
78     free (remotefilename);
79     return -1;
80   }
81
82   if (close (fd) == -1) {
83     perror (filename);
84     unlink (filename);
85     free (remotefilename);
86     return -1;
87   }
88
89   /* Get the old stat. */
90   if (stat (filename, &oldstat) == -1) {
91     perror (filename);
92     unlink (filename);
93     free (remotefilename);
94     return -1;
95   }
96
97   /* Edit it. */
98   /* XXX Safe? */
99   snprintf (buf, sizeof buf, "%s %s", editor, filename);
100
101   r = system (buf);
102   if (r != 0) {
103     perror (buf);
104     unlink (filename);
105     free (remotefilename);
106     return -1;
107   }
108
109   /* Get the new stat. */
110   if (stat (filename, &newstat) == -1) {
111     perror (filename);
112     unlink (filename);
113     free (remotefilename);
114     return -1;
115   }
116
117   /* Changed? */
118   if (oldstat.st_ctime == newstat.st_ctime &&
119       oldstat.st_size == newstat.st_size) {
120     unlink (filename);
121     free (remotefilename);
122     return 0;
123   }
124
125   /* Write new content. */
126   if (guestfs_upload (g, filename, remotefilename) == -1) {
127     unlink (filename);
128     free (remotefilename);
129     return -1;
130   }
131
132   unlink (filename);
133   free (remotefilename);
134   return 0;
135 }