• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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