g13: Add commands --suspend and --remove.
[gnupg.git] / g13 / sh-blockdev.c
1 /* sh-blockdev.c - Block device functions for g13-syshelp
2  * Copyright (C) 2015 Werner Koch
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdarg.h>
25 #include <errno.h>
26 #include <assert.h>
27 #include <limits.h>
28
29 #include "g13-syshelp.h"
30 #include <assuan.h>
31 #include "i18n.h"
32 #include "exectool.h"
33 #include "keyblob.h"
34
35 #ifndef HAVE_STRTOULL
36 # error building this tool requires strtoull(3)
37 #endif
38 #ifndef ULLONG_MAX
39 # error ULLONG_MAX missing
40 #endif
41
42
43 /* Return the size measured in the number of 512 byte sectors for the
44    block device NAME.  */
45 gpg_error_t
46 sh_blockdev_getsz (const char *name, unsigned long long *r_nblocks)
47 {
48   gpg_error_t err;
49   const char *argv[3];
50   char *result;
51
52   *r_nblocks = 0;
53   argv[0] = "--getsz";
54   argv[1] = name;
55   argv[2] = NULL;
56   err = gnupg_exec_tool ("/sbin/blockdev", argv, NULL, &result, NULL);
57   if (!err)
58     {
59       gpg_err_set_errno (0);
60       *r_nblocks = strtoull (result, NULL, 10);
61       if (*r_nblocks == ULLONG_MAX && errno)
62         {
63           err = gpg_error_from_syserror ();
64           *r_nblocks = 0;
65         }
66       xfree (result);
67     }
68   return err;
69 }
70
71
72 /* Return 0 if the device NAME looks like an empty partition. */
73 gpg_error_t
74 sh_is_empty_partition (const char *name)
75 {
76   gpg_error_t err;
77   const char *argv[6];
78   char *buffer;
79   estream_t fp;
80   char *p;
81   size_t nread;
82
83   argv[0] = "-o";
84   argv[1] = "value";
85   argv[2] = "-s";
86   argv[3] = "UUID";
87   argv[4] = name;
88   argv[5] = NULL;
89   err = gnupg_exec_tool ("/sbin/blkid", argv, NULL, &buffer, NULL);
90   if (err)
91     return gpg_error (GPG_ERR_FALSE);
92   if (*buffer)
93     {
94       /* There seems to be an UUID - thus we have a file system.  */
95       xfree (buffer);
96       return gpg_error (GPG_ERR_FALSE);
97     }
98   xfree (buffer);
99
100   argv[0] = "-o";
101   argv[1] = "value";
102   argv[2] = "-s";
103   argv[3] = "PARTUUID";
104   argv[4] = name;
105   argv[5] = NULL;
106   err = gnupg_exec_tool ("/sbin/blkid", argv, NULL, &buffer, NULL);
107   if (err)
108     return gpg_error (GPG_ERR_FALSE);
109   if (!*buffer)
110     {
111       /* If there is no PARTUUID we assume that name has already a
112          mapped partition.  */
113       xfree (buffer);
114       return gpg_error (GPG_ERR_FALSE);
115     }
116   xfree (buffer);
117
118   /* As a safeguard we require that the first 32k of a partition are
119      all zero before we assume the partition is empty.  */
120   buffer = xtrymalloc (32 * 1024);
121   if (!buffer)
122     return gpg_error_from_syserror ();
123   fp = es_fopen (name, "rb,samethread");
124   if (!fp)
125     {
126       err = gpg_error_from_syserror ();
127       log_error ("error opening '%s': %s\n", name, gpg_strerror (err));
128       xfree (buffer);
129       return gpg_error (GPG_ERR_FALSE);
130     }
131   if (es_read (fp, buffer, 32 * 1024, &nread))
132     err = gpg_error_from_syserror ();
133   else if (nread != 32 *1024)
134     err = gpg_error (GPG_ERR_TOO_SHORT);
135   else
136     err = 0;
137   es_fclose (fp);
138   if (err)
139     {
140       log_error ("error reading the first 32 KiB from '%s': %s\n",
141                  name, gpg_strerror (err));
142       xfree (buffer);
143       return err;
144     }
145   for (p=buffer; nread && !*p; nread--, p++)
146     ;
147   xfree (buffer);
148   if (nread)
149     return gpg_error (GPG_ERR_FALSE);  /* No all zeroes.  */
150
151   return 0;
152 }