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 (at) 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 #include "namespace.h" 26 #include "color.h" 27 28 int preferred_family = AF_UNSPEC; 29 int human_readable; 30 int use_iec; 31 int show_stats; 32 int show_details; 33 int resolve_hosts; 34 int oneline; 35 int brief; 36 int timestamp; 37 const char *_SL_; 38 int force; 39 int max_flush_loops = 10; 40 int batch_mode; 41 bool do_all; 42 43 struct rtnl_handle rth = { .fd = -1 }; 44 45 static void usage(void) __attribute__((noreturn)); 46 47 static void usage(void) 48 { 49 fprintf(stderr, 50 "Usage: ip [ OPTIONS ] OBJECT { COMMAND | help }\n" 51 " ip [ -force ] -batch filename\n" 52 "where OBJECT := { link | address | addrlabel | route | rule | neighbor | ntable |\n" 53 " tunnel | tuntap | maddress | mroute | mrule | monitor | xfrm |\n" 54 " netns | l2tp | fou | tcp_metrics | token | netconf }\n" 55 " OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n" 56 " -h[uman-readable] | -iec |\n" 57 " -f[amily] { inet | inet6 | ipx | dnet | mpls | bridge | link } |\n" 58 " -4 | -6 | -I | -D | -B | -0 |\n" 59 " -l[oops] { maximum-addr-flush-attempts } | -br[ief] |\n" 60 " -o[neline] | -t[imestamp] | -ts[hort] | -b[atch] [filename] |\n" 61 " -rc[vbuf] [size] | -n[etns] name | -a[ll] |-c[olor]}\n"); 62 exit(-1); 63 } 64 65 static int do_help(int argc, char **argv) 66 { 67 usage(); 68 return 0; 69 } 70 71 static const struct cmd { 72 const char *cmd; 73 int (*func)(int argc, char **argv); 74 } cmds[] = { 75 { "address", do_ipaddr }, 76 { "addrlabel", do_ipaddrlabel }, 77 { "maddress", do_multiaddr }, 78 { "route", do_iproute }, 79 { "rule", do_iprule }, 80 { "neighbor", do_ipneigh }, 81 { "neighbour", do_ipneigh }, 82 { "ntable", do_ipntable }, 83 { "ntbl", do_ipntable }, 84 { "link", do_iplink }, 85 { "l2tp", do_ipl2tp }, 86 { "fou", do_ipfou }, 87 { "tunnel", do_iptunnel }, 88 { "tunl", do_iptunnel }, 89 { "tuntap", do_iptuntap }, 90 { "tap", do_iptuntap }, 91 { "token", do_iptoken }, 92 { "tcpmetrics", do_tcp_metrics }, 93 { "tcp_metrics", do_tcp_metrics }, 94 { "monitor", do_ipmonitor }, 95 { "xfrm", do_xfrm }, 96 { "mroute", do_multiroute }, 97 { "mrule", do_multirule }, 98 { "netns", do_netns }, 99 { "netconf", do_ipnetconf }, 100 { "help", do_help }, 101 { 0 } 102 }; 103 104 static int do_cmd(const char *argv0, int argc, char **argv) 105 { 106 const struct cmd *c; 107 108 for (c = cmds; c->cmd; ++c) { 109 if (matches(argv0, c->cmd) == 0) 110 return -(c->func(argc-1, argv+1)); 111 } 112 113 fprintf(stderr, "Object \"%s\" is unknown, try \"ip help\".\n", argv0); 114 return EXIT_FAILURE; 115 } 116 117 #ifndef ANDROID 118 static int batch(const char *name) 119 { 120 char *line = NULL; 121 size_t len = 0; 122 int ret = EXIT_SUCCESS; 123 int orig_family = preferred_family; 124 125 batch_mode = 1; 126 127 if (name && strcmp(name, "-") != 0) { 128 if (freopen(name, "r", stdin) == NULL) { 129 fprintf(stderr, 130 "Cannot open file \"%s\" for reading: %s\n", 131 name, strerror(errno)); 132 return EXIT_FAILURE; 133 } 134 } 135 136 if (rtnl_open(&rth, 0) < 0) { 137 fprintf(stderr, "Cannot open rtnetlink\n"); 138 return EXIT_FAILURE; 139 } 140 141 cmdlineno = 0; 142 while (getcmdline(&line, &len, stdin) != -1) { 143 char *largv[100]; 144 int largc; 145 146 preferred_family = orig_family; 147 148 largc = makeargs(line, largv, 100); 149 if (largc == 0) 150 continue; /* blank line */ 151 152 if (do_cmd(largv[0], largc, largv)) { 153 fprintf(stderr, "Command failed %s:%d\n", 154 name, cmdlineno); 155 ret = EXIT_FAILURE; 156 if (!force) 157 break; 158 } 159 } 160 if (line) 161 free(line); 162 163 rtnl_close(&rth); 164 return ret; 165 } 166 #endif 167 168 169 int main(int argc, char **argv) 170 { 171 char *basename; 172 #ifndef ANDROID 173 char *batch_file = NULL; 174 #endif 175 176 basename = strrchr(argv[0], '/'); 177 if (basename == NULL) 178 basename = argv[0]; 179 else 180 basename++; 181 182 while (argc > 1) { 183 char *opt = argv[1]; 184 185 if (strcmp(opt, "--") == 0) { 186 argc--; argv++; 187 break; 188 } 189 if (opt[0] != '-') 190 break; 191 if (opt[1] == '-') 192 opt++; 193 if (matches(opt, "-loops") == 0) { 194 argc--; 195 argv++; 196 if (argc <= 1) 197 usage(); 198 max_flush_loops = atoi(argv[1]); 199 } else if (matches(opt, "-family") == 0) { 200 argc--; 201 argv++; 202 if (argc <= 1) 203 usage(); 204 if (strcmp(argv[1], "help") == 0) 205 usage(); 206 else 207 preferred_family = read_family(argv[1]); 208 if (preferred_family == AF_UNSPEC) 209 invarg("invalid protocol family", argv[1]); 210 } else if (strcmp(opt, "-4") == 0) { 211 preferred_family = AF_INET; 212 } else if (strcmp(opt, "-6") == 0) { 213 preferred_family = AF_INET6; 214 } else if (strcmp(opt, "-0") == 0) { 215 preferred_family = AF_PACKET; 216 } else if (strcmp(opt, "-I") == 0) { 217 preferred_family = AF_IPX; 218 } else if (strcmp(opt, "-D") == 0) { 219 preferred_family = AF_DECnet; 220 } else if (strcmp(opt, "-M") == 0) { 221 preferred_family = AF_MPLS; 222 } else if (strcmp(opt, "-B") == 0) { 223 preferred_family = AF_BRIDGE; 224 } else if (matches(opt, "-human") == 0 || 225 matches(opt, "-human-readable") == 0) { 226 ++human_readable; 227 } else if (matches(opt, "-iec") == 0) { 228 ++use_iec; 229 } else if (matches(opt, "-stats") == 0 || 230 matches(opt, "-statistics") == 0) { 231 ++show_stats; 232 } else if (matches(opt, "-details") == 0) { 233 ++show_details; 234 } else if (matches(opt, "-resolve") == 0) { 235 ++resolve_hosts; 236 } else if (matches(opt, "-oneline") == 0) { 237 ++oneline; 238 } else if (matches(opt, "-timestamp") == 0) { 239 ++timestamp; 240 } else if (matches(opt, "-tshort") == 0) { 241 ++timestamp; 242 ++timestamp_short; 243 #if 0 244 } else if (matches(opt, "-numeric") == 0) { 245 rtnl_names_numeric++; 246 #endif 247 } else if (matches(opt, "-Version") == 0) { 248 printf("ip utility, iproute2-ss%s\n", SNAPSHOT); 249 exit(0); 250 } else if (matches(opt, "-force") == 0) { 251 ++force; 252 #ifndef ANDROID 253 } else if (matches(opt, "-batch") == 0) { 254 argc--; 255 argv++; 256 if (argc <= 1) 257 usage(); 258 batch_file = argv[1]; 259 #endif 260 } else if (matches(opt, "-brief") == 0) { 261 ++brief; 262 } else if (matches(opt, "-rcvbuf") == 0) { 263 unsigned int size; 264 265 argc--; 266 argv++; 267 if (argc <= 1) 268 usage(); 269 if (get_unsigned(&size, argv[1], 0)) { 270 fprintf(stderr, "Invalid rcvbuf size '%s'\n", 271 argv[1]); 272 exit(-1); 273 } 274 rcvbuf = size; 275 } else if (matches(opt, "-color") == 0) { 276 enable_color(); 277 } else if (matches(opt, "-help") == 0) { 278 usage(); 279 } else if (matches(opt, "-netns") == 0) { 280 NEXT_ARG(); 281 if (netns_switch(argv[1])) 282 exit(-1); 283 } else if (matches(opt, "-all") == 0) { 284 do_all = true; 285 } else { 286 fprintf(stderr, 287 "Option \"%s\" is unknown, try \"ip -help\".\n", 288 opt); 289 exit(-1); 290 } 291 argc--; argv++; 292 } 293 294 _SL_ = oneline ? "\\" : "\n"; 295 296 #ifndef ANDROID 297 if (batch_file) 298 return batch(batch_file); 299 #endif 300 301 if (rtnl_open(&rth, 0) < 0) 302 exit(1); 303 304 if (strlen(basename) > 2) 305 return do_cmd(basename+2, argc, argv); 306 307 if (argc > 1) 308 return do_cmd(argv[1], argc-1, argv+1); 309 310 rtnl_close(&rth); 311 usage(); 312 } 313