418f53ea703f2971ee27ed740501fe20d65120d3
[platform/upstream/cryptsetup.git] / src / utils_tools.c
1 /*
2  * cryptsetup - setup cryptographic volumes for dm-crypt
3  *
4  * Copyright (C) 2004, Christophe Saout <christophe@saout.de>
5  * Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
6  * Copyright (C) 2009-2012, Red Hat, Inc. All rights reserved.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * version 2 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include "cryptsetup.h"
23 #include <signal.h>
24
25 int opt_verbose = 0;
26 int opt_debug = 0;
27 int opt_batch_mode = 0;
28
29 /* interrupt handling */
30 volatile int quit = 0;
31 static int signals_blocked = 0;
32
33 static void int_handler(int sig __attribute__((__unused__)))
34 {
35         quit++;
36 }
37
38 void set_int_block(int block)
39 {
40         sigset_t signals_open;
41
42         log_dbg("%slocking interruption on signal.", block ? "B" : "Unb");
43
44         sigemptyset(&signals_open);
45         sigaddset(&signals_open, SIGINT);
46         sigaddset(&signals_open, SIGTERM);
47         sigprocmask(block ? SIG_SETMASK : SIG_UNBLOCK, &signals_open, NULL);
48         signals_blocked = block;
49         quit = 0;
50 }
51
52 void set_int_handler(int block)
53 {
54         struct sigaction sigaction_open;
55
56         log_dbg("Installing SIGINT/SIGTERM handler.");
57         memset(&sigaction_open, 0, sizeof(struct sigaction));
58         sigaction_open.sa_handler = int_handler;
59         sigaction(SIGINT, &sigaction_open, 0);
60         sigaction(SIGTERM, &sigaction_open, 0);
61         set_int_block(block);
62 }
63
64 void check_signal(int *r)
65 {
66         if (quit && !*r)
67                 *r = -EINTR;
68 }
69
70 /* crypt_get_key() with signal handler */
71 int tools_get_key(const char *prompt,
72                   char **key, size_t *key_size,
73                   size_t keyfile_offset, size_t keyfile_size_max,
74                   const char *key_file,
75                   int timeout, int verify, int pwquality,
76                   struct crypt_device *cd)
77 {
78         int r, block;
79
80         block = signals_blocked;
81         if (block)
82                 set_int_block(0);
83
84         r = crypt_get_key(prompt, key, key_size, keyfile_offset,
85                           keyfile_size_max, key_file, timeout, verify, cd);
86         if (block && !quit)
87                 set_int_block(1);
88
89         return r;
90 }
91
92 __attribute__((format(printf, 5, 6)))
93 void clogger(struct crypt_device *cd, int level, const char *file, int line,
94              const char *format, ...)
95 {
96         va_list argp;
97         char *target = NULL;
98
99         va_start(argp, format);
100
101         if (vasprintf(&target, format, argp) > 0) {
102                 if (level >= 0) {
103                         crypt_log(cd, level, target);
104 #ifdef CRYPT_DEBUG
105                 } else if (opt_debug)
106                         printf("# %s:%d %s\n", file ?: "?", line, target);
107 #else
108                 } else if (opt_debug)
109                         printf("# %s\n", target);
110 #endif
111         }
112
113         va_end(argp);
114         free(target);
115 }
116
117 void tool_log(int level, const char *msg, void *usrptr __attribute__((unused)))
118 {
119         switch(level) {
120
121         case CRYPT_LOG_NORMAL:
122                 fputs(msg, stdout);
123                 break;
124         case CRYPT_LOG_VERBOSE:
125                 if (opt_verbose)
126                         fputs(msg, stdout);
127                 break;
128         case CRYPT_LOG_ERROR:
129                 fputs(msg, stderr);
130                 break;
131         case CRYPT_LOG_DEBUG:
132                 if (opt_debug)
133                         printf("# %s\n", msg);
134                 break;
135         default:
136                 fprintf(stderr, "Internal error on logging class for msg: %s", msg);
137                 break;
138         }
139 }
140
141 void quiet_log(int level, const char *msg, void *usrptr)
142 {
143         if (!opt_verbose && (level == CRYPT_LOG_ERROR || level == CRYPT_LOG_NORMAL))
144                 level = CRYPT_LOG_VERBOSE;
145         tool_log(level, msg, usrptr);
146 }
147
148 int yesDialog(const char *msg, void *usrptr __attribute__((unused)))
149 {
150         char *answer = NULL;
151         size_t size = 0;
152         int r = 1, block;
153
154         block = signals_blocked;
155         if (block)
156                 set_int_block(0);
157
158         if(isatty(STDIN_FILENO) && !opt_batch_mode) {
159                 log_std("\nWARNING!\n========\n");
160                 log_std("%s\n\nAre you sure? (Type uppercase yes): ", msg);
161                 if(getline(&answer, &size, stdin) == -1) {
162                         r = 0;
163                         /* Aborted by signal */
164                         if (!quit)
165                                 log_err(_("Error reading response from terminal.\n"));
166                         else
167                                 log_dbg("Query interrupted on signal.");
168                 } else if(strcmp(answer, "YES\n"))
169                         r = 0;
170         }
171
172         if (block && !quit)
173                 set_int_block(1);
174
175         free(answer);
176         return r;
177 }
178
179 void show_status(int errcode)
180 {
181         char error[256], *error_;
182
183         if(!opt_verbose)
184                 return;
185
186         if(!errcode) {
187                 log_std(_("Command successful.\n"));
188                 return;
189         }
190
191         crypt_get_error(error, sizeof(error));
192
193         if (!error[0]) {
194                 error_ = strerror_r(-errcode, error, sizeof(error));
195                 if (error_ != error) {
196                         strncpy(error, error_, sizeof(error));
197                         error[sizeof(error) - 1] = '\0';
198                 }
199         }
200
201         log_err(_("Command failed with code %i"), -errcode);
202         if (*error)
203                 log_err(": %s\n", error);
204         else
205                 log_err(".\n");
206 }
207
208 const char *uuid_or_device(const char *spec)
209 {
210         static char device[PATH_MAX];
211         char s, *ptr;
212         int i = 0, uuid_len = 5;
213
214         /* Check if it is correct UUID=<LUKS_UUID> format */
215         if (spec && !strncmp(spec, "UUID=", uuid_len)) {
216                 strcpy(device, "/dev/disk/by-uuid/");
217                 ptr = &device[strlen(device)];
218                 i = uuid_len;
219                 while ((s = spec[i++]) && i < PATH_MAX) {
220                         if (!isxdigit(s) && s != '-')
221                                 return spec; /* Bail it out */
222                         if (isalpha(s))
223                                 s = tolower(s);
224                         *ptr++ = s;
225                 }
226                 *ptr = '\0';
227                 return device;
228         }
229
230         return spec;
231 }
232
233 __attribute__ ((noreturn)) void usage(poptContext popt_context,
234                                              int exitcode, const char *error,
235                                              const char *more)
236 {
237         poptPrintUsage(popt_context, stderr, 0);
238         if (error)
239                 log_err("%s: %s\n", more, error);
240         poptFreeContext(popt_context);
241         exit(exitcode);
242 }
243
244 void dbg_version_and_cmd(int argc, const char **argv)
245 {
246         int i;
247
248         log_std("# %s %s processing \"", PACKAGE_NAME, PACKAGE_VERSION);
249         for (i = 0; i < argc; i++) {
250                 if (i)
251                         log_std(" ");
252                 log_std("%s", argv[i]);
253         }
254         log_std("\"\n");
255 }
256
257 /* Translate exit code to simple codes */
258 int translate_errno(int r)
259 {
260         switch (r) {
261         case 0:         r = EXIT_SUCCESS; break;
262         case -EEXIST:
263         case -EBUSY:    r = 5; break;
264         case -ENOTBLK:
265         case -ENODEV:   r = 4; break;
266         case -ENOMEM:   r = 3; break;
267         case -EPERM:    r = 2; break;
268         case -EINVAL:
269         case -ENOENT:
270         case -ENOSYS:
271         default:        r = EXIT_FAILURE;
272         }
273         return r;
274 }