daemon: Remove -f (don't fork) option.
[libguestfs.git] / daemon / checksum.c
1 /* libguestfs - the guestfsd daemon
2  * Copyright (C) 2009 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., 675 Mass Ave, Cambridge, MA 02139, 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 <sys/stat.h>
27
28 #include "guestfs_protocol.h"
29 #include "daemon.h"
30 #include "actions.h"
31
32 static const char *
33 program_of_csum (const char *csumtype)
34 {
35   if (STRCASEEQ (csumtype, "crc"))
36     return "cksum";
37   else if (STRCASEEQ (csumtype, "md5"))
38     return "md5sum";
39   else if (STRCASEEQ (csumtype, "sha1"))
40     return "sha1sum";
41   else if (STRCASEEQ (csumtype, "sha224"))
42     return "sha224sum";
43   else if (STRCASEEQ (csumtype, "sha256"))
44     return "sha256sum";
45   else if (STRCASEEQ (csumtype, "sha384"))
46     return "sha384sum";
47   else if (STRCASEEQ (csumtype, "sha512"))
48     return "sha512sum";
49   else {
50     reply_with_error ("unknown checksum type, expecting crc|md5|sha1|sha224|sha256|sha384|sha512");
51     return NULL;
52   }
53 }
54
55 static char *
56 checksum (const char *csumtype, int fd)
57 {
58   const char *program;
59   char *out, *err;
60   int flags, r;
61   int len;
62
63   program = program_of_csum (csumtype);
64   if (program == NULL) {
65     close (fd);
66     return NULL;
67   }
68
69   flags = COMMAND_FLAG_CHROOT_COPY_FILE_TO_STDIN | fd;
70   r = commandf (&out, &err, flags, program, NULL);
71   if (r == -1) {
72     reply_with_error ("%s: %s", program, err);
73     free (out);
74     free (err);
75     return NULL;
76   }
77
78   free (err);
79
80   /* Split it at the first whitespace. */
81   len = strcspn (out, " \t\n");
82   out[len] = '\0';
83
84   return out;                   /* Caller frees. */
85 }
86
87 char *
88 do_checksum (const char *csumtype, const char *path)
89 {
90   int fd;
91
92   CHROOT_IN;
93   fd = open (path, O_RDONLY);
94   CHROOT_OUT;
95
96   if (fd == -1) {
97     reply_with_perror ("%s", path);
98     return NULL;
99   }
100
101   return checksum (csumtype, fd);
102 }
103
104 char *
105 do_checksum_device (const char *csumtype, const char *device)
106 {
107   int fd;
108
109   fd = open (device, O_RDONLY);
110   if (fd == -1) {
111     reply_with_perror ("%s", device);
112     return NULL;
113   }
114
115   return checksum (csumtype, fd);
116 }
117
118 /* Has one FileOut parameter. */
119 int
120 do_checksums_out (const char *csumtype, const char *dir)
121 {
122   struct stat statbuf;
123   int r;
124
125   const char *program = program_of_csum (csumtype);
126   if (program == NULL)
127     return -1;
128
129   char *sysrootdir = sysroot_path (dir);
130   if (!sysrootdir) {
131     reply_with_perror ("malloc");
132     return -1;
133   }
134
135   r = stat (sysrootdir, &statbuf);
136   if (r == -1) {
137     reply_with_perror ("%s", dir);
138     free (sysrootdir);
139     return -1;
140   }
141   if (!S_ISDIR (statbuf.st_mode)) {
142     reply_with_error ("%s: not a directory", dir);
143     free (sysrootdir);
144     return -1;
145   }
146
147   char *cmd;
148   if (asprintf_nowarn (&cmd, "cd %Q && find -type f -print0 | xargs -0 %s",
149                        sysrootdir, program) == -1) {
150     reply_with_perror ("asprintf");
151     free (sysrootdir);
152     return -1;
153   }
154   free (sysrootdir);
155
156   if (verbose)
157     fprintf (stderr, "%s\n", cmd);
158
159   FILE *fp = popen (cmd, "r");
160   if (fp == NULL) {
161     reply_with_perror ("%s", cmd);
162     free (cmd);
163     return -1;
164   }
165   free (cmd);
166
167   /* Now we must send the reply message, before the file contents.  After
168    * this there is no opportunity in the protocol to send any error
169    * message back.  Instead we can only cancel the transfer.
170    */
171   reply (NULL, NULL);
172
173   char str[GUESTFS_MAX_CHUNK_SIZE];
174
175   while ((r = fread (str, 1, GUESTFS_MAX_CHUNK_SIZE, fp)) > 0) {
176     if (send_file_write (str, r) < 0) {
177       pclose (fp);
178       return -1;
179     }
180   }
181
182   if (ferror (fp)) {
183     perror (dir);
184     send_file_end (1);                /* Cancel. */
185     pclose (fp);
186     return -1;
187   }
188
189   if (pclose (fp) != 0) {
190     perror (dir);
191     send_file_end (1);                /* Cancel. */
192     return -1;
193   }
194
195   if (send_file_end (0))        /* Normal end of file. */
196     return -1;
197
198   return 0;
199 }