Move signal handling into common utils code.
[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
32 static void int_handler(int sig __attribute__((__unused__)))
33 {
34         quit++;
35 }
36
37 void set_int_block(int block)
38 {
39         sigset_t signals_open;
40
41         sigemptyset(&signals_open);
42         sigaddset(&signals_open, SIGINT);
43         sigaddset(&signals_open, SIGTERM);
44         sigprocmask(block ? SIG_SETMASK : SIG_UNBLOCK, &signals_open, NULL);
45 }
46
47 void set_int_handler(void)
48 {
49         struct sigaction sigaction_open;
50
51         memset(&sigaction_open, 0, sizeof(struct sigaction));
52         sigaction_open.sa_handler = int_handler;
53         sigaction(SIGINT, &sigaction_open, 0);
54         sigaction(SIGTERM, &sigaction_open, 0);
55         set_int_block(0);
56 }
57
58 __attribute__((format(printf, 5, 6)))
59 void clogger(struct crypt_device *cd, int level, const char *file, int line,
60              const char *format, ...)
61 {
62         va_list argp;
63         char *target = NULL;
64
65         va_start(argp, format);
66
67         if (vasprintf(&target, format, argp) > 0) {
68                 if (level >= 0) {
69                         crypt_log(cd, level, target);
70 #ifdef CRYPT_DEBUG
71                 } else if (opt_debug)
72                         printf("# %s:%d %s\n", file ?: "?", line, target);
73 #else
74                 } else if (opt_debug)
75                         printf("# %s\n", target);
76 #endif
77         }
78
79         va_end(argp);
80         free(target);
81 }
82
83 void tool_log(int level, const char *msg, void *usrptr __attribute__((unused)))
84 {
85         switch(level) {
86
87         case CRYPT_LOG_NORMAL:
88                 fputs(msg, stdout);
89                 break;
90         case CRYPT_LOG_VERBOSE:
91                 if (opt_verbose)
92                         fputs(msg, stdout);
93                 break;
94         case CRYPT_LOG_ERROR:
95                 fputs(msg, stderr);
96                 break;
97         case CRYPT_LOG_DEBUG:
98                 if (opt_debug)
99                         printf("# %s\n", msg);
100                 break;
101         default:
102                 fprintf(stderr, "Internal error on logging class for msg: %s", msg);
103                 break;
104         }
105 }
106
107 void quiet_log(int level, const char *msg, void *usrptr)
108 {
109         if (!opt_verbose && (level == CRYPT_LOG_ERROR || level == CRYPT_LOG_NORMAL))
110                 level = CRYPT_LOG_VERBOSE;
111         tool_log(level, msg, usrptr);
112 }
113
114 int yesDialog(const char *msg, void *usrptr __attribute__((unused)))
115 {
116         char *answer = NULL;
117         size_t size = 0;
118         int r = 1;
119
120         if(isatty(STDIN_FILENO) && !opt_batch_mode) {
121                 log_std("\nWARNING!\n========\n");
122                 log_std("%s\n\nAre you sure? (Type uppercase yes): ", msg);
123                 if(getline(&answer, &size, stdin) == -1) {
124                         perror("getline");
125                         free(answer);
126                         return 0;
127                 }
128                 if(strcmp(answer, "YES\n"))
129                         r = 0;
130                 free(answer);
131         }
132
133         return r;
134 }
135
136 void show_status(int errcode)
137 {
138         char error[256], *error_;
139
140         if(!opt_verbose)
141                 return;
142
143         if(!errcode) {
144                 log_std(_("Command successful.\n"));
145                 return;
146         }
147
148         crypt_get_error(error, sizeof(error));
149
150         if (!error[0]) {
151                 error_ = strerror_r(-errcode, error, sizeof(error));
152                 if (error_ != error) {
153                         strncpy(error, error_, sizeof(error));
154                         error[sizeof(error) - 1] = '\0';
155                 }
156         }
157
158         log_err(_("Command failed with code %i"), -errcode);
159         if (*error)
160                 log_err(": %s\n", error);
161         else
162                 log_err(".\n");
163 }
164
165 const char *uuid_or_device(const char *spec)
166 {
167         static char device[PATH_MAX];
168         char s, *ptr;
169         int i = 0, uuid_len = 5;
170
171         /* Check if it is correct UUID=<LUKS_UUID> format */
172         if (spec && !strncmp(spec, "UUID=", uuid_len)) {
173                 strcpy(device, "/dev/disk/by-uuid/");
174                 ptr = &device[strlen(device)];
175                 i = uuid_len;
176                 while ((s = spec[i++]) && i < PATH_MAX) {
177                         if (!isxdigit(s) && s != '-')
178                                 return spec; /* Bail it out */
179                         if (isalpha(s))
180                                 s = tolower(s);
181                         *ptr++ = s;
182                 }
183                 *ptr = '\0';
184                 return device;
185         }
186
187         return spec;
188 }
189
190 __attribute__ ((noreturn)) void usage(poptContext popt_context,
191                                              int exitcode, const char *error,
192                                              const char *more)
193 {
194         poptPrintUsage(popt_context, stderr, 0);
195         if (error)
196                 log_err("%s: %s\n", more, error);
197         poptFreeContext(popt_context);
198         exit(exitcode);
199 }
200
201 void dbg_version_and_cmd(int argc, const char **argv)
202 {
203         int i;
204
205         log_std("# %s %s processing \"", PACKAGE_NAME, PACKAGE_VERSION);
206         for (i = 0; i < argc; i++) {
207                 if (i)
208                         log_std(" ");
209                 log_std("%s", argv[i]);
210         }
211         log_std("\"\n");
212 }
213
214 /* Translate exit code to simple codes */
215 int translate_errno(int r)
216 {
217         switch (r) {
218         case 0:         r = EXIT_SUCCESS; break;
219         case -EEXIST:
220         case -EBUSY:    r = 5; break;
221         case -ENOTBLK:
222         case -ENODEV:   r = 4; break;
223         case -ENOMEM:   r = 3; break;
224         case -EPERM:    r = 2; break;
225         case -EINVAL:
226         case -ENOENT:
227         case -ENOSYS:
228         default:        r = EXIT_FAILURE;
229         }
230         return r;
231 }