Maik Broemme contributed gcc warning fixes (break after default: label)
[oss-qm-packages.git] / nameif.c
blob04658c5b2c9ecc429d1c777506c3af8ffec99859
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"
26 const char default_conf[] = "/etc/mactab";
27 const char *fname = default_conf;
28 int use_syslog;
29 int ctl_sk = -1;
31 void err(char *msg)
33 if (use_syslog) {
34 syslog(LOG_ERR,"%s: %m", msg);
35 } else {
36 perror(msg);
38 exit(1);
41 void complain(char *fmt, ...)
43 va_list ap;
44 va_start(ap,fmt);
45 if (use_syslog) {
46 vsyslog(LOG_ERR,fmt,ap);
47 } else {
48 vfprintf(stderr,fmt,ap);
49 fputc('\n',stderr);
51 va_end(ap);
52 exit(1);
55 void warning(char *fmt, ...)
57 va_list ap;
58 va_start(ap,fmt);
59 if (use_syslog) {
60 vsyslog(LOG_ERR,fmt,ap);
61 } else {
62 vfprintf(stderr,fmt,ap);
63 fputc('\n',stderr);
65 va_end(ap);
68 int parsemac(char *str, unsigned char *mac)
70 char *s;
71 while ((s = strsep(&str, ":")) != NULL) {
72 unsigned byte;
73 if (sscanf(s,"%x", &byte)!=1 || byte > 0xff)
74 return -1;
75 *mac++ = byte;
77 return 0;
80 void *xmalloc(unsigned sz)
82 void *p = calloc(sz,1);
83 if (!p) errno=ENOMEM, err("xmalloc");
84 return p;
87 void opensock(void)
89 if (ctl_sk < 0)
90 ctl_sk = socket(PF_INET,SOCK_DGRAM,0);
93 #ifndef ifr_newname
94 #define ifr_newname ifr_ifru.ifru_slave
95 #endif
97 int setname(char *oldname, char *newname)
99 struct ifreq ifr;
100 opensock();
101 memset(&ifr,0,sizeof(struct ifreq));
102 strcpy(ifr.ifr_name, oldname);
103 strcpy(ifr.ifr_newname, newname);
104 return ioctl(ctl_sk, SIOCSIFNAME, &ifr);
107 int getmac(char *name, unsigned char *mac)
109 int r;
110 struct ifreq ifr;
111 opensock();
112 memset(&ifr,0,sizeof(struct ifreq));
113 strcpy(ifr.ifr_name, name);
114 r = ioctl(ctl_sk, SIOCGIFHWADDR, &ifr);
115 memcpy(mac, ifr.ifr_hwaddr.sa_data, 6);
116 return r;
119 struct change {
120 struct change *next;
121 int found;
122 char ifname[IFNAMSIZ+1];
123 unsigned char mac[6];
125 struct change *clist;
127 struct change *lookupmac(unsigned char *mac)
129 struct change *ch;
130 for (ch = clist;ch;ch = ch->next)
131 if (!memcmp(ch->mac, mac, 6))
132 return ch;
133 return NULL;
136 int addchange(char *p, struct change *ch, char *pos)
138 if (strchr(ch->ifname, ':'))
139 warning(_("alias device %s at %s probably has no mac"),
140 ch->ifname, pos);
141 if (parsemac(p,ch->mac) < 0)
142 complain(_("cannot parse MAC `%s' at %s"), p, pos);
143 ch->next = clist;
144 clist = ch;
145 return 0;
148 void readconf(void)
150 char *line;
151 size_t linel;
152 int linenum;
153 FILE *ifh;
154 char *p;
155 int n;
157 ifh = fopen(fname, "r");
158 if (!ifh)
159 complain(_("opening configuration file %s: %s"),fname,strerror(errno));
161 line = NULL;
162 linel = 0;
163 linenum = 1;
164 while (getdelim(&line, &linel, '\n', ifh) > 0) {
165 struct change *ch = xmalloc(sizeof(struct change));
166 char pos[20];
168 sprintf(pos, _("line %d"), linenum);
170 if ((p = strchr(line,'#')) != NULL)
171 *p = '\0';
172 p = line;
173 while (isspace(*p))
174 ++p;
175 if (*p == '\0')
176 continue;
177 n = strcspn(p, " \t");
178 if (n > IFNAMSIZ-1)
179 complain(_("interface name too long at line %d"), line);
180 memcpy(ch->ifname, p, n);
181 ch->ifname[n] = 0;
182 p += n;
183 p += strspn(p, " \t");
184 n = strspn(p, "0123456789ABCDEFabcdef:");
185 p[n] = 0;
186 addchange(p, ch, pos);
187 linenum++;
189 fclose(ifh);
192 struct option lopt[] = {
193 {"syslog", 0, NULL, 's' },
194 {"config-file", 1, NULL, 'c' },
195 {"help", 0, NULL, '?' },
196 {NULL},
199 void usage(void)
201 fprintf(stderr, _("usage: nameif [-c configurationfile] [-s] {ifname macaddress}\n"));
202 exit(1);
205 int main(int ac, char **av)
207 FILE *ifh;
208 char *p;
209 int n;
210 int linenum;
211 char *line = NULL;
212 size_t linel = 0;
214 for (;;) {
215 int c = getopt_long(ac,av,"c:s",lopt,NULL);
216 if (c == -1) break;
217 switch (c) {
218 default:
219 case '?':
220 usage();
221 case 'c':
222 fname = optarg;
223 break;
224 case 's':
225 use_syslog = 1;
226 break;
230 if (use_syslog)
231 openlog("nameif",0,LOG_LOCAL0);
233 while (optind < ac) {
234 struct change *ch = xmalloc(sizeof(struct change));
235 char pos[30];
237 if ((ac-optind) & 1)
238 usage();
239 if (strlen(av[optind])+1>IFNAMSIZ)
240 complain(_("interface name `%s' too long"), av[optind]);
241 strcpy(ch->ifname, av[optind]);
242 optind++;
243 sprintf(pos,_("argument %d"),optind);
244 addchange(av[optind], ch, pos);
245 optind++;
248 if (!clist || fname != default_conf)
249 readconf();
251 ifh = fopen("/proc/net/dev", "r");
252 if (!ifh) complain(_("open of /proc/net/dev: %s"), strerror(errno));
255 linenum = 0;
256 while (getdelim(&line, &linel, '\n', ifh) > 0) {
257 struct change *ch;
258 unsigned char mac[6];
260 if (linenum++ < 2)
261 continue;
263 p = line;
264 while (isspace(*p))
265 ++p;
266 n = strcspn(p, ": \t");
267 p[n] = 0;
269 if (n > IFNAMSIZ-1)
270 complain(_("interface name `%s' too long"), p);
272 if (getmac(p, mac) < 0)
273 continue;
275 ch = lookupmac(mac);
276 if (!ch)
277 continue;
279 ch->found = 1;
280 if (strcmp(p, ch->ifname)) {
281 if (setname(p, ch->ifname) < 0)
282 complain(_("cannot change name of %s to %s: %s"),
283 p, ch->ifname, strerror(errno));
286 fclose(ifh);
288 while (clist) {
289 struct change *ch = clist;
290 clist = clist->next;
291 if (!ch->found)
292 warning(_("interface '%s' not found"), ch->ifname);
293 free(ch);
296 if (use_syslog)
297 closelog();
298 return 0;