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