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