netstat memory leak fixed.
[platform/upstream/net-tools.git] / nameif.c
1 /* 
2  * Name Interfaces based on MAC address.
3  * Writen 2000 by Andi Kleen.
4  * Subject to the Gnu Public License, version 2.  
5  * TODO: make it support token ring etc.
6  * $Id: nameif.c,v 1.4 2003/09/11 03:46:49 ak Exp $
7  */ 
8 #ifndef _GNU_SOURCE 
9 #define _GNU_SOURCE
10 #endif
11 #include <stdio.h>
12 #include <getopt.h>
13 #include <sys/syslog.h>
14 #include <errno.h>
15 #include <stdlib.h>
16 #include <ctype.h>
17 #include <string.h>
18 #include <stdarg.h>
19 #include <sys/socket.h>
20 #include <sys/ioctl.h>
21 #include <net/if.h>
22 #include <linux/sockios.h>
23 #include <errno.h>
24 #include "intl.h" 
25 #include "net-support.h"
26
27 const char default_conf[] = "/etc/mactab"; 
28 const char *fname = default_conf; 
29 int use_syslog; 
30 int ctl_sk = -1; 
31
32 void err(char *msg) 
33
34         if (use_syslog) { 
35                 syslog(LOG_ERR,"%s: %m", msg); 
36         } else { 
37                 perror(msg); 
38         } 
39         exit(1); 
40 }
41
42 void complain(char *fmt, ...) 
43
44         va_list ap;
45         va_start(ap,fmt);
46         if (use_syslog) { 
47                 vsyslog(LOG_ERR,fmt,ap);
48         } else {
49                 vfprintf(stderr,fmt,ap);
50                 fputc('\n',stderr); 
51         }
52         va_end(ap); 
53         exit(1);
54
55
56 void warning(char *fmt, ...) 
57
58         va_list ap;
59         va_start(ap,fmt);
60         if (use_syslog) { 
61                 vsyslog(LOG_ERR,fmt,ap);
62         } else {
63                 vfprintf(stderr,fmt,ap);
64                 fputc('\n',stderr); 
65         }
66         va_end(ap); 
67
68
69 int parsemac(char *str, unsigned char *mac)
70
71         char *s; 
72         while ((s = strsep(&str, ":")) != NULL) { 
73                 unsigned byte;
74                 if (sscanf(s,"%x", &byte)!=1 || byte > 0xff) 
75                         return -1;
76                 *mac++ = byte; 
77         }  
78         return 0;
79
80
81 void *xmalloc(unsigned sz)
82
83         void *p = calloc(sz,1);
84         if (!p) errno=ENOMEM, err("xmalloc"); 
85         return p; 
86
87
88 void opensock(void)
89 {
90         if (ctl_sk < 0) 
91                 ctl_sk = socket(PF_INET,SOCK_DGRAM,0); 
92 }
93
94 #ifndef ifr_newname
95 #define ifr_newname ifr_ifru.ifru_slave
96 #endif
97
98 int  setname(char *oldname, char *newname)
99 {
100         struct ifreq ifr;
101         opensock(); 
102         memset(&ifr,0,sizeof(struct ifreq));
103         strncpy(ifr.ifr_name, oldname, IFNAMSIZ);
104         strncpy(ifr.ifr_newname, newname, IFNAMSIZ);
105         return ioctl(ctl_sk, SIOCSIFNAME, &ifr);
106 }
107
108 int getmac(char *name, unsigned char *mac)
109 {
110         int r;
111         struct ifreq ifr;
112         opensock(); 
113         memset(&ifr,0,sizeof(struct ifreq));
114         strcpy(ifr.ifr_name, name); 
115         r = ioctl(ctl_sk, SIOCGIFHWADDR, &ifr);
116         memcpy(mac, ifr.ifr_hwaddr.sa_data, 6); 
117         return r; 
118 }
119
120 struct change { 
121         struct change *next;
122         int found;
123         char ifname[IFNAMSIZ+1];
124         unsigned char mac[6];
125 }; 
126 struct change *clist;
127
128 struct change *lookupmac(unsigned char *mac) 
129
130         struct change *ch;
131         for (ch = clist;ch;ch = ch->next) 
132                 if (!memcmp(ch->mac, mac, 6))
133                         return ch;
134         return NULL; 
135
136
137 int addchange(char *p, struct change *ch, char *pos)
138 {
139         if (strchr(ch->ifname, ':'))
140                 warning(_("alias device %s at %s probably has no mac"), 
141                         ch->ifname, pos); 
142         if (parsemac(p,ch->mac) < 0) 
143                 complain(_("cannot parse MAC `%s' at %s"), p, pos); 
144         ch->next = clist;
145         clist = ch;
146         return 0; 
147 }
148
149 void readconf(void)
150 {
151         char *line; 
152         size_t linel; 
153         int linenum; 
154         FILE *ifh;
155         char *p;
156         int n;
157         struct change *ch = NULL;
158
159         ifh = fopen(fname, "r");
160         if (!ifh) 
161                 complain(_("opening configuration file %s: %s"),fname,strerror(errno)); 
162
163         line = NULL; 
164         linel = 0;
165         linenum = 1; 
166         while (getdelim(&line, &linel, '\n', ifh) > 0) {
167                 char pos[20]; 
168
169                 sprintf(pos, _("line %d"), linenum); 
170
171                 if ((p = strchr(line,'#')) != NULL)
172                         *p = '\0';
173                 p = line; 
174                 while (isspace(*p))
175                         ++p; 
176                 if (*p == '\0')
177                         continue; 
178                 n = strcspn(p, " \t"); 
179                 if (n > IFNAMSIZ-1) 
180                         complain(_("interface name too long at line %d"), line);  
181                 ch = xmalloc(sizeof(struct change));
182                 memcpy(ch->ifname, p, n); 
183                 ch->ifname[n] = 0; 
184                 p += n; 
185                 p += strspn(p, " \t"); 
186                 n = strspn(p, "0123456789ABCDEFabcdef:"); 
187                 p[n] = 0; 
188                 addchange(p, ch, pos);
189                 linenum++;
190         }   
191         fclose(ifh); 
192 }
193
194 struct option lopt[] = { 
195         {"syslog", 0, NULL, 's' },
196         {"config-file", 1, NULL, 'c' },
197         {"help", 0, NULL, '?' }, 
198         {NULL}, 
199 }; 
200
201 void usage(void)
202 {
203         fprintf(stderr, _("usage: nameif [-c configurationfile] [-s] {ifname macaddress}\n")); 
204         exit(E_USAGE);
205 }
206
207 int main(int ac, char **av) 
208
209         FILE *ifh; 
210         char *p;
211         int n;
212         int linenum; 
213         char *line = NULL;
214         size_t linel = 0;
215         int ret = 0;
216
217         for (;;) {
218                 int c = getopt_long(ac,av,"c:s",lopt,NULL);
219                 if (c == -1) break;
220                 switch (c) { 
221                 default:
222                 case '?':
223                         usage(); 
224                 case 'c':
225                         fname = optarg;
226                         break;
227                 case 's':
228                         use_syslog = 1;
229                         break;
230                 }
231         }
232
233         if (use_syslog) 
234                 openlog("nameif",0,LOG_LOCAL0);
235                 
236         while (optind < ac) { 
237                 struct change *ch = xmalloc(sizeof(struct change)); 
238                 char pos[30];
239
240                 if ((ac-optind) & 1) 
241                         usage();
242                 if (strlen(av[optind])+1>IFNAMSIZ) 
243                         complain(_("interface name `%s' too long"), av[optind]);
244                 strcpy(ch->ifname, av[optind]); 
245                 optind++; 
246                 sprintf(pos,_("argument %d"),optind); 
247                 addchange(av[optind], ch, pos); 
248                 optind++; 
249         } 
250
251         if (!clist || fname != default_conf) 
252                 readconf(); 
253
254         ifh = fopen("/proc/net/dev", "r"); 
255         if (!ifh)  complain(_("open of /proc/net/dev: %s"), strerror(errno)); 
256
257
258         linenum = 0;
259         while (getdelim(&line, &linel, '\n', ifh) > 0) {
260                 struct change *ch; 
261                 unsigned char mac[6];
262
263                 if (linenum++ < 2) 
264                         continue;
265                         
266                 p = line; 
267                 while (isspace(*p)) 
268                         ++p;
269                 n = strcspn(p, ": \t");  
270                 p[n] = 0; 
271                 
272                 if (n > IFNAMSIZ-1) 
273                         complain(_("interface name `%s' too long"), p); 
274                         
275                 if (getmac(p, mac) < 0) 
276                         continue;
277                         
278                 ch = lookupmac(mac); 
279                 if (!ch) 
280                         continue;
281                 
282                 ch->found = 1;  
283                 if (strcmp(p, ch->ifname)) { 
284                         if (setname(p, ch->ifname) < 0)  
285                                 complain(_("cannot change name of %s to %s: %s"),
286                                                 p, ch->ifname, strerror(errno)); 
287                 } 
288         } 
289         fclose(ifh); 
290         
291         while (clist) { 
292                 struct change *ch = clist;
293                 clist = clist->next;
294                 if (!ch->found){
295                         warning(_("interface '%s' not found"), ch->ifname); 
296                         ret = 1;
297                 }
298                 free(ch); 
299         }
300
301         if (use_syslog)
302                 closelog();
303         return ret;
304
305