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