Add -f checksum mode to allow caching of appliances.
[febootstrap.git] / helper / checksum.c
1 /* febootstrap-supermin-helper reimplementation in C.
2  * Copyright (C) 2009-2010 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 <errno.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <assert.h>
29
30 #include "error.h"
31
32 #include "helper.h"
33
34 static FILE *pp = NULL;
35
36 /* This is the command we run to calculate the SHA.  Note that we sort
37  * the rows first so that the checksum is roughly stable, since the
38  * order that we output files might not be (eg. because we rely on the
39  * ordering of readdir).  Uncomment the second line to see the output
40  * before hashing.
41  */
42 static const char *shacmd = "sort | sha256sum | awk '{print $1}'";
43 //static const char *shacmd = "sort | cat";
44
45 static void
46 checksum_start (const char *hostcpu, const char *appliance,
47                 const char *modpath, const char *initrd)
48 {
49   pp = popen (shacmd, "w");
50   if (pp == NULL)
51     error (EXIT_FAILURE, errno, "popen: command failed: %s", shacmd);
52
53   fprintf (pp, "%s %s %s %d\n",
54            PACKAGE_STRING, hostcpu, modpath, geteuid ());
55 }
56
57 static void
58 checksum_end (void)
59 {
60   if (pclose (pp) == -1)
61     error (EXIT_FAILURE, errno, "pclose: command failed: %s", shacmd);
62   pp = NULL;
63 }
64
65 static void
66 checksum_file_stat (const char *filename, const struct stat *statbuf)
67 {
68   /* Publically writable directories (ie. /tmp) don't have stable
69    * times.  Since we only care about some attributes of directories
70    * in any case, we vary the output accordingly.
71    */
72   if (!S_ISDIR (statbuf->st_mode))
73     fprintf (pp, "%s %ld %ld %d %d %ld %o\n",
74              filename,
75              (long) statbuf->st_ctime, (long) statbuf->st_mtime,
76              statbuf->st_uid, statbuf->st_gid, statbuf->st_size,
77              statbuf->st_mode);
78   else
79     fprintf (pp, "%s %d %d %o\n",
80              filename,
81              statbuf->st_uid, statbuf->st_gid,
82              statbuf->st_mode);
83 }
84
85 static void
86 checksum_file (const char *filename)
87 {
88   struct stat statbuf;
89
90   if (lstat (filename, &statbuf) == -1)
91     error (EXIT_FAILURE, errno, "lstat: %s", filename);
92   checksum_file_stat (filename, &statbuf);
93 }
94
95 static void
96 checksum_fts_entry (FTSENT *entry)
97 {
98   if (entry->fts_info & FTS_NS || entry->fts_info & FTS_NSOK)
99     checksum_file (entry->fts_path);
100   else
101     checksum_file_stat (entry->fts_path, entry->fts_statp);
102 }
103
104 static void
105 checksum_cpio_file (const char *cpio_file)
106 {
107   checksum_file (cpio_file);
108 }
109
110 struct writer checksum_writer = {
111   .wr_start = checksum_start,
112   .wr_end = checksum_end,
113   .wr_file = checksum_file,
114   .wr_file_stat = checksum_file_stat,
115   .wr_fts_entry = checksum_fts_entry,
116   .wr_cpio_file = checksum_cpio_file,
117 };