1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3 * src/utils.c Utilities
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation version 2.1
8 * of the License.
9 *
10 * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch>
11 */
12
13 /**
14 * @defgroup cli Command Line Interface API
15 *
16 * @{
17 *
18 * These modules provide an interface for text based applications. The
19 * functions provided are wrappers for their libnl equivalent with
20 * added error handling. The functions check for allocation failures,
21 * invalid input, and unknown types and will print error messages
22 * accordingly via nl_cli_fatal().
23 */
24
25 #include <netlink/cli/utils.h>
26 #include <locale.h>
27
28 #include "lib/defs.h"
29
30 #ifdef HAVE_DLFCN_H
31 #include <dlfcn.h>
32 #endif
33
34 /**
35 * Parse a text based 32 bit unsigned integer argument
36 * @arg arg Integer in text form.
37 *
38 * Tries to convert the number provided in arg to a uint32_t. Will call
39 * nl_cli_fatal() if the conversion fails.
40 *
41 * @return 32bit unsigned integer.
42 */
nl_cli_parse_u32(const char * arg)43 uint32_t nl_cli_parse_u32(const char *arg)
44 {
45 unsigned long lval;
46 char *endptr;
47
48 lval = strtoul(arg, &endptr, 0);
49 if (endptr == arg || lval == ULONG_MAX)
50 nl_cli_fatal(EINVAL, "Unable to parse \"%s\", not a number.",
51 arg);
52
53 return (uint32_t) lval;
54 }
55
nl_cli_print_version(void)56 void nl_cli_print_version(void)
57 {
58 printf("libnl tools version %s\n", LIBNL_VERSION);
59 printf(
60 "Copyright (C) 2003-2010 Thomas Graf <tgraf@redhat.com>\n"
61 "\n"
62 "This program comes with ABSOLUTELY NO WARRANTY. This is free \n"
63 "software, and you are welcome to redistribute it under certain\n"
64 "conditions. See the GNU General Public License for details.\n"
65 );
66
67 exit(0);
68 }
69
70 /**
71 * Print error message and quit application
72 * @arg err Error code.
73 * @arg fmt Error message.
74 *
75 * Prints the formatted error message to stderr and quits the application
76 * using the provided error code.
77 */
nl_cli_fatal(int err,const char * fmt,...)78 void nl_cli_fatal(int err, const char *fmt, ...)
79 {
80 va_list ap;
81
82 fprintf(stderr, "Error: ");
83
84 if (fmt) {
85 va_start(ap, fmt);
86 vfprintf(stderr, fmt, ap);
87 va_end(ap);
88 fprintf(stderr, "\n");
89 } else {
90 char *buf;
91 #ifdef HAVE_STRERROR_L
92 locale_t loc = newlocale(LC_MESSAGES_MASK, "", (locale_t)0);
93 if (loc == (locale_t)0) {
94 if (errno == ENOENT)
95 loc = newlocale(LC_MESSAGES_MASK,
96 "POSIX", (locale_t)0);
97 if (loc == (locale_t)0)
98 buf = "newlocale() failed";
99 }
100 if (loc != (locale_t)0)
101 buf = strerror_l(err, loc);
102 #else
103 buf = strerror(err);
104 #endif
105 fprintf(stderr, "%s\n", buf);
106 #ifdef HAVE_STRERROR_L
107 if (loc != (locale_t)0)
108 freelocale(loc);
109 #endif
110 }
111
112 exit(abs(err));
113 }
114
nl_cli_connect(struct nl_sock * sk,int protocol)115 int nl_cli_connect(struct nl_sock *sk, int protocol)
116 {
117 int err;
118
119 if ((err = nl_connect(sk, protocol)) < 0)
120 nl_cli_fatal(err, "Unable to connect netlink socket: %s",
121 nl_geterror(err));
122
123 return err;
124 }
125
nl_cli_alloc_socket(void)126 struct nl_sock *nl_cli_alloc_socket(void)
127 {
128 struct nl_sock *sock;
129
130 if (!(sock = nl_socket_alloc()))
131 nl_cli_fatal(ENOBUFS, "Unable to allocate netlink socket");
132
133 return sock;
134 }
135
nl_cli_addr_parse(const char * str,int family)136 struct nl_addr *nl_cli_addr_parse(const char *str, int family)
137 {
138 struct nl_addr *addr;
139 int err;
140
141 if ((err = nl_addr_parse(str, family, &addr)) < 0)
142 nl_cli_fatal(err, "Unable to parse address \"%s\": %s",
143 str, nl_geterror(err));
144
145 return addr;
146 }
147
nl_cli_parse_dumptype(const char * str)148 int nl_cli_parse_dumptype(const char *str)
149 {
150 if (!strcasecmp(str, "brief"))
151 return NL_DUMP_LINE;
152 else if (!strcasecmp(str, "details") || !strcasecmp(str, "detailed"))
153 return NL_DUMP_DETAILS;
154 else if (!strcasecmp(str, "stats"))
155 return NL_DUMP_STATS;
156 else
157 nl_cli_fatal(EINVAL, "Invalid dump type \"%s\".\n", str);
158
159 return 0;
160 }
161
nl_cli_confirm(struct nl_object * obj,struct nl_dump_params * params,int default_yes)162 int nl_cli_confirm(struct nl_object *obj, struct nl_dump_params *params,
163 int default_yes)
164 {
165 nl_object_dump(obj, params);
166
167 for (;;) {
168 char buf[32] = { 0 };
169 int answer;
170
171 printf("Delete? (%c/%c) ",
172 default_yes ? 'Y' : 'y',
173 default_yes ? 'n' : 'N');
174
175 if (!fgets(buf, sizeof(buf), stdin)) {
176 fprintf(stderr, "Error while reading\n.");
177 continue;
178 }
179
180 switch ((answer = tolower(buf[0]))) {
181 case '\n':
182 answer = default_yes ? 'y' : 'n';
183 /* fall through */
184 case 'y':
185 case 'n':
186 return answer == 'y';
187 }
188
189 fprintf(stderr, "Invalid input, try again.\n");
190 }
191
192 return 0;
193
194 }
195
nl_cli_alloc_cache(struct nl_sock * sock,const char * name,int (* ac)(struct nl_sock *,struct nl_cache **))196 struct nl_cache *nl_cli_alloc_cache(struct nl_sock *sock, const char *name,
197 int (*ac)(struct nl_sock *, struct nl_cache **))
198 {
199 struct nl_cache *cache;
200 int err;
201
202 if ((err = ac(sock, &cache)) < 0)
203 nl_cli_fatal(err, "Unable to allocate %s cache: %s",
204 name, nl_geterror(err));
205
206 nl_cache_mngt_provide(cache);
207
208 return cache;
209 }
210
nl_cli_alloc_cache_flags(struct nl_sock * sock,const char * name,unsigned int flags,int (* ac)(struct nl_sock *,struct nl_cache **,unsigned int))211 struct nl_cache *nl_cli_alloc_cache_flags(struct nl_sock *sock,
212 const char *name, unsigned int flags,
213 int (*ac)(struct nl_sock *, struct nl_cache **,
214 unsigned int))
215 {
216 struct nl_cache *cache;
217 int err;
218
219 if ((err = ac(sock, &cache, flags)) < 0)
220 nl_cli_fatal(err, "Unable to allocate %s cache: %s",
221 name, nl_geterror(err));
222
223 nl_cache_mngt_provide(cache);
224
225 return cache;
226 }
227
nl_cli_load_module(const char * prefix,const char * name)228 void nl_cli_load_module(const char *prefix, const char *name)
229 {
230 char path[FILENAME_MAX+1];
231
232 snprintf(path, sizeof(path), "%s/%s/%s.so",
233 PKGLIBDIR, prefix, name);
234
235 #ifdef HAVE_DLFCN_H
236 {
237 void *handle;
238
239 if (!(handle = dlopen(path, RTLD_NOW))) {
240 nl_cli_fatal(ENOENT, "Unable to load module \"%s\": %s\n",
241 path, dlerror());
242 }
243 }
244 #else
245 nl_cli_fatal(ENOTSUP, "Unable to load module \"%s\": built without dynamic libraries support\n",
246 path);
247 #endif
248 }
249
250 /** @} */
251