]> git.proxmox.com Git - mirror_iproute2.git/blame - tc/tc.c
Use const char
[mirror_iproute2.git] / tc / tc.c
CommitLineData
aba5acdf
SH
1/*
2 * tc.c "tc" utility frontend.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10 *
11 * Fixes:
12 *
13 * Petri Mattila <petri@prihateam.fi> 990308: wrong memset's resulted in faults
14 */
15
16#include <stdio.h>
17#include <stdlib.h>
18#include <unistd.h>
19#include <syslog.h>
20#include <fcntl.h>
21#include <dlfcn.h>
22#include <sys/socket.h>
23#include <netinet/in.h>
24#include <arpa/inet.h>
25#include <string.h>
26#include <errno.h>
27
28#include "SNAPSHOT.h"
29#include "utils.h"
30#include "tc_util.h"
31#include "tc_common.h"
32
33int show_stats = 0;
34int show_details = 0;
35int show_raw = 0;
36int resolve_hosts = 0;
37
38void *BODY;
39static struct qdisc_util * qdisc_list;
40static struct filter_util * filter_list;
41
42static int print_noqopt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
43{
44 if (opt && RTA_PAYLOAD(opt))
45 fprintf(f, "[Unknown qdisc, optlen=%u] ", RTA_PAYLOAD(opt));
46 return 0;
47}
48
49static int parse_noqopt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
50{
51 if (argc) {
52 fprintf(stderr, "Unknown qdisc \"%s\", hence option \"%s\" is unparsable\n", qu->id, *argv);
53 return -1;
54 }
55 return 0;
56}
57
58static int print_nofopt(struct filter_util *qu, FILE *f, struct rtattr *opt, __u32 fhandle)
59{
60 if (opt && RTA_PAYLOAD(opt))
61 fprintf(f, "fh %08x [Unknown filter, optlen=%u] ", fhandle, RTA_PAYLOAD(opt));
62 else if (fhandle)
63 fprintf(f, "fh %08x ", fhandle);
64 return 0;
65}
66
67static int parse_nofopt(struct filter_util *qu, char *fhandle, int argc, char **argv, struct nlmsghdr *n)
68{
69 __u32 handle;
70
71 if (argc) {
72 fprintf(stderr, "Unknown filter \"%s\", hence option \"%s\" is unparsable\n", qu->id, *argv);
73 return -1;
74 }
75 if (fhandle) {
76 struct tcmsg *t = NLMSG_DATA(n);
77 if (get_u32(&handle, fhandle, 16)) {
78 fprintf(stderr, "Unparsable filter ID \"%s\"\n", fhandle);
79 return -1;
80 }
81 t->tcm_handle = handle;
82 }
83 return 0;
84}
85
86#if 0
87/* Builtin filter types */
88
89static int f_parse_noopt(struct filter_util *qu, char *fhandle, int argc, char **argv, struct nlmsghdr *n)
90{
91 if (argc || fhandle) {
92 fprintf(stderr, "Filter \"%s\" has no options.\n", qu->id);
93 return -1;
94 }
95 return 0;
96}
97#endif
98
99struct qdisc_util *get_qdisc_kind(char *str)
100{
101 void *dlh;
102 char buf[256];
103 struct qdisc_util *q;
104
105 for (q = qdisc_list; q; q = q->next)
106 if (strcmp(q->id, str) == 0)
107 return q;
108
109 snprintf(buf, sizeof(buf), "q_%s.so", str);
110 dlh = dlopen(buf, RTLD_LAZY);
111 if (dlh == NULL) {
112 dlh = BODY;
113 if (dlh == NULL) {
114 dlh = BODY = dlopen(NULL, RTLD_LAZY);
115 if (dlh == NULL)
116 goto noexist;
117 }
118 }
119
120 snprintf(buf, sizeof(buf), "%s_util", str);
121 q = dlsym(dlh, buf);
122 if (q == NULL)
123 goto noexist;
124
125reg:
126 q->next = qdisc_list;
127 qdisc_list = q;
128 return q;
129
130noexist:
131 q = malloc(sizeof(*q));
132 if (q) {
133 memset(q, 0, sizeof(*q));
134 strncpy(q->id, str, 15);
135 q->parse_qopt = parse_noqopt;
136 q->print_qopt = print_noqopt;
137 goto reg;
138 }
139 return q;
140}
141
142
143struct filter_util *get_filter_kind(char *str)
144{
145 void *dlh;
146 char buf[256];
147 struct filter_util *q;
148
149 for (q = filter_list; q; q = q->next)
150 if (strcmp(q->id, str) == 0)
151 return q;
152
153 snprintf(buf, sizeof(buf), "f_%s.so", str);
154 dlh = dlopen(buf, RTLD_LAZY);
155 if (dlh == NULL) {
156 dlh = BODY;
157 if (dlh == NULL) {
158 dlh = BODY = dlopen(NULL, RTLD_LAZY);
159 if (dlh == NULL)
160 goto noexist;
161 }
162 }
163
164 snprintf(buf, sizeof(buf), "%s_util", str);
165 q = dlsym(dlh, buf);
166 if (q == NULL)
167 goto noexist;
168
169reg:
170 q->next = filter_list;
171 filter_list = q;
172 return q;
173
174noexist:
175 q = malloc(sizeof(*q));
176 if (q) {
177 memset(q, 0, sizeof(*q));
178 strncpy(q->id, str, 15);
179 q->parse_fopt = parse_nofopt;
180 q->print_fopt = print_nofopt;
181 goto reg;
182 }
183 return q;
184}
185
186static void usage(void) __attribute__((noreturn));
187
188static void usage(void)
189{
190 fprintf(stderr, "Usage: tc [ OPTIONS ] OBJECT { COMMAND | help }\n"
191 "where OBJECT := { qdisc | class | filter }\n"
192 " OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] | -b[atch] file }\n");
193 exit(-1);
194}
195
196
197
198int main(int argc, char **argv)
199{
200 char *basename;
201
202 basename = strrchr(argv[0], '/');
203 if (basename == NULL)
204 basename = argv[0];
205 else
206 basename++;
207
208
209 /* batch mode */
210 if (argc > 1 && matches(argv[1], "-batch") == 0) {
211 FILE *batch;
212 char line[400];
213 char *largv[100];
214 int largc, ret=0;
215#define BMAXARG (sizeof(largv)/sizeof(char *)-2)
216
217 if (argc != 3) {
218 fprintf(stderr, "Wrong number of arguments in batch mode\n");
219 exit(-1);
220 }
221 if (matches(argv[2], "-") != 0) {
222 if ((batch = fopen(argv[2], "r")) == NULL) {
223 fprintf(stderr, "Cannot open file \"%s\" for reading: %s=n", argv[2], strerror(errno));
224 exit(-1);
225 }
226 } else {
227 if ((batch = fdopen(0, "r")) == NULL) {
228 fprintf(stderr, "Cannot open stdin for reading: %s=n", strerror(errno));
229 exit(-1);
230 }
231 }
232
233 tc_core_init();
234
235 while (fgets(line, sizeof(line)-1, batch)) {
236 if (line[strlen(line)-1]=='\n') {
237 line[strlen(line)-1] = '\0';
238 } else {
239 fprintf(stderr, "No newline at the end of line, looks like to long (%d chars or more)\n", strlen(line));
240 exit(-1);
241 }
242 largc = 0;
243 largv[largc]=strtok(line, " ");
244 while ((largv[++largc]=strtok(NULL, " ")) != NULL) {
245 if (largc > BMAXARG) {
246 fprintf(stderr, "Over %d arguments in batch mode, enough!\n", BMAXARG);
247 exit(-1);
248 }
249 }
250
251 if (matches(largv[0], "qdisc") == 0) {
252 ret += do_qdisc(largc-1, largv+1);
253 } else if (matches(largv[0], "class") == 0) {
254 ret += do_class(largc-1, largv+1);
255 } else if (matches(largv[0], "filter") == 0) {
256 ret += do_filter(largc-1, largv+1);
257 } else if (matches(largv[0], "help") == 0) {
258 usage(); /* note that usage() doesn't return */
259 } else {
260 fprintf(stderr, "Object \"%s\" is unknown, try \"tc help\".\n", largv[1]);
261 exit(-1);
262 }
263 }
264 fclose(batch);
265 exit(0); /* end of batch, that's all */
266 }
267
268 while (argc > 1) {
269 if (argv[1][0] != '-')
270 break;
271 if (matches(argv[1], "-stats") == 0 ||
272 matches(argv[1], "-statistics") == 0) {
273 ++show_stats;
274 } else if (matches(argv[1], "-details") == 0) {
275 ++show_details;
276 } else if (matches(argv[1], "-raw") == 0) {
277 ++show_raw;
278 } else if (matches(argv[1], "-Version") == 0) {
279 printf("tc utility, iproute2-ss%s\n", SNAPSHOT);
280 exit(0);
281 } else if (matches(argv[1], "-help") == 0) {
282 usage();
283 } else {
284 fprintf(stderr, "Option \"%s\" is unknown, try \"tc -help\".\n", argv[1]);
285 exit(-1);
286 }
287 argc--; argv++;
288 }
289
290 tc_core_init();
291
292 if (argc > 1) {
293 if (matches(argv[1], "qdisc") == 0)
294 return do_qdisc(argc-2, argv+2);
295 if (matches(argv[1], "class") == 0)
296 return do_class(argc-2, argv+2);
297 if (matches(argv[1], "filter") == 0)
298 return do_filter(argc-2, argv+2);
299 if (matches(argv[1], "help") == 0)
300 usage();
301 fprintf(stderr, "Object \"%s\" is unknown, try \"tc help\".\n", argv[1]);
302 exit(-1);
303 }
304
305 usage();
306}