This commit was generated by cvs2svn to compensate for changes in r120,
[util-vserver.git] / src / chbind.c
1 // $Id: chbind.c,v 1.1.4.1 2003/10/14 00:42:32 ensc Exp $
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 #ifdef HAVE_CONFIG_H
21 #  include <config.h>
22 #endif
23 #include "compat.h"
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <netdb.h>
29 #include <sys/socket.h>
30 #include <sys/ioctl.h>
31 #include <netinet/in.h>
32 #include <net/if.h>
33 #include <unistd.h>
34 #include <errno.h>
35
36 #include "vserver.h"
37
38 static void usage()
39 {
40         fprintf (stderr,"chbind version %s\n",VERSION);
41         fprintf (stderr,"chbind [ --silent ] [ --ip ip_num[/mask] ] [ --bcast broadcast ] command argument\n");
42         exit (-1);
43 }
44
45 /*
46         Check if a network device exist in /proc/net/dev.
47         This is used because ifconfig_ioctl triggers modprobe if requesting
48         information about non existant devices.
49
50         Return != 0 if the device exist.
51 */
52 static int chbind_devexist (const char *dev)
53 {
54         int ret = 0;
55         FILE *fin = fopen ("/proc/net/dev","r");
56         if (fin != NULL){
57                 int len = strlen(dev);
58                 char buf[1000];
59                 fgets(buf,sizeof(buf)-1,fin);   // Skip one line
60                 while (fgets(buf,sizeof(buf)-1,fin)!=NULL){
61                         const char *pt = strstr(buf,dev);
62                         if (pt != NULL && pt[len] == ':'){
63                                 ret = 1;
64                                 break;
65                         }
66                 }
67                 fclose (fin);
68         }
69         return ret;
70 }
71
72
73 static int ifconfig_ioctl(
74         int fd,
75         const char *ifname,
76         int cmd,
77         struct ifreq *ifr)
78 {
79         strcpy(ifr->ifr_name, ifname);
80         return ioctl(fd, cmd,ifr);
81 }
82
83 /*
84         Fetch the IP number of an interface from the kernel.
85         Assume the device is already available in the kernel
86         Return -1 if any error.
87 */
88 int ifconfig_getaddr (
89         const char *ifname,
90         unsigned long *addr,
91         unsigned long *mask,
92         unsigned long *bcast)
93 {
94         int ret = -1;
95         if (chbind_devexist(ifname)){
96                 int skfd = socket(AF_INET, SOCK_DGRAM, 0);
97                 *addr = 0;
98                 *bcast = 0xffffffff;
99                 if (skfd != -1){
100                         struct ifreq ifr;
101                         if (ifconfig_ioctl(skfd,ifname,SIOCGIFADDR, &ifr) >= 0){
102                                 struct sockaddr_in *sin = (struct sockaddr_in*)&ifr.ifr_addr;
103                                 *addr = sin->sin_addr.s_addr;
104                                 ret = 0;
105                         }
106                         if (ifconfig_ioctl(skfd,ifname,SIOCGIFNETMASK, &ifr) >= 0){
107                                 struct sockaddr_in *sin = (struct sockaddr_in*)&ifr.ifr_addr;
108                                 *mask = sin->sin_addr.s_addr;
109                                 ret = 0;
110                         }
111                         if (ifconfig_ioctl(skfd,ifname,SIOCGIFBRDADDR, &ifr) >= 0){
112                                 struct sockaddr_in *sin = (struct sockaddr_in*)&ifr.ifr_addr;
113                                 *bcast = sin->sin_addr.s_addr;
114                                 ret = 0;
115                         }
116                         close (skfd);
117                 }
118         }
119         return ret;
120 }
121
122
123
124
125 int main (int argc, char *argv[])
126 {
127         int ret = -1;
128         int silent = 0;
129         int i;
130         struct vc_ip_mask_pair  ips[16];
131         int nbaddrs = 0;
132         unsigned long bcast = 0xffffffff;
133         for (i=1; i<argc; i++){
134                 const char *arg = argv[i];
135                 const char *opt = argv[i+1];
136                 if (strcmp(arg,"--ip")==0){
137                         unsigned long addr,mask;
138                         if (nbaddrs == 16){
139                                 fprintf (stderr,"Too many IP numbers, max 16, ignored\n");
140
141                         }else if (ifconfig_getaddr(opt,&addr,&mask,&bcast)==-1){
142                                 unsigned long mask = 0x00ffffff;
143                                 const char *pt = strchr(opt,'/');
144                                 char tmpopt[strlen(opt)+1];
145                                 struct hostent *h;
146                                 
147                                 if (pt != NULL){
148                                         strcpy (tmpopt,opt);
149                                         tmpopt[pt-opt] = '\0';
150                                         opt = tmpopt;
151                                         pt++;
152                                         if (strchr(pt,'.')==NULL){
153                                                 // Ok, we have a network size, not a netmask
154                                                 int size = atoi(pt);
155                                                 int i;
156                                                 mask = 0;
157                                                 for (i=0; i<size; i++){
158                                                         mask = mask >> 1;
159                                                         mask |= 0x80000000;
160                                                 }
161                                                 mask = ntohl(mask);
162                                         }else{
163                                                 struct hostent *h = gethostbyname (pt);
164                                                 if (h != NULL){
165                                                         memcpy (&mask,h->h_addr,sizeof(mask));
166                                                 }else{
167                                                         fprintf (stderr,"Invalid netmask: %s\n",pt);
168                                                         usage();
169                                                 }
170                                         }
171                                                         
172                                 }
173
174                                 h = gethostbyname (opt);
175                                 if (h == NULL){
176                                         fprintf (stderr,"Invalid IP number or host name: %s\n",opt);
177                                         usage();
178                                 }else{
179                                         memcpy (&addr,h->h_addr,sizeof(addr));
180                                         ips[nbaddrs].ip   = addr;
181                                         ips[nbaddrs].mask = mask;
182                                         ++nbaddrs;
183                                 }
184                         }else{
185                               ips[nbaddrs].ip   = addr;
186                               ips[nbaddrs].mask = mask;
187                               ++nbaddrs;
188                         }
189                         i++;
190                 }else if (strcmp(arg,"--bcast")==0){
191                         unsigned long tmp;
192                         if (ifconfig_getaddr(opt,&tmp,&tmp,&bcast)==-1){
193                                 struct hostent *h = gethostbyname (opt);
194                                 if (h == NULL){
195                                         fprintf (stderr,"Invalid broadcast number: %s\n",opt);
196                                         usage();
197                                 }else{
198                                         memcpy (&bcast,h->h_addr,sizeof(bcast));
199                                 }
200                         }
201                         i++;
202                 }else if (strcmp(arg,"--silent")==0){
203                         silent = 1;
204                 }else{
205                         break;
206                 }
207         }
208         if (i == argc){
209                 usage();
210         }else if (argv[i][0] == '-'){
211                 usage();
212         }else{
213               if (vc_set_ipv4root(bcast,nbaddrs,ips)==0){
214                         if (!silent){
215                                 int i;
216                                 printf ("ipv4root is now");
217                                 for (i=0; i<nbaddrs; i++){
218                                         unsigned long hostaddr = ntohl(ips[i].ip);
219                                         printf (" %ld.%ld.%ld.%ld"
220                                                 ,hostaddr>>24
221                                                 ,(hostaddr>>16)&0xff
222                                                 ,(hostaddr>>8)&0xff
223                                                 ,hostaddr &0xff);
224                                 }
225                                 printf ("\n");
226                         }
227                         execvp (argv[i],argv+i);
228                         fprintf (stderr,"Can't exec %s (%s)\n",argv[i],strerror(errno));
229                 }else{
230                         fprintf (stderr,"Can't set the ipv4 root (%s)\n",strerror(errno));
231                 }
232         }
233         return ret;
234 }
235
236