more socket stuff
[nestedvm.git] / src / org / ibex / nestedvm / support_aux.c
1 #include <string.h>
2 #include <sys/stat.h>
3 #include <sys/dirent.h>
4 #include <sys/types.h>
5 #include <utime.h>
6 #include <errno.h>
7 #include <unistd.h>
8 #include <fcntl.h>
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <signal.h>
12 #include <sys/sysctl.h>
13 #include <sys/utsname.h>
14 #include <paths.h>
15
16 #include <nestedvm/socket.h>
17
18 int _syscall_set_errno(struct _reent *ptr, int err) {
19     ptr->_errno = -err;
20     return -1;
21 }
22
23 #define REENT_WRAPPER0R(f,rt) \
24     extern rt _##f##_r(struct _reent *ptr); \
25     rt f() { return _##f##_r(_REENT); }
26 #define REENT_WRAPPER0(f) REENT_WRAPPER0R(f,int)
27
28 #define REENT_WRAPPER1R(f,rt,t1) \
29     extern rt _##f##_r(struct _reent *ptr, t1 a); \
30     rt f(t1 a) { return _##f##_r(_REENT,a); }
31 #define REENT_WRAPPER1(f,t1) REENT_WRAPPER1R(f,int,t1)
32
33 #define REENT_WRAPPER2R(f,rt,t1,t2) \
34     extern rt _##f##_r(struct _reent *ptr, t1 a, t2 b); \
35     rt f(t1 a, t2 b) { return _##f##_r(_REENT,a,b); }
36 #define REENT_WRAPPER2(f,t1,t2) REENT_WRAPPER2R(f,int,t1,t2)
37
38 #define REENT_WRAPPER3R(f,rt,t1,t2,t3) \
39     extern rt _##f##_r(struct _reent *ptr, t1 a, t2 b, t3 c); \
40     rt f(t1 a, t2 b, t3 c) { return _##f##_r(_REENT,a,b,c); }
41 #define REENT_WRAPPER3(f,t1,t2,t3) REENT_WRAPPER3R(f,int,t1,t2,t3)
42
43 #define REENT_WRAPPER4R(f,rt,t1,t2,t3,t4) \
44 extern rt _##f##_r(struct _reent *ptr, t1 a, t2 b, t3 c, t4 d); \
45 rt f(t1 a, t2 b, t3 c, t4 d) { return _##f##_r(_REENT,a,b,c,d); }
46 #define REENT_WRAPPER4(f,t1,t2,t3,t4) REENT_WRAPPER4R(f,int,t1,t2,t3,t4)
47
48 #define REENT_WRAPPER5R(f,rt,t1,t2,t3,t4,t5) \
49 extern rt _##f##_r(struct _reent *ptr, t1 a, t2 b, t3 c, t4 d, t5 e); \
50 rt f(t1 a, t2 b, t3 c, t4 d, t5 e) { return _##f##_r(_REENT,a,b,c,d,e); }
51 #define REENT_WRAPPER5(f,t1,t2,t3,t4,t5) REENT_WRAPPER5R(f,int,t1,t2,t3,t4,t5)
52
53 #define REENT_WRAPPER6R(f,rt,t1,t2,t3,t4,t5,t6) \
54 extern rt _##f##_r(struct _reent *ptr, t1 a, t2 b, t3 c, t4 d, t5 e, t6 f); \
55 rt f(t1 a, t2 b, t3 c, t4 d, t5 e, t6 f) { return _##f##_r(_REENT,a,b,c,d,e,f); }
56 #define REENT_WRAPPER6(f,t1,t2,t3,t4,t5,t6) REENT_WRAPPER6R(f,int,t1,t2,t3,t4,t5,t6)
57
58 REENT_WRAPPER2(mkdir,const char *,mode_t)
59 REENT_WRAPPER2(access,const char *,int)
60 REENT_WRAPPER1(rmdir,const char *)
61 REENT_WRAPPER1R(sysconf,long,int)
62 REENT_WRAPPER1(chdir,const char*)
63 REENT_WRAPPER2(utime,const char *,const struct utimbuf *)
64 REENT_WRAPPER1(pipe,int *)
65 REENT_WRAPPER2(dup2,int,int)
66 REENT_WRAPPER3(waitpid,pid_t,int *,int)
67 REENT_WRAPPER2R(getcwd,char *,char *,size_t)
68 REENT_WRAPPER2R(_getcwd,char *,char *,size_t)
69 REENT_WRAPPER2(symlink,const char *,const char *)
70 REENT_WRAPPER3(readlink,const char *, char *,int)
71 REENT_WRAPPER3(chown,const char *,uid_t,gid_t)
72 REENT_WRAPPER3(fchown,int,uid_t,gid_t)
73 REENT_WRAPPER3(lchown,const char *,uid_t,gid_t)
74 REENT_WRAPPER2(chmod,const char *,mode_t)
75 REENT_WRAPPER2(fchmod,int,mode_t)
76 REENT_WRAPPER2(lstat,const char *,struct stat *)
77 REENT_WRAPPER4(getdents,int, char *, size_t,long *)
78 REENT_WRAPPER1(dup,int)
79 REENT_WRAPPER2R(pathconf,long,const char *,int)
80 REENT_WRAPPER0(vfork)
81 REENT_WRAPPER1(chroot,const char *)
82 REENT_WRAPPER3(mknod,const char *,mode_t,dev_t)
83 REENT_WRAPPER2(ftruncate,int,off_t)
84 REENT_WRAPPER1(usleep,unsigned int)
85 REENT_WRAPPER2(mkfifo,const char *, mode_t)
86 REENT_WRAPPER3(klogctl,int,char*,int)
87 REENT_WRAPPER2R(realpath,char *,const char *,char *)
88 REENT_WRAPPER6(_sysctl,int *,int, void *, size_t*, void *, size_t)
89 REENT_WRAPPER6(sysctl,int *, int, void *, size_t*, void *, size_t)
90 REENT_WRAPPER2(getpriority,int,int)
91 REENT_WRAPPER3(setpriority,int,int,int)
92 REENT_WRAPPER3(connect,int,const struct sockaddr *,socklen_t)
93 REENT_WRAPPER3(socket,int,int,int)
94 REENT_WRAPPER3(_resolve_hostname,const char *,char*,size_t*)
95 REENT_WRAPPER3(_resolve_ip,int,char*,size_t)
96 REENT_WRAPPER3(accept,int,struct sockaddr *,socklen_t*)
97 REENT_WRAPPER5(getsockopt,int,int,int,void*,socklen_t*)
98 REENT_WRAPPER5(setsockopt,int,int,int,const void*,socklen_t)
99 REENT_WRAPPER3(bind,int,const struct sockaddr *,socklen_t)
100 REENT_WRAPPER2(listen,int,int)
101 REENT_WRAPPER2(shutdown,int,int)
102 REENT_WRAPPER6(sendto,int,const void*,size_t,int,const struct sockaddr*,socklen_t)
103 REENT_WRAPPER6(recvfrom,int,void*,size_t,int,struct sockaddr*,socklen_t*)
104 REENT_WRAPPER5(select,int,fd_set*,fd_set*,fd_set*,struct timeval*)
105 REENT_WRAPPER4(send,int,const void*,size_t,int)
106 REENT_WRAPPER4(recv,int,void*,size_t,int)
107 REENT_WRAPPER2(getgroups,int,gid_t*)
108 REENT_WRAPPER3(getsockname,int,struct sockaddr*,int*)
109 REENT_WRAPPER3(getpeername,int,struct sockaddr*,int*)
110 REENT_WRAPPER1(setuid,uid_t)
111 REENT_WRAPPER1(seteuid,uid_t)
112 REENT_WRAPPER1(setgid,gid_t)
113 REENT_WRAPPER1(setegid,gid_t)
114 REENT_WRAPPER2(setgroups,int,const gid_t *)
115 REENT_WRAPPER0R(setsid,pid_t)
116
117 extern int __execve_r(struct _reent *ptr, const char *path, char *const argv[], char *const envp[]);
118 int _execve(const char *path, char *const argv[], char *const envp[]) {
119     return __execve_r(_REENT,path,argv,envp);
120 }
121
122 char *_getcwd_r(struct _reent *ptr, char *buf, size_t size) {
123     if(buf != NULL) {
124         buf = __getcwd_r(ptr,buf,size);
125         return (long)buf == -1 ? NULL : buf;
126     }
127     
128     size = 256;
129     for(;;) {
130         buf = malloc(size);
131         char *ret = __getcwd_r(ptr,buf,size);
132         if((long)ret != -1) return ret;
133         free(buf);
134         size *= 2;
135         if(ptr->_errno != ERANGE) return NULL;
136     }
137 }
138
139 pid_t _wait_r(struct _reent *ptr, int *status) {
140     return _waitpid_r(ptr,-1,status,0);
141 }
142
143 long _pathconf_r(struct _reent *ptr,const char *path, int name) {
144     switch(name) {
145         default:
146             fprintf(stderr,"WARNING: pathconf: Unknown \"name\": %d\n",name);
147             ptr->_errno = EINVAL;
148             return -1;
149     }
150 }
151
152 int _sysctl_r(struct _reent *ptr, int *name, int namelen, void *oldp, size_t *oldlen, void *newp, size_t newlen) {
153     if(name[0] != CTL_USER) return _sysctl(name,namelen,oldp,oldlen,newp,newlen);
154     if(newp != NULL) { ptr->_errno = EPERM; return -1; }
155     if(namelen != 2) { ptr->_errno = EINVAL; return -1; }
156     
157     switch(name[1]) {
158         default:
159             fprintf(stderr,"WARNING: sysctl: Unknown name: %d\n",name[1]);
160             ptr->_errno = EINVAL;
161             return -1;
162     }
163 }
164
165 void sync() {
166     /* do nothing*/
167 }
168
169 int fsync(int fd) {
170     /* do nothing */
171     return 0;
172 }
173
174 char *ttyname(int fd) {
175     return isatty(fd) ? "/dev/console" : NULL;
176 }
177
178 int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) {
179     _sig_func_ptr old;
180     _sig_func_ptr new;
181     if(act) {
182         if(act->sa_flags || act->sa_mask != ~((sigset_t)0)) { errno = EINVAL; return -1; }
183         old = signal(sig,act->sa_handler);
184     } else if(oact) {
185         old = signal(sig,SIG_DFL);
186         signal(sig,old);
187     }
188     if(oact) {
189         oact->sa_handler = old;
190         oact->sa_mask = 0;
191         oact->sa_mask = ~((sigset_t)0);
192     }
193     return 0;
194 }
195
196 int sigfillset(sigset_t *set) {
197     *set = ~((sigset_t)0);
198     return 0;
199 }
200
201 int sigemptyset(sigset_t *set) {
202     *set = (sigset_t) 0;
203     return 0;
204 }
205
206 DIR *opendir(const char *path) {
207     struct stat sb;
208     int fd;
209     DIR *dir;
210     
211     fd = open(path,O_RDONLY);
212     if(fd < 0) return NULL;
213     
214     if(fstat(fd,&sb) < 0 || !S_ISDIR(sb.st_mode)) {
215         close(fd);
216         errno = ENOTDIR;
217         return NULL;
218     }
219     
220     dir = malloc(sizeof(*dir));
221     if(dir == NULL) {
222         close(fd);
223         errno = ENOMEM;
224         return NULL;
225     }
226     dir->dd_fd = fd;
227     dir->dd_buf = malloc(sizeof(struct dirent));
228     dir->dd_size = sizeof(struct dirent);
229     if(dir->dd_buf == NULL) {
230         close(fd);
231         free(dir);
232         return NULL;
233     }
234     dir->dd_loc = 0;
235     dir->dd_len = 0;
236     return dir;
237 }
238
239 struct dirent *readdir(DIR *dir) {
240     struct dirent *dp;
241     errno = 0;
242     if(dir->dd_loc == 0 || dir->dd_loc == dir->dd_len) {
243         dir->dd_len = getdents(dir->dd_fd,dir->dd_buf,dir->dd_size,NULL);
244         dir->dd_loc = 0;
245         if(dir->dd_len <= 0) { dir->dd_len = 0; return NULL; }
246     }
247     dp = (struct dirent*) (dir->dd_buf + dir->dd_loc);
248     if(dp->d_reclen == 0 || dp->d_reclen > dir->dd_len - dir->dd_loc) return NULL;
249     dir->dd_loc += dp->d_reclen;
250     return dp;
251 }
252
253 int closedir(DIR *dir) {
254     int fd = dir->dd_fd;
255     free(dir->dd_buf);
256     free(dir);
257     return close(fd);
258 }
259
260 /*
261  * Networking/Socket stuff
262  */
263
264 /* This should really be part of the newlib _reent structure */
265 int h_errno;
266
267 char *inet_ntoa(struct in_addr in) {
268     static char buf[18];
269     const unsigned char *p = (void*) &in;
270     snprintf(buf,sizeof(buf),"%u.%u.%u.%u",p[0],p[1],p[2],p[3]);
271     return buf;
272 }
273
274 struct servent *getservbyname(const char *name,const char *proto) {
275     return NULL;
276 }
277
278 static const char *h_errlist[] = { "No Error","Unknown host", "Host name lookup failure","Unknown server error","No address associated with name" };
279
280 const char *hstrerror(int err) {
281     if(err < 0 || err > 4) return "Unknown Error";
282     return h_errlist[err];
283 }
284
285 void herror(const char *string) {
286     fprintf(stderr,"%s: %s\n",string,hstrerror(h_errno));
287 }
288
289 extern int _resolve_ip(int addr, char *buf, size_t size);
290
291 struct hostent *gethostbyaddr(const char *addr, int len, int type) {
292     static struct hostent hostent;
293     static char name[128];
294     static char *aliases[1];
295     static char *addr_list[1];
296     static char addr_list_buf[4];
297     int err,i;
298     
299     if(type != AF_INET || len != 4) return NULL;
300     memcpy(&i,addr,4);
301     memcpy(addr_list_buf,addr,4);
302     err = _resolve_ip(i,name,sizeof(name));
303     if(err != 0) { h_errno = err; return NULL; }
304     
305     hostent.h_name = name;
306     hostent.h_aliases = aliases;
307     aliases[0] = NULL;
308     hostent.h_addrtype = AF_INET;
309     hostent.h_length = sizeof(struct in_addr);
310     hostent.h_addr_list = addr_list;
311     addr_list[0] = addr_list_buf;
312     
313     return &hostent;
314 }
315
316 extern int _resolve_hostname(const char *, char *buf, size_t *size);
317
318 struct hostent *gethostbyname(const char *hostname) {
319 #define MAX_ADDRS 256
320     static struct hostent hostent;
321     static char saved_hostname[128];
322     static char *addr_list[MAX_ADDRS+1];
323     static char addr_list_buf[MAX_ADDRS*sizeof(struct in_addr)];
324     static char *aliases[1];
325     
326     unsigned char buf[MAX_ADDRS*sizeof(struct in_addr)];
327     size_t size = sizeof(buf);
328     int err,i,n=0;
329     
330     err = _resolve_hostname(hostname,buf,&size);
331     if(err != 0) { h_errno = err; return NULL; }
332     
333     memcpy(addr_list_buf,buf,size);
334     for(i=0;i<size;i += sizeof(struct in_addr)) addr_list[n++] = &addr_list_buf[i];
335     addr_list[n] = NULL;
336     strncpy(saved_hostname,hostname,sizeof(saved_hostname));
337     aliases[0] = NULL;
338     
339     hostent.h_name = saved_hostname;
340     hostent.h_aliases = aliases;
341     hostent.h_addrtype = AF_INET;
342     hostent.h_length = sizeof(struct in_addr);
343     hostent.h_addr_list = addr_list;
344     
345     return &hostent;
346 }
347
348 /*
349  * Other People's Code 
350  */
351
352 /* FreeBSD's dirname/basename */
353
354 /* FIXME: Put these in a header */
355
356 /*
357  * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
358  * All rights reserved.
359  *
360  * Redistribution and use in source and binary forms, with or without
361  * modification, are permitted provided that the following conditions
362  * are met:
363  * 1. Redistributions of source code must retain the above copyright
364  *    notice, this list of conditions and the following disclaimer.
365  * 2. Redistributions in binary form must reproduce the above copyright
366  *    notice, this list of conditions and the following disclaimer in the
367  *    documentation and/or other materials provided with the distribution.
368  * 3. The name of the author may not be used to endorse or promote products
369  *    derived from this software without specific prior written permission.
370  *
371  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
372  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
373  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
374  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
375  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
376  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
377  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
378  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
379  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
380  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
381  */
382
383 char *
384 dirname(path)
385 const char *path;
386 {
387     static char bname[MAXPATHLEN];
388     register const char *endp;
389     
390     /* Empty or NULL string gets treated as "." */
391     if (path == NULL || *path == '\0') {
392         (void)strcpy(bname, ".");
393         return(bname);
394     }
395     
396     /* Strip trailing slashes */
397     endp = path + strlen(path) - 1;
398     while (endp > path && *endp == '/')
399         endp--;
400     
401     /* Find the start of the dir */
402     while (endp > path && *endp != '/')
403         endp--;
404     
405     /* Either the dir is "/" or there are no slashes */
406     if (endp == path) {
407         (void)strcpy(bname, *endp == '/' ? "/" : ".");
408         return(bname);
409     } else {
410         do {
411             endp--;
412         } while (endp > path && *endp == '/');
413     }
414     
415     if (endp - path + 2 > sizeof(bname)) {
416         errno = ENAMETOOLONG;
417         return(NULL);
418     }
419     (void)strncpy(bname, path, endp - path + 1);
420     bname[endp - path + 1] = '\0';
421     return(bname);
422 }
423
424 char *
425 basename(path)
426 const char *path;
427 {
428     static char bname[MAXPATHLEN];
429     register const char *endp, *startp;
430     
431     /* Empty or NULL string gets treated as "." */
432     if (path == NULL || *path == '\0') {
433         (void)strcpy(bname, ".");
434         return(bname);
435     }
436     
437     /* Strip trailing slashes */
438     endp = path + strlen(path) - 1;
439     while (endp > path && *endp == '/')
440         endp--;
441     
442     /* All slashes becomes "/" */
443     if (endp == path && *endp == '/') {
444         (void)strcpy(bname, "/");
445         return(bname);
446     }
447     
448     /* Find the start of the base */
449     startp = endp;
450     while (startp > path && *(startp - 1) != '/')
451         startp--;
452     
453     if (endp - startp + 2 > sizeof(bname)) {
454         errno = ENAMETOOLONG;
455         return(NULL);
456     }
457     (void)strncpy(bname, startp, endp - startp + 1);
458     bname[endp - startp + 1] = '\0';
459     return(bname);
460 }
461
462 /* FreeBSD's uname */
463 int
464 uname(name)
465 struct utsname *name;
466 {
467         int mib[2], rval;
468         size_t len;
469         char *p;
470         int oerrno;
471     
472         rval = 0;
473     
474         mib[0] = CTL_KERN;
475         mib[1] = KERN_OSTYPE;
476         len = sizeof(name->sysname);
477         oerrno = errno;
478         if (sysctl(mib, 2, &name->sysname, &len, NULL, 0) == -1) {
479                 if(errno == ENOMEM)
480                         errno = oerrno;
481                 else
482                         rval = -1;
483         }
484         name->sysname[sizeof(name->sysname) - 1] = '\0';
485     
486         mib[0] = CTL_KERN;
487         mib[1] = KERN_HOSTNAME;
488         len = sizeof(name->nodename);
489         oerrno = errno;
490         if (sysctl(mib, 2, &name->nodename, &len, NULL, 0) == -1) {
491                 if(errno == ENOMEM)
492                         errno = oerrno;
493                 else
494                         rval = -1;
495         }
496         name->nodename[sizeof(name->nodename) - 1] = '\0';
497     
498         mib[0] = CTL_KERN;
499         mib[1] = KERN_OSRELEASE;
500         len = sizeof(name->release);
501         oerrno = errno;
502         if (sysctl(mib, 2, &name->release, &len, NULL, 0) == -1) {
503                 if(errno == ENOMEM)
504                         errno = oerrno;
505                 else
506                         rval = -1;
507         }
508         name->release[sizeof(name->release) - 1] = '\0';
509     
510         /* The version may have newlines in it, turn them into spaces. */
511         mib[0] = CTL_KERN;
512         mib[1] = KERN_VERSION;
513         len = sizeof(name->version);
514         oerrno = errno;
515         if (sysctl(mib, 2, &name->version, &len, NULL, 0) == -1) {
516                 if (errno == ENOMEM)
517                         errno = oerrno;
518                 else
519                         rval = -1;
520         }
521         name->version[sizeof(name->version) - 1] = '\0';
522         for (p = name->version; len--; ++p) {
523                 if (*p == '\n' || *p == '\t') {
524                         if (len > 1)
525                                 *p = ' ';
526                         else
527                                 *p = '\0';
528                 }
529         }
530     
531         mib[0] = CTL_HW;
532         mib[1] = HW_MACHINE;
533         len = sizeof(name->machine);
534         oerrno = errno;
535         if (sysctl(mib, 2, &name->machine, &len, NULL, 0) == -1) {
536                 if (errno == ENOMEM)
537                         errno = oerrno;
538                 else
539                         rval = -1;
540         }
541         name->machine[sizeof(name->machine) - 1] = '\0';
542         return (rval);
543 }
544
545 /* FreeBSD's gethostname */
546 int
547 gethostname(name, namelen)
548 char *name;
549 int namelen;
550 {
551     int mib[2];
552     size_t size;
553     
554     mib[0] = CTL_KERN;
555     mib[1] = KERN_HOSTNAME;
556     size = namelen;
557     if (sysctl(mib, 2, name, &size, NULL, 0) == -1)
558         return (-1);
559     return (0);
560 }
561
562 /* FreeBSD's daemon() - modified for nestedvm */
563 int
564 daemon(nochdir, noclose)
565 int nochdir, noclose;
566 {
567         int fd;
568     
569         switch (fork()) {
570         case -1:
571             return (-1);
572         case 0:
573             break;
574         default:
575             _exit(0);
576         }
577     
578         if (setsid() == -1)
579                 return (-1);
580     
581         if (!nochdir)
582                 (void)chdir("/");
583     
584         if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
585                 (void)dup2(fd, STDIN_FILENO);
586                 (void)dup2(fd, STDOUT_FILENO);
587                 (void)dup2(fd, STDERR_FILENO);
588                 if (fd > 2)
589                         (void)close(fd);
590         }
591         return (0);
592 }
593
594 /* FreeBSD's inet_addr/inet_aton */
595
596 /* 
597 * Check whether "cp" is a valid ASCII representation
598  * of an Internet address and convert to a binary address.
599  * Returns 1 if the address is valid, 0 if not.
600  * This replaces inet_addr, the return value from which
601  * cannot distinguish between failure and a local broadcast address.
602  */
603 int
604 inet_aton(cp, addr)
605 register const char *cp;
606 struct in_addr *addr;
607 {
608         u_long parts[4];
609         in_addr_t val;
610         char *c;
611         char *endptr;
612         int gotend, n;
613     
614         c = (char *)cp;
615         n = 0;
616         /*
617          * Run through the string, grabbing numbers until
618          * the end of the string, or some error
619          */
620         gotend = 0;
621         while (!gotend) {
622                 errno = 0;
623                 val = strtoul(c, &endptr, 0);
624         
625                 if (errno == ERANGE)    /* Fail completely if it overflowed. */
626                         return (0);
627                 
628                 /* 
629             * If the whole string is invalid, endptr will equal
630                  * c.. this way we can make sure someone hasn't
631                  * gone '.12' or something which would get past
632                  * the next check.
633                  */
634                 if (endptr == c)
635                         return (0);
636                 parts[n] = val;
637                 c = endptr;
638         
639                 /* Check the next character past the previous number's end */
640                 switch (*c) {
641             case '.' :
642                 /* Make sure we only do 3 dots .. */
643                 if (n == 3)     /* Whoops. Quit. */
644                     return (0);
645                 n++;
646                 c++;
647                 break;
648                 
649             case '\0':
650                 gotend = 1;
651                 break;
652                 
653             default:
654                 if (isspace((unsigned char)*c)) {
655                     gotend = 1;
656                     break;
657                 } else
658                     return (0); /* Invalid character, so fail */
659                 }
660         
661         }
662     
663         /*
664          * Concoct the address according to
665          * the number of parts specified.
666          */
667     
668         switch (n) {
669         case 0:                         /* a -- 32 bits */
670             /*
671              * Nothing is necessary here.  Overflow checking was
672              * already done in strtoul().
673              */
674             break;
675         case 1:                         /* a.b -- 8.24 bits */
676             if (val > 0xffffff || parts[0] > 0xff)
677                 return (0);
678             val |= parts[0] << 24;
679             break;
680             
681         case 2:                         /* a.b.c -- 8.8.16 bits */
682             if (val > 0xffff || parts[0] > 0xff || parts[1] > 0xff)
683                 return (0);
684             val |= (parts[0] << 24) | (parts[1] << 16);
685                 break;
686                 
687             case 3:                             /* a.b.c.d -- 8.8.8.8 bits */
688                 if (val > 0xff || parts[0] > 0xff || parts[1] > 0xff ||
689                     parts[2] > 0xff)
690                     return (0);
691                 val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
692                     break;
693         }
694     
695         if (addr != NULL)
696                 addr->s_addr = htonl(val);
697         return (1);
698 }
699
700 /*
701  * ASCII internet address interpretation routine.
702  * The value returned is in network order.
703  */
704 in_addr_t               /* XXX should be struct in_addr :( */
705 inet_addr(cp)
706 register const char *cp;
707 {
708         struct in_addr val;
709     
710         if (inet_aton(cp, &val))
711                 return (val.s_addr);
712         return (INADDR_NONE);
713 }
714
715 int
716 getgrouplist(uname, agroup, groups, grpcnt)
717 const char *uname;
718 gid_t agroup;
719 register gid_t *groups;
720 int *grpcnt;
721 {
722         register struct group *grp;
723         register int i, ngroups;
724         int ret, maxgroups;
725     
726         ret = 0;
727         ngroups = 0;
728         maxgroups = *grpcnt;
729         /*
730          * When installing primary group, duplicate it;
731          * the first element of groups is the effective gid
732          * and will be overwritten when a setgid file is executed.
733          */
734         groups[ngroups++] = agroup;
735         if (maxgroups > 1)
736                 groups[ngroups++] = agroup;
737         /*
738          * Scan the group file to find additional groups.
739          */
740         setgrent();
741         while ((grp = getgrent())) {
742                 for (i = 0; i < ngroups; i++) {
743                         if (grp->gr_gid == groups[i])
744                                 goto skip;
745                 }
746                 for (i = 0; grp->gr_mem[i]; i++) {
747                         if (!strcmp(grp->gr_mem[i], uname)) {
748                                 if (ngroups >= maxgroups) {
749                                         ret = -1;
750                                         break;
751                                 }
752                                 groups[ngroups++] = grp->gr_gid;
753                                 break;
754                         }
755                 }
756 skip: ;
757         }
758         endgrent();
759         *grpcnt = ngroups;
760         return (ret);
761 }
762
763 int
764 initgroups(uname, agroup)
765 const char *uname;
766 gid_t agroup;
767 {
768     gid_t groups[32], ngroups;
769     
770     ngroups = 32;
771     getgrouplist(uname, agroup, groups, &ngroups);
772     return (setgroups(ngroups, groups));
773 }