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