ip.c revision 7397944de6c11519a5951fc1bcff20225e71c4bd
1/* 2 * ip.c "ip" 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 12#include <stdio.h> 13#include <stdlib.h> 14#include <unistd.h> 15#include <syslog.h> 16#include <fcntl.h> 17#include <sys/socket.h> 18#include <netinet/in.h> 19#include <string.h> 20#include <errno.h> 21 22#include "SNAPSHOT.h" 23#include "utils.h" 24#include "ip_common.h" 25 26int preferred_family = AF_UNSPEC; 27int show_stats = 0; 28int show_details = 0; 29int resolve_hosts = 0; 30int oneline = 0; 31int timestamp = 0; 32char * _SL_ = NULL; 33char *batch_file = NULL; 34int force = 0; 35int max_flush_loops = 10; 36 37struct rtnl_handle rth = { .fd = -1 }; 38 39static void usage(void) __attribute__((noreturn)); 40 41static void usage(void) 42{ 43 fprintf(stderr, 44"Usage: ip [ OPTIONS ] OBJECT { COMMAND | help }\n" 45" ip [ -force ] -batch filename\n" 46"where OBJECT := { link | addr | addrlabel | route | rule | neigh | ntable |\n" 47" tunnel | tuntap | maddr | mroute | mrule | monitor | xfrm |\n" 48" netns }\n" 49" OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n" 50" -f[amily] { inet | inet6 | ipx | dnet | link } |\n" 51" -l[oops] { maximum-addr-flush-attempts } |\n" 52" -o[neline] | -t[imestamp] | -b[atch] [filename] |\n" 53" -rc[vbuf] [size]}\n"); 54 exit(-1); 55} 56 57static int do_help(int argc, char **argv) 58{ 59 usage(); 60} 61 62static const struct cmd { 63 const char *cmd; 64 int (*func)(int argc, char **argv); 65} cmds[] = { 66 { "address", do_ipaddr }, 67 { "addrlabel", do_ipaddrlabel }, 68 { "maddress", do_multiaddr }, 69 { "route", do_iproute }, 70 { "rule", do_iprule }, 71 { "neighbor", do_ipneigh }, 72 { "neighbour", do_ipneigh }, 73 { "ntable", do_ipntable }, 74 { "ntbl", do_ipntable }, 75 { "link", do_iplink }, 76 { "tunnel", do_iptunnel }, 77 { "tunl", do_iptunnel }, 78 { "tuntap", do_iptuntap }, 79 { "tap", do_iptuntap }, 80 { "monitor", do_ipmonitor }, 81 { "xfrm", do_xfrm }, 82 { "mroute", do_multiroute }, 83 { "mrule", do_multirule }, 84 { "netns", do_netns }, 85 { "help", do_help }, 86 { 0 } 87}; 88 89static int do_cmd(const char *argv0, int argc, char **argv) 90{ 91 const struct cmd *c; 92 93 for (c = cmds; c->cmd; ++c) { 94 if (matches(argv0, c->cmd) == 0) { 95 return -(c->func(argc-1, argv+1)); 96 } 97 } 98 99 fprintf(stderr, "Object \"%s\" is unknown, try \"ip help\".\n", argv0); 100 return EXIT_FAILURE; 101} 102 103static int batch(const char *name) 104{ 105 char *line = NULL; 106 size_t len = 0; 107 int ret = EXIT_SUCCESS; 108 109 if (name && strcmp(name, "-") != 0) { 110 if (freopen(name, "r", stdin) == NULL) { 111 fprintf(stderr, "Cannot open file \"%s\" for reading: %s\n", 112 name, strerror(errno)); 113 return EXIT_FAILURE; 114 } 115 } 116 117 if (rtnl_open(&rth, 0) < 0) { 118 fprintf(stderr, "Cannot open rtnetlink\n"); 119 return EXIT_FAILURE; 120 } 121 122 cmdlineno = 0; 123 while (getcmdline(&line, &len, stdin) != -1) { 124 char *largv[100]; 125 int largc; 126 127 largc = makeargs(line, largv, 100); 128 if (largc == 0) 129 continue; /* blank line */ 130 131 if (do_cmd(largv[0], largc, largv)) { 132 fprintf(stderr, "Command failed %s:%d\n", name, cmdlineno); 133 ret = EXIT_FAILURE; 134 if (!force) 135 break; 136 } 137 } 138 if (line) 139 free(line); 140 141 rtnl_close(&rth); 142 return ret; 143} 144 145 146int main(int argc, char **argv) 147{ 148 char *basename; 149 150 basename = strrchr(argv[0], '/'); 151 if (basename == NULL) 152 basename = argv[0]; 153 else 154 basename++; 155 156 while (argc > 1) { 157 char *opt = argv[1]; 158 if (strcmp(opt,"--") == 0) { 159 argc--; argv++; 160 break; 161 } 162 if (opt[0] != '-') 163 break; 164 if (opt[1] == '-') 165 opt++; 166 if (matches(opt, "-loops") == 0) { 167 argc--; 168 argv++; 169 if (argc <= 1) 170 usage(); 171 max_flush_loops = atoi(argv[1]); 172 } else if (matches(opt, "-family") == 0) { 173 argc--; 174 argv++; 175 if (argc <= 1) 176 usage(); 177 if (strcmp(argv[1], "inet") == 0) 178 preferred_family = AF_INET; 179 else if (strcmp(argv[1], "inet6") == 0) 180 preferred_family = AF_INET6; 181 else if (strcmp(argv[1], "dnet") == 0) 182 preferred_family = AF_DECnet; 183 else if (strcmp(argv[1], "link") == 0) 184 preferred_family = AF_PACKET; 185 else if (strcmp(argv[1], "ipx") == 0) 186 preferred_family = AF_IPX; 187 else if (strcmp(argv[1], "help") == 0) 188 usage(); 189 else 190 invarg(argv[1], "invalid protocol family"); 191 } else if (strcmp(opt, "-4") == 0) { 192 preferred_family = AF_INET; 193 } else if (strcmp(opt, "-6") == 0) { 194 preferred_family = AF_INET6; 195 } else if (strcmp(opt, "-0") == 0) { 196 preferred_family = AF_PACKET; 197 } else if (strcmp(opt, "-I") == 0) { 198 preferred_family = AF_IPX; 199 } else if (strcmp(opt, "-D") == 0) { 200 preferred_family = AF_DECnet; 201 } else if (matches(opt, "-stats") == 0 || 202 matches(opt, "-statistics") == 0) { 203 ++show_stats; 204 } else if (matches(opt, "-details") == 0) { 205 ++show_details; 206 } else if (matches(opt, "-resolve") == 0) { 207 ++resolve_hosts; 208 } else if (matches(opt, "-oneline") == 0) { 209 ++oneline; 210 } else if (matches(opt, "-timestamp") == 0) { 211 ++timestamp; 212#if 0 213 } else if (matches(opt, "-numeric") == 0) { 214 rtnl_names_numeric++; 215#endif 216 } else if (matches(opt, "-Version") == 0) { 217 printf("ip utility, iproute2-ss%s\n", SNAPSHOT); 218 exit(0); 219 } else if (matches(opt, "-force") == 0) { 220 ++force; 221 } else if (matches(opt, "-batch") == 0) { 222 argc--; 223 argv++; 224 if (argc <= 1) 225 usage(); 226 batch_file = argv[1]; 227 } else if (matches(opt, "-rcvbuf") == 0) { 228 unsigned int size; 229 230 argc--; 231 argv++; 232 if (argc <= 1) 233 usage(); 234 if (get_unsigned(&size, argv[1], 0)) { 235 fprintf(stderr, "Invalid rcvbuf size '%s'\n", 236 argv[1]); 237 exit(-1); 238 } 239 rcvbuf = size; 240 } else if (matches(opt, "-help") == 0) { 241 usage(); 242 } else { 243 fprintf(stderr, "Option \"%s\" is unknown, try \"ip -help\".\n", opt); 244 exit(-1); 245 } 246 argc--; argv++; 247 } 248 249 _SL_ = oneline ? "\\" : "\n" ; 250 251 if (batch_file) 252 return batch(batch_file); 253 254 if (rtnl_open(&rth, 0) < 0) 255 exit(1); 256 257 if (strlen(basename) > 2) 258 return do_cmd(basename+2, argc, argv); 259 260 if (argc > 1) 261 return do_cmd(argv[1], argc-1, argv+1); 262 263 rtnl_close(&rth); 264 usage(); 265} 266