initial checkin
[util-vserver.git] / util-vserver / src / chbind.c
1 // $Id$
2
3 // Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
4 // based on chbind.cc by Jacques Gelinas
5 //  
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2, or (at your option)
9 // any later version.
10 //  
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 //  
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <netdb.h>
24 #include <sys/socket.h>
25 #include <sys/ioctl.h>
26 #include <netinet/in.h>
27 #include <net/if.h>
28 #include <unistd.h>
29 #include <errno.h>
30
31 #include "vserver.h"
32
33 static void usage()
34 {
35         fprintf (stderr,"chbind version %s\n",VERSION);
36         fprintf (stderr,"chbind [ --silent ] [ --ip ip_num[/mask] ] [ --bcast broadcast ] command argument\n");
37         exit (-1);
38 }
39
40 /*
41         Check if a network device exist in /proc/net/dev.
42         This is used because ifconfig_ioctl triggers modprobe if requesting
43         information about non existant devices.
44
45         Return != 0 if the device exist.
46 */
47 static int chbind_devexist (const char *dev)
48 {
49         int ret = 0;
50         FILE *fin = fopen ("/proc/net/dev","r");
51         if (fin != NULL){
52                 int len = strlen(dev);
53                 char buf[1000];
54                 fgets(buf,sizeof(buf)-1,fin);   // Skip one line
55                 while (fgets(buf,sizeof(buf)-1,fin)!=NULL){
56                         const char *pt = strstr(buf,dev);
57                         if (pt != NULL && pt[len] == ':'){
58                                 ret = 1;
59                                 break;
60                         }
61                 }
62                 fclose (fin);
63         }
64         return ret;
65 }
66
67
68 static int ifconfig_ioctl(
69         int fd,
70         const char *ifname,
71         int cmd,
72         struct ifreq *ifr)
73 {
74         strcpy(ifr->ifr_name, ifname);
75         return ioctl(fd, cmd,ifr);
76 }
77
78 /*
79         Fetch the IP number of an interface from the kernel.
80         Assume the device is already available in the kernel
81         Return -1 if any error.
82 */
83 int ifconfig_getaddr (
84         const char *ifname,
85         unsigned long *addr,
86         unsigned long *mask,
87         unsigned long *bcast)
88 {
89         int ret = -1;
90         if (chbind_devexist(ifname)){
91                 int skfd = socket(AF_INET, SOCK_DGRAM, 0);
92                 *addr = 0;
93                 *bcast = 0xffffffff;
94                 if (skfd != -1){
95                         struct ifreq ifr;
96                         if (ifconfig_ioctl(skfd,ifname,SIOCGIFADDR, &ifr) >= 0){
97                                 struct sockaddr_in *sin = (struct sockaddr_in*)&ifr.ifr_addr;
98                                 *addr = sin->sin_addr.s_addr;
99                                 ret = 0;
100                         }
101                         if (ifconfig_ioctl(skfd,ifname,SIOCGIFNETMASK, &ifr) >= 0){
102                                 struct sockaddr_in *sin = (struct sockaddr_in*)&ifr.ifr_addr;
103                                 *mask = sin->sin_addr.s_addr;
104                                 ret = 0;
105                         }
106                         if (ifconfig_ioctl(skfd,ifname,SIOCGIFBRDADDR, &ifr) >= 0){
107                                 struct sockaddr_in *sin = (struct sockaddr_in*)&ifr.ifr_addr;
108                                 *bcast = sin->sin_addr.s_addr;
109                                 ret = 0;
110                         }
111                         close (skfd);
112                 }
113         }
114         return ret;
115 }
116
117
118
119
120 int main (int argc, char *argv[])
121 {
122         int ret = -1;
123         int silent = 0;
124         int i;
125         unsigned long addrs[16],masks[16];
126         int nbaddrs = 0;
127         unsigned long bcast = 0xffffffff;
128         for (i=1; i<argc; i++){
129                 const char *arg = argv[i];
130                 const char *opt = argv[i+1];
131                 if (strcmp(arg,"--ip")==0){
132                         unsigned long addr,mask;
133                         if (nbaddrs == 16){
134                                 fprintf (stderr,"Too many IP numbers, max 16, ignored\n");
135
136                         }else if (ifconfig_getaddr(opt,&addr,&mask,&bcast)==-1){
137                                 unsigned long mask = 0x00ffffff;
138                                 const char *pt = strchr(opt,'/');
139                                 char tmpopt[strlen(opt)+1];
140                                 struct hostent *h;
141                                 
142                                 if (pt != NULL){
143                                         strcpy (tmpopt,opt);
144                                         tmpopt[pt-opt] = '\0';
145                                         opt = tmpopt;
146                                         pt++;
147                                         if (strchr(pt,'.')==NULL){
148                                                 // Ok, we have a network size, not a netmask
149                                                 int size = atoi(pt);
150                                                 int i;
151                                                 mask = 0;
152                                                 for (i=0; i<size; i++){
153                                                         mask = mask >> 1;
154                                                         mask |= 0x80000000;
155                                                 }
156                                                 mask = ntohl(mask);
157                                         }else{
158                                                 struct hostent *h = gethostbyname (pt);
159                                                 if (h != NULL){
160                                                         memcpy (&mask,h->h_addr,sizeof(mask));
161                                                 }else{
162                                                         fprintf (stderr,"Invalid netmask: %s\n",pt);
163                                                         usage();
164                                                 }
165                                         }
166                                                         
167                                 }
168
169                                 h = gethostbyname (opt);
170                                 if (h == NULL){
171                                         fprintf (stderr,"Invalid IP number or host name: %s\n",opt);
172                                         usage();
173                                 }else{
174                                         memcpy (&addr,h->h_addr,sizeof(addr));
175                                         masks[nbaddrs] = mask;
176                                         addrs[nbaddrs++] = addr;
177                                 }
178                         }else{
179                                 masks[nbaddrs] = mask;
180                                 addrs[nbaddrs++] = addr;
181                         }
182                         i++;
183                 }else if (strcmp(arg,"--bcast")==0){
184                         unsigned long tmp;
185                         if (ifconfig_getaddr(opt,&tmp,&tmp,&bcast)==-1){
186                                 struct hostent *h = gethostbyname (opt);
187                                 if (h == NULL){
188                                         fprintf (stderr,"Invalid broadcast number: %s\n",opt);
189                                         usage();
190                                 }else{
191                                         memcpy (&bcast,h->h_addr,sizeof(bcast));
192                                 }
193                         }
194                         i++;
195                 }else if (strcmp(arg,"--silent")==0){
196                         silent = 1;
197                 }else{
198                         break;
199                 }
200         }
201         if (i == argc){
202                 usage();
203         }else if (argv[i][0] == '-'){
204                 usage();
205         }else{
206                 if (call_set_ipv4root(addrs,nbaddrs,bcast,masks)==0){
207                         if (!silent){
208                                 int i;
209                                 printf ("ipv4root is now");
210                                 for (i=0; i<nbaddrs; i++){
211                                         unsigned long hostaddr = ntohl(addrs[i]);
212                                         printf (" %ld.%ld.%ld.%ld"
213                                                 ,hostaddr>>24
214                                                 ,(hostaddr>>16)&0xff
215                                                 ,(hostaddr>>8)&0xff
216                                                 ,hostaddr &0xff);
217                                 }
218                                 printf ("\n");
219                         }
220                         execvp (argv[i],argv+i);
221                         fprintf (stderr,"Can't exec %s (%s)\n",argv[i],strerror(errno));
222                 }else{
223                         fprintf (stderr,"Can't set the ipv4 root (%s)\n",strerror(errno));
224                 }
225         }
226         return ret;
227 }
228
229