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