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