use newlib/libc/unix
[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 DIR *opendir(const char *path) {
197     struct stat sb;
198     int fd;
199     DIR *dir;
200     
201     fd = open(path,O_RDONLY);
202     if(fd < 0) return NULL;
203     
204     if(fstat(fd,&sb) < 0 || !S_ISDIR(sb.st_mode)) {
205         close(fd);
206         errno = ENOTDIR;
207         return NULL;
208     }
209     
210     dir = malloc(sizeof(*dir));
211     if(dir == NULL) {
212         close(fd);
213         errno = ENOMEM;
214         return NULL;
215     }
216     dir->dd_fd = fd;
217     dir->dd_buf = malloc(sizeof(struct dirent));
218     dir->dd_size = sizeof(struct dirent);
219     if(dir->dd_buf == NULL) {
220         close(fd);
221         free(dir);
222         return NULL;
223     }
224     dir->dd_loc = 0;
225     dir->dd_len = 0;
226     return dir;
227 }
228
229 struct dirent *readdir(DIR *dir) {
230     struct dirent *dp;
231     errno = 0;
232     if(dir->dd_loc == 0 || dir->dd_loc == dir->dd_len) {
233         dir->dd_len = getdents(dir->dd_fd,dir->dd_buf,dir->dd_size,NULL);
234         dir->dd_loc = 0;
235         if(dir->dd_len <= 0) { dir->dd_len = 0; return NULL; }
236     }
237     dp = (struct dirent*) (dir->dd_buf + dir->dd_loc);
238     if(dp->d_reclen == 0 || dp->d_reclen > dir->dd_len - dir->dd_loc) return NULL;
239     dir->dd_loc += dp->d_reclen;
240     return dp;
241 }
242
243 int closedir(DIR *dir) {
244     int fd = dir->dd_fd;
245     free(dir->dd_buf);
246     free(dir);
247     return close(fd);
248 }
249
250 /*
251  * Networking/Socket stuff
252  */
253
254 /* This should really be part of the newlib _reent structure */
255 int h_errno;
256
257 char *inet_ntoa(struct in_addr in) {
258     static char buf[18];
259     const unsigned char *p = (void*) &in;
260     snprintf(buf,sizeof(buf),"%u.%u.%u.%u",p[0],p[1],p[2],p[3]);
261     return buf;
262 }
263
264 struct servent *getservbyname(const char *name,const char *proto) {
265     return NULL;
266 }
267
268 static const char *h_errlist[] = { "No Error","Unknown host", "Host name lookup failure","Unknown server error","No address associated with name" };
269
270 const char *hstrerror(int err) {
271     if(err < 0 || err > 4) return "Unknown Error";
272     return h_errlist[err];
273 }
274
275 void herror(const char *string) {
276     fprintf(stderr,"%s: %s\n",string,hstrerror(h_errno));
277 }
278
279 extern int _resolve_ip(int addr, char *buf, size_t size);
280
281 struct hostent *gethostbyaddr(const char *addr, int len, int type) {
282     static struct hostent hostent;
283     static char name[128];
284     static char *aliases[1];
285     static char *addr_list[1];
286     static char addr_list_buf[4];
287     int err,i;
288     
289     if(type != AF_INET || len != 4) return NULL;
290     memcpy(&i,addr,4);
291     memcpy(addr_list_buf,addr,4);
292     err = _resolve_ip(i,name,sizeof(name));
293     if(err != 0) { h_errno = err; return NULL; }
294     
295     hostent.h_name = name;
296     hostent.h_aliases = aliases;
297     aliases[0] = NULL;
298     hostent.h_addrtype = AF_INET;
299     hostent.h_length = sizeof(struct in_addr);
300     hostent.h_addr_list = addr_list;
301     addr_list[0] = addr_list_buf;
302     
303     return &hostent;
304 }
305
306 extern int _resolve_hostname(const char *, char *buf, size_t *size);
307
308 struct hostent *gethostbyname(const char *hostname) {
309 #define MAX_ADDRS 256
310     static struct hostent hostent;
311     static char saved_hostname[128];
312     static char *addr_list[MAX_ADDRS+1];
313     static char addr_list_buf[MAX_ADDRS*sizeof(struct in_addr)];
314     static char *aliases[1];
315     
316     unsigned char buf[MAX_ADDRS*sizeof(struct in_addr)];
317     size_t size = sizeof(buf);
318     int err,i,n=0;
319     
320     err = _resolve_hostname(hostname,buf,&size);
321     if(err != 0) { h_errno = err; return NULL; }
322     
323     memcpy(addr_list_buf,buf,size);
324     for(i=0;i<size;i += sizeof(struct in_addr)) addr_list[n++] = &addr_list_buf[i];
325     addr_list[n] = NULL;
326     strncpy(saved_hostname,hostname,sizeof(saved_hostname));
327     aliases[0] = NULL;
328     
329     hostent.h_name = saved_hostname;
330     hostent.h_aliases = aliases;
331     hostent.h_addrtype = AF_INET;
332     hostent.h_length = sizeof(struct in_addr);
333     hostent.h_addr_list = addr_list;
334     
335     return &hostent;
336 }
337
338 static struct passwd pw_passwd;
339 static struct group gr_group;
340 static FILE *passwd_fp;
341 static FILE *group_fp;
342 static char pw_name[1024];
343 static char pw_password[1024];
344 static char pw_gecos[1024];
345 static char pw_dir[1024];
346 static char pw_shell[1024];
347 static char gr_name[1024];
348 static char gr_passwd[1024];
349 static char *gr_mem[1];
350
351 static int gr_parse_body(const char *buf) {
352     if(sscanf(buf,"%[^:]:%[^:]:%hu",gr_name,gr_passwd,&gr_group.gr_gid) < 3) return -1;
353     gr_group.gr_name = gr_name;
354     gr_group.gr_passwd = gr_passwd;
355     gr_group.gr_mem = gr_mem;
356     gr_mem[0] = NULL;
357     return 0;
358 }
359
360 static int pw_parse_body(const char *buf) {
361     int pos;
362     if(sscanf(buf,"%[^:]:%[^:]:%d:%d:%[^:]:%[^:]:%s\n",pw_name,pw_password,&pw_passwd.pw_uid,&pw_passwd.pw_gid,pw_gecos,pw_dir,pw_shell) < 7) return -1;
363     pw_passwd.pw_name = pw_name;
364     pw_passwd.pw_passwd = pw_password;
365     pw_passwd.pw_gecos = pw_gecos;
366     pw_passwd.pw_dir = pw_dir;
367     pw_passwd.pw_shell = pw_shell;
368     pw_passwd.pw_comment = "";
369     return 0;
370 }
371
372 struct group *getgrnam(const char *name) {
373     FILE *fp;
374     char buf[1024];
375     
376     if((fp=fopen("/etc/group","r"))==NULL) return NULL;
377     while(fgets(buf,sizeof(buf),fp)) {
378         if(buf[0] == '#') continue;
379         if(gr_parse_body(buf) < 0) {
380             fclose(fp);
381             return NULL;
382         }
383         if(strcmp(name,gr_name)==0) {
384             fclose(fp);
385             return &gr_group;
386         }
387     }
388     fclose(fp);
389     return NULL;
390 }
391
392 struct group *getgrgid(gid_t gid) {
393     FILE *fp;
394     char buf[1024];
395     
396     if((fp=fopen("/etc/group","r"))==NULL) return NULL;
397     while(fgets(buf,sizeof(buf),fp)) {
398         if(buf[0] == '#') continue;
399         if(gr_parse_body(buf) < 0) {
400             fclose(fp);
401             return NULL;
402         }
403         if(gid == gr_group.gr_gid) {
404             fclose(fp);
405             return &gr_group;
406         }
407     }
408     fclose(fp);
409     return NULL;
410 }
411     
412 struct group *getgrent() {
413     char buf[1024];
414     if(group_fp == NULL) return NULL;
415     if(fgets(buf,sizeof(buf),group_fp) == NULL) return NULL;
416     if(buf[0] == '#') return getgrent();
417     if(gr_parse_body(buf) < 0) return NULL;
418     return &gr_group;
419 }
420
421 void setgrent() { 
422     if(group_fp != NULL) fclose(group_fp);
423     group_fp = fopen("/etc/group","r");
424 }
425
426 void endgrent() {
427     if(group_fp != NULL) fclose(group_fp);
428     group_fp = NULL;
429 }
430
431 struct passwd *getpwnam(const char *name) {
432     FILE *fp;
433     char buf[1024];
434     
435     if((fp=fopen("/etc/passwd","r"))==NULL) return NULL;
436     while(fgets(buf,sizeof(buf),fp)) {
437         if(buf[0] == '#') continue;
438         if(pw_parse_body(buf) < 0) {
439             fclose(fp);
440             return NULL;
441         }
442         if(strcmp(name,pw_name)==0) {
443             fclose(fp);
444             return &pw_passwd;
445         }
446     }
447     fclose(fp);
448     return NULL;
449 }
450
451 struct passwd *getpwuid(uid_t uid) {
452     FILE *fp;
453     char buf[1024];
454     
455     if((fp=fopen("/etc/passwd","r"))==NULL) return NULL;
456     while(fgets(buf,sizeof(buf),fp)) {
457         if(buf[0] == '#') continue;
458         if(pw_parse_body(buf) < 0) {
459             fclose(fp);
460             return NULL;
461         }
462         if(uid == pw_passwd.pw_uid) {
463             fclose(fp);
464             return &pw_passwd;
465         }
466     }
467     fclose(fp);
468     return NULL;
469 }
470
471 struct passwd *getpwent() {
472     char buf[1024];
473     if(passwd_fp == NULL) return NULL;
474     if(fgets(buf,sizeof(buf),passwd_fp) == NULL) return NULL;
475     if(buf[0] == '#') return getpwent();
476     if(pw_parse_body(buf) < 0) return NULL;
477     return &pw_passwd;
478 }
479
480 void setpwent() { 
481     if(passwd_fp != NULL) fclose(passwd_fp);
482     passwd_fp = fopen("/etc/group","r");
483 }
484
485 void endpwent() {
486     if(passwd_fp != NULL) fclose(passwd_fp);
487     passwd_fp = NULL;
488 }
489
490 char *getpass(const char *prompt) {
491     static char buf[1024];
492     int len = 0;
493     fputs(prompt,stderr);
494     fflush(stdout);
495     if(fgets(buf,sizeof(buf),stdin)!=NULL) {
496         len = strlen(buf);
497         if(buf[len-1] == '\n') len--;
498     }
499     fputc('\n',stderr);
500     buf[len] = '\0';
501     return buf;
502 }
503
504 /* Argh... newlib's asprintf is totally broken... */
505 int vasprintf(char **ret, const char *fmt, va_list ap) {
506     int n;
507     char *p;
508     *ret = malloc(128); /* just guess for now */
509     if(!*ret) return -1;
510     n = vsnprintf(*ret,128,fmt,ap);
511     if(n < 128) {
512         return n;
513     } else {
514         p = realloc(*ret,n+1);
515         if(!p) { free(*ret); return -1; }
516         return vsprintf(*ret = p,fmt,ap);
517     }
518 }
519
520
521 /*
522  * Other People's Code 
523  */
524
525 /* FreeBSD's dirname/basename */
526
527 /* FIXME: Put these in a header */
528
529 /*
530  * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
531  * All rights reserved.
532  *
533  * Redistribution and use in source and binary forms, with or without
534  * modification, are permitted provided that the following conditions
535  * are met:
536  * 1. Redistributions of source code must retain the above copyright
537  *    notice, this list of conditions and the following disclaimer.
538  * 2. Redistributions in binary form must reproduce the above copyright
539  *    notice, this list of conditions and the following disclaimer in the
540  *    documentation and/or other materials provided with the distribution.
541  * 3. The name of the author may not be used to endorse or promote products
542  *    derived from this software without specific prior written permission.
543  *
544  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
545  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
546  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
547  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
548  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
549  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
550  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
551  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
552  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
553  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
554  */
555
556 char *
557 dirname(path)
558 const char *path;
559 {
560     static char bname[MAXPATHLEN];
561     register const char *endp;
562     
563     /* Empty or NULL string gets treated as "." */
564     if (path == NULL || *path == '\0') {
565         (void)strcpy(bname, ".");
566         return(bname);
567     }
568     
569     /* Strip trailing slashes */
570     endp = path + strlen(path) - 1;
571     while (endp > path && *endp == '/')
572         endp--;
573     
574     /* Find the start of the dir */
575     while (endp > path && *endp != '/')
576         endp--;
577     
578     /* Either the dir is "/" or there are no slashes */
579     if (endp == path) {
580         (void)strcpy(bname, *endp == '/' ? "/" : ".");
581         return(bname);
582     } else {
583         do {
584             endp--;
585         } while (endp > path && *endp == '/');
586     }
587     
588     if (endp - path + 2 > sizeof(bname)) {
589         errno = ENAMETOOLONG;
590         return(NULL);
591     }
592     (void)strncpy(bname, path, endp - path + 1);
593     bname[endp - path + 1] = '\0';
594     return(bname);
595 }
596
597 char *
598 basename(path)
599 const char *path;
600 {
601     static char bname[MAXPATHLEN];
602     register const char *endp, *startp;
603     
604     /* Empty or NULL string gets treated as "." */
605     if (path == NULL || *path == '\0') {
606         (void)strcpy(bname, ".");
607         return(bname);
608     }
609     
610     /* Strip trailing slashes */
611     endp = path + strlen(path) - 1;
612     while (endp > path && *endp == '/')
613         endp--;
614     
615     /* All slashes becomes "/" */
616     if (endp == path && *endp == '/') {
617         (void)strcpy(bname, "/");
618         return(bname);
619     }
620     
621     /* Find the start of the base */
622     startp = endp;
623     while (startp > path && *(startp - 1) != '/')
624         startp--;
625     
626     if (endp - startp + 2 > sizeof(bname)) {
627         errno = ENAMETOOLONG;
628         return(NULL);
629     }
630     (void)strncpy(bname, startp, endp - startp + 1);
631     bname[endp - startp + 1] = '\0';
632     return(bname);
633 }
634
635 /* FreeBSD's uname */
636 int
637 uname(name)
638 struct utsname *name;
639 {
640         int mib[2], rval;
641         size_t len;
642         char *p;
643         int oerrno;
644     
645         rval = 0;
646     
647         mib[0] = CTL_KERN;
648         mib[1] = KERN_OSTYPE;
649         len = sizeof(name->sysname);
650         oerrno = errno;
651         if (sysctl(mib, 2, &name->sysname, &len, NULL, 0) == -1) {
652                 if(errno == ENOMEM)
653                         errno = oerrno;
654                 else
655                         rval = -1;
656         }
657         name->sysname[sizeof(name->sysname) - 1] = '\0';
658     
659         mib[0] = CTL_KERN;
660         mib[1] = KERN_HOSTNAME;
661         len = sizeof(name->nodename);
662         oerrno = errno;
663         if (sysctl(mib, 2, &name->nodename, &len, NULL, 0) == -1) {
664                 if(errno == ENOMEM)
665                         errno = oerrno;
666                 else
667                         rval = -1;
668         }
669         name->nodename[sizeof(name->nodename) - 1] = '\0';
670     
671         mib[0] = CTL_KERN;
672         mib[1] = KERN_OSRELEASE;
673         len = sizeof(name->release);
674         oerrno = errno;
675         if (sysctl(mib, 2, &name->release, &len, NULL, 0) == -1) {
676                 if(errno == ENOMEM)
677                         errno = oerrno;
678                 else
679                         rval = -1;
680         }
681         name->release[sizeof(name->release) - 1] = '\0';
682     
683         /* The version may have newlines in it, turn them into spaces. */
684         mib[0] = CTL_KERN;
685         mib[1] = KERN_VERSION;
686         len = sizeof(name->version);
687         oerrno = errno;
688         if (sysctl(mib, 2, &name->version, &len, NULL, 0) == -1) {
689                 if (errno == ENOMEM)
690                         errno = oerrno;
691                 else
692                         rval = -1;
693         }
694         name->version[sizeof(name->version) - 1] = '\0';
695         for (p = name->version; len--; ++p) {
696                 if (*p == '\n' || *p == '\t') {
697                         if (len > 1)
698                                 *p = ' ';
699                         else
700                                 *p = '\0';
701                 }
702         }
703     
704         mib[0] = CTL_HW;
705         mib[1] = HW_MACHINE;
706         len = sizeof(name->machine);
707         oerrno = errno;
708         if (sysctl(mib, 2, &name->machine, &len, NULL, 0) == -1) {
709                 if (errno == ENOMEM)
710                         errno = oerrno;
711                 else
712                         rval = -1;
713         }
714         name->machine[sizeof(name->machine) - 1] = '\0';
715         return (rval);
716 }
717
718 /* FreeBSD's gethostname */
719 int
720 gethostname(name, namelen)
721 char *name;
722 int namelen;
723 {
724     int mib[2];
725     size_t size;
726     
727     mib[0] = CTL_KERN;
728     mib[1] = KERN_HOSTNAME;
729     size = namelen;
730     if (sysctl(mib, 2, name, &size, NULL, 0) == -1)
731         return (-1);
732     return (0);
733 }
734
735 /* FreeBSD's daemon() - modified for nestedvm */
736 int
737 daemon(nochdir, noclose)
738 int nochdir, noclose;
739 {
740         int fd;
741     
742         switch (fork()) {
743         case -1:
744             return (-1);
745         case 0:
746             break;
747         default:
748             _exit(0);
749         }
750     
751         if (setsid() == -1)
752                 return (-1);
753     
754         if (!nochdir)
755                 (void)chdir("/");
756     
757         if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
758                 (void)dup2(fd, STDIN_FILENO);
759                 (void)dup2(fd, STDOUT_FILENO);
760                 (void)dup2(fd, STDERR_FILENO);
761                 if (fd > 2)
762                         (void)close(fd);
763         }
764         return (0);
765 }
766
767 /* FreeBSD's inet_addr/inet_aton */
768
769 /* 
770 * Check whether "cp" is a valid ASCII representation
771  * of an Internet address and convert to a binary address.
772  * Returns 1 if the address is valid, 0 if not.
773  * This replaces inet_addr, the return value from which
774  * cannot distinguish between failure and a local broadcast address.
775  */
776 int
777 inet_aton(cp, addr)
778 register const char *cp;
779 struct in_addr *addr;
780 {
781         u_long parts[4];
782         in_addr_t val;
783         char *c;
784         char *endptr;
785         int gotend, n;
786     
787         c = (char *)cp;
788         n = 0;
789         /*
790          * Run through the string, grabbing numbers until
791          * the end of the string, or some error
792          */
793         gotend = 0;
794         while (!gotend) {
795                 errno = 0;
796                 val = strtoul(c, &endptr, 0);
797         
798                 if (errno == ERANGE)    /* Fail completely if it overflowed. */
799                         return (0);
800                 
801                 /* 
802             * If the whole string is invalid, endptr will equal
803                  * c.. this way we can make sure someone hasn't
804                  * gone '.12' or something which would get past
805                  * the next check.
806                  */
807                 if (endptr == c)
808                         return (0);
809                 parts[n] = val;
810                 c = endptr;
811         
812                 /* Check the next character past the previous number's end */
813                 switch (*c) {
814             case '.' :
815                 /* Make sure we only do 3 dots .. */
816                 if (n == 3)     /* Whoops. Quit. */
817                     return (0);
818                 n++;
819                 c++;
820                 break;
821                 
822             case '\0':
823                 gotend = 1;
824                 break;
825                 
826             default:
827                 if (isspace((unsigned char)*c)) {
828                     gotend = 1;
829                     break;
830                 } else
831                     return (0); /* Invalid character, so fail */
832                 }
833         
834         }
835     
836         /*
837          * Concoct the address according to
838          * the number of parts specified.
839          */
840     
841         switch (n) {
842         case 0:                         /* a -- 32 bits */
843             /*
844              * Nothing is necessary here.  Overflow checking was
845              * already done in strtoul().
846              */
847             break;
848         case 1:                         /* a.b -- 8.24 bits */
849             if (val > 0xffffff || parts[0] > 0xff)
850                 return (0);
851             val |= parts[0] << 24;
852             break;
853             
854         case 2:                         /* a.b.c -- 8.8.16 bits */
855             if (val > 0xffff || parts[0] > 0xff || parts[1] > 0xff)
856                 return (0);
857             val |= (parts[0] << 24) | (parts[1] << 16);
858                 break;
859                 
860             case 3:                             /* a.b.c.d -- 8.8.8.8 bits */
861                 if (val > 0xff || parts[0] > 0xff || parts[1] > 0xff ||
862                     parts[2] > 0xff)
863                     return (0);
864                 val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
865                     break;
866         }
867     
868         if (addr != NULL)
869                 addr->s_addr = htonl(val);
870         return (1);
871 }
872
873 /*
874  * ASCII internet address interpretation routine.
875  * The value returned is in network order.
876  */
877 in_addr_t               /* XXX should be struct in_addr :( */
878 inet_addr(cp)
879 register const char *cp;
880 {
881         struct in_addr val;
882     
883         if (inet_aton(cp, &val))
884                 return (val.s_addr);
885         return (INADDR_NONE);
886 }
887
888 int
889 getgrouplist(uname, agroup, groups, grpcnt)
890 const char *uname;
891 gid_t agroup;
892 register gid_t *groups;
893 int *grpcnt;
894 {
895         register struct group *grp;
896         register int i, ngroups;
897         int ret, maxgroups;
898     
899         ret = 0;
900         ngroups = 0;
901         maxgroups = *grpcnt;
902         /*
903          * When installing primary group, duplicate it;
904          * the first element of groups is the effective gid
905          * and will be overwritten when a setgid file is executed.
906          */
907         groups[ngroups++] = agroup;
908         if (maxgroups > 1)
909                 groups[ngroups++] = agroup;
910         /*
911          * Scan the group file to find additional groups.
912          */
913         setgrent();
914         while ((grp = getgrent())) {
915                 for (i = 0; i < ngroups; i++) {
916                         if (grp->gr_gid == groups[i])
917                                 goto skip;
918                 }
919                 for (i = 0; grp->gr_mem[i]; i++) {
920                         if (!strcmp(grp->gr_mem[i], uname)) {
921                                 if (ngroups >= maxgroups) {
922                                         ret = -1;
923                                         break;
924                                 }
925                                 groups[ngroups++] = grp->gr_gid;
926                                 break;
927                         }
928                 }
929 skip: ;
930         }
931         endgrent();
932         *grpcnt = ngroups;
933         return (ret);
934 }
935
936 int
937 initgroups(uname, agroup)
938 const char *uname;
939 gid_t agroup;
940 {
941     gid_t groups[32], ngroups;
942     
943     ngroups = 32;
944     getgrouplist(uname, agroup, groups, &ngroups);
945     return (setgroups(ngroups, groups));
946 }