helper: Ignore times of special files when calculating checksum.
[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) and special files
69    * don't have stable times.  Since we only care about some
70    * attributes of directories and special files, we vary the output
71    * accordingly.
72    */
73   if (S_ISREG (statbuf->st_mode))
74     fprintf (pp, "%s %ld %ld %d %d %ld %o\n",
75              filename,
76              (long) statbuf->st_ctime, (long) statbuf->st_mtime,
77              statbuf->st_uid, statbuf->st_gid, statbuf->st_size,
78              statbuf->st_mode);
79   else
80     fprintf (pp, "%s %d %d %o\n",
81              filename,
82              statbuf->st_uid, statbuf->st_gid,
83              statbuf->st_mode);
84 }
85
86 static void
87 checksum_file (const char *filename)
88 {
89   struct stat statbuf;
90
91   if (lstat (filename, &statbuf) == -1)
92     error (EXIT_FAILURE, errno, "lstat: %s", filename);
93   checksum_file_stat (filename, &statbuf);
94 }
95
96 static void
97 checksum_fts_entry (FTSENT *entry)
98 {
99   if (entry->fts_info & FTS_NS || entry->fts_info & FTS_NSOK)
100     checksum_file (entry->fts_path);
101   else
102     checksum_file_stat (entry->fts_path, entry->fts_statp);
103 }
104
105 static void
106 checksum_cpio_file (const char *cpio_file)
107 {
108   checksum_file (cpio_file);
109 }
110
111 struct writer checksum_writer = {
112   .wr_start = checksum_start,
113   .wr_end = checksum_end,
114   .wr_file = checksum_file,
115   .wr_file_stat = checksum_file_stat,
116   .wr_fts_entry = checksum_fts_entry,
117   .wr_cpio_file = checksum_cpio_file,
118 };