Imported Upstream version 2.6.1
[platform/upstream/cryptsetup.git] / src / utils_args.c
1 /*
2  * Command line arguments parsing helpers
3  *
4  * Copyright (C) 2020-2023 Red Hat, Inc. All rights reserved.
5  * Copyright (C) 2020-2023 Ondrej Kozina
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
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
24 void tools_parse_arg_value(poptContext popt_context, crypt_arg_type_info type, struct tools_arg *arg, const char *popt_arg, int popt_val, bool(*needs_size_conv_fn)(unsigned arg_id))
25 {
26         char *end, msg[128];
27         long long int ll;
28         long long unsigned int ull;
29
30         errno = 0;
31
32         switch (type) {
33         case CRYPT_ARG_BOOL:
34                 break;
35         case CRYPT_ARG_STRING:
36                 if (arg->set)
37                         free(arg->u.str_value);
38                 arg->u.str_value = poptGetOptArg(popt_context);
39                 break;
40         case CRYPT_ARG_INT32:
41                 ll = strtoll(popt_arg, &end, 10);
42                 if (*end || !*popt_arg || ll > INT32_MAX || ll < INT32_MIN || errno == ERANGE)
43                         usage(popt_context, EXIT_FAILURE, poptStrerror(POPT_ERROR_BADNUMBER),
44                               poptGetInvocationName(popt_context));
45                 arg->u.i32_value = (int32_t)ll;
46                 break;
47         case CRYPT_ARG_UINT32:
48                 ull = strtoull(popt_arg, &end, 10);
49                 if (*end || !*popt_arg || ull > UINT32_MAX || errno == ERANGE)
50                         usage(popt_context, EXIT_FAILURE, poptStrerror(POPT_ERROR_BADNUMBER),
51                               poptGetInvocationName(popt_context));
52                 arg->u.u32_value = (uint32_t)ull;
53                 break;
54         case CRYPT_ARG_INT64:
55                 ll = strtoll(popt_arg, &end, 10);
56                 if (*end || !*popt_arg || errno == ERANGE)
57                         usage(popt_context, EXIT_FAILURE, poptStrerror(POPT_ERROR_BADNUMBER),
58                               poptGetInvocationName(popt_context));
59                 arg->u.i64_value = ll;
60                 break;
61         case CRYPT_ARG_UINT64:
62                 /* special size strings with units converted to integers */
63                 if (needs_size_conv_fn && needs_size_conv_fn(popt_val)) {
64                         if (tools_string_to_size(popt_arg, &arg->u.u64_value)) {
65                                 if (snprintf(msg, sizeof(msg), _("Invalid size specification in parameter --%s."), arg->name) < 0)
66                                         msg[0] = '\0';
67                                 usage(popt_context, EXIT_FAILURE, msg,
68                                       poptGetInvocationName(popt_context));
69                         }
70                 } else {
71                         ull = strtoull(popt_arg, &end, 10);
72                         if (*end || !*popt_arg || errno == ERANGE)
73                                 usage(popt_context, EXIT_FAILURE, poptStrerror(POPT_ERROR_BADNUMBER),
74                                       poptGetInvocationName(popt_context));
75                         arg->u.u64_value = ull;
76                 }
77                 break;
78         case CRYPT_ARG_ALIAS:
79                 tools_parse_arg_value(popt_context, arg->u.o.ptr->type, arg->u.o.ptr, popt_arg, arg->u.o.id, needs_size_conv_fn);
80                 break;
81         default:
82                 /* this signals internal tools coding mistake */
83                 abort();
84         }
85
86         arg->set = true;
87 }
88
89 void tools_args_free(struct tools_arg *args, size_t args_size)
90 {
91         size_t i;
92
93         for (i = 0; i < args_size; i++) {
94                 if (args[i].set && args[i].type == CRYPT_ARG_STRING)
95                         free(args[i].u.str_value);
96                 args[i].set = false;
97         }
98 }
99
100 static bool action_allowed(const char *action, const char * const* list, size_t list_size)
101 {
102         size_t i;
103
104         if (!list[0])
105                 return true;
106
107         for (i = 0; i < list_size && list[i]; i++) {
108                 if (!strcmp(action, list[i]))
109                         return true;
110         }
111
112         return false;
113 }
114
115 void tools_check_args(const char *action, const struct tools_arg *args, size_t args_size, poptContext popt_context)
116 {
117         size_t i;
118         char msg[256];
119
120         for (i = 1; i < args_size; i++) {
121                 if (args[i].set) {
122                         if (action_allowed(action, args[i].actions_array, MAX_ACTIONS)) {
123                                 continue;
124                         } else {
125                                 if (snprintf(msg, sizeof(msg), _("Option --%s is not allowed with %s action."), args[i].name, action) < 0)
126                                         msg[0] = '\0';
127                                 usage(popt_context, EXIT_FAILURE, msg, poptGetInvocationName(popt_context));
128                         }
129                 }
130         }
131 }