uname/sysctl support
[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 <nestedvm/sockets.h>
15 #include <paths.h>
16
17 int _syscall_set_errno(struct _reent *ptr, int err) {
18     ptr->_errno = -err;
19     return -1;
20 }
21
22 extern int _stat_r(struct _reent *, const char *, struct stat *);
23 int _access_r(struct _reent *ptr, const char *pathname, int mode) {
24     struct stat statbuf;
25     if(_stat_r(ptr,pathname,&statbuf) < 0) return -1;
26     return 0;
27 }
28
29 /* NestedVM doesn't, and probably never will, support this security related stuff */
30 uid_t getuid() { return 0; }
31 gid_t getgid() { return 0; }
32 uid_t geteuid() { return 0; }
33 gid_t getegid() { return 0; }
34 int getgroups(int gidsetlen, gid_t *gidset) {
35     if(gidsetlen) *gidset = 0;
36     return 1;
37 }
38 mode_t umask(mode_t new) { return 0022; }
39 int _chmod_r(struct _reent *ptr, const char *f, mode_t mode) { return 0; }
40 int _fchmod_r(struct _reent *ptr, int fd, mode_t mode) { return 0; }
41 int _chown_r(struct _reent *ptr, const char *f, uid_t uid, gid_t gid) { return 0; }
42 int _fchown_r(struct _reent *ptr, int fd, uid_t uid, gid_t gid) { return 0; }
43
44 #define REENT_WRAPPER0R(f,rt) \
45     extern rt _##f##_r(struct _reent *ptr); \
46     rt f() { return _##f##_r(_REENT); }
47 #define REENT_WRAPPER0(f) REENT_WRAPPER0R(f,int)
48
49 #define REENT_WRAPPER1R(f,rt,t1) \
50     extern rt _##f##_r(struct _reent *ptr, t1 a); \
51     rt f(t1 a) { return _##f##_r(_REENT,a); }
52 #define REENT_WRAPPER1(f,t1) REENT_WRAPPER1R(f,int,t1)
53
54 #define REENT_WRAPPER2R(f,rt,t1,t2) \
55     extern rt _##f##_r(struct _reent *ptr, t1 a, t2 b); \
56     rt f(t1 a, t2 b) { return _##f##_r(_REENT,a,b); }
57 #define REENT_WRAPPER2(f,t1,t2) REENT_WRAPPER2R(f,int,t1,t2)
58
59 #define REENT_WRAPPER3R(f,rt,t1,t2,t3) \
60     extern rt _##f##_r(struct _reent *ptr, t1 a, t2 b, t3 c); \
61     rt f(t1 a, t2 b, t3 c) { return _##f##_r(_REENT,a,b,c); }
62 #define REENT_WRAPPER3(f,t1,t2,t3) REENT_WRAPPER3R(f,int,t1,t2,t3)
63
64 #define REENT_WRAPPER4R(f,rt,t1,t2,t3,t4) \
65 extern rt _##f##_r(struct _reent *ptr, t1 a, t2 b, t3 c, t4 d); \
66 rt f(t1 a, t2 b, t3 c, t4 d) { return _##f##_r(_REENT,a,b,c,d); }
67 #define REENT_WRAPPER4(f,t1,t2,t3,t4) REENT_WRAPPER4R(f,int,t1,t2,t3,t4)
68
69 #define REENT_WRAPPER5R(f,rt,t1,t2,t3,t4,t5) \
70 extern rt _##f##_r(struct _reent *ptr, t1 a, t2 b, t3 c, t4 d, t5 e); \
71 rt f(t1 a, t2 b, t3 c, t4 d, t5 e) { return _##f##_r(_REENT,a,b,c,d,e); }
72 #define REENT_WRAPPER5(f,t1,t2,t3,t4,t5) REENT_WRAPPER5R(f,int,t1,t2,t3,t4,t5)
73
74 #define REENT_WRAPPER6R(f,rt,t1,t2,t3,t4,t5,t6) \
75 extern rt _##f##_r(struct _reent *ptr, t1 a, t2 b, t3 c, t4 d, t5 e, t6 f); \
76 rt f(t1 a, t2 b, t3 c, t4 d, t5 e, t6 f) { return _##f##_r(_REENT,a,b,c,d,e,f); }
77 #define REENT_WRAPPER6(f,t1,t2,t3,t4,t5,t6) REENT_WRAPPER6R(f,int,t1,t2,t3,t4,t5,t6)
78
79 REENT_WRAPPER2(mkdir,const char *,mode_t)
80 REENT_WRAPPER2(access,const char *,int)
81 REENT_WRAPPER1(rmdir,const char *)
82 REENT_WRAPPER1R(sysconf,long,int)
83 REENT_WRAPPER1(chdir,const char*)
84 REENT_WRAPPER2(utime,const char *,const struct utimbuf *)
85 REENT_WRAPPER1(pipe,int *)
86 REENT_WRAPPER2(dup2,int,int)
87 REENT_WRAPPER3(waitpid,pid_t,int *,int)
88 REENT_WRAPPER2R(getcwd,char *,char *,size_t)
89 REENT_WRAPPER2R(_getcwd,char *,char *,size_t)
90 REENT_WRAPPER2(symlink,const char *,const char *)
91 REENT_WRAPPER3(readlink,const char *, char *,int)
92 REENT_WRAPPER3(chown,const char *,uid_t,gid_t)
93 REENT_WRAPPER3(fchown,int,uid_t,gid_t)
94 REENT_WRAPPER3(lchown,const char *,uid_t,gid_t)
95 REENT_WRAPPER2(chmod,const char *,mode_t)
96 REENT_WRAPPER2(fchmod,int,mode_t)
97 REENT_WRAPPER2(lstat,const char *,struct stat *)
98 REENT_WRAPPER4(getdents,int, char *, size_t,long *)
99 REENT_WRAPPER1(dup,int)
100 REENT_WRAPPER2R(pathconf,long,const char *,int)
101 REENT_WRAPPER0(vfork)
102 REENT_WRAPPER1(chroot,const char *)
103 REENT_WRAPPER3(mknod,const char *,mode_t,dev_t)
104 REENT_WRAPPER2(ftruncate,int,off_t)
105 REENT_WRAPPER1(usleep,unsigned int)
106 REENT_WRAPPER2(mkfifo,const char *, mode_t)
107 REENT_WRAPPER3(klogctl,int,char*,int)
108 REENT_WRAPPER2R(realpath,char *,const char *,char *)
109 REENT_WRAPPER6(_sysctl,int *,int, void *, size_t*, void *, size_t)
110 REENT_WRAPPER6(sysctl,int *, int, void *, size_t*, void *, size_t)
111 REENT_WRAPPER2(getpriority,int,int)
112 REENT_WRAPPER3(setpriority,int,int,int)
113 REENT_WRAPPER3(connect,int,const struct sockaddr *,socklen_t)
114 REENT_WRAPPER3(socket,int,int,int)
115 REENT_WRAPPER3(_resolve_hostname,const char *,char*,size_t*)
116 REENT_WRAPPER3(accept,int,struct sockaddr *,socklen_t*)
117 REENT_WRAPPER5(getsockopt,int,int,int,void*,socklen_t*)
118 REENT_WRAPPER5(setsockopt,int,int,int,const void*,socklen_t)
119 REENT_WRAPPER3(bind,int,const struct sockaddr *,socklen_t)
120 REENT_WRAPPER2(listen,int,int)
121 REENT_WRAPPER2(shutdown,int,int)
122
123 extern int __execve_r(struct _reent *ptr, const char *path, char *const argv[], char *const envp[]);
124 int _execve(const char *path, char *const argv[], char *const envp[]) {
125     return __execve_r(_REENT,path,argv,envp);
126 }
127
128 char *_getcwd_r(struct _reent *ptr, char *buf, size_t size) {
129     if(buf != NULL) {
130         buf = __getcwd_r(ptr,buf,size);
131         return (long)buf == -1 ? NULL : buf;
132     }
133     
134     size = 256;
135     for(;;) {
136         buf = malloc(size);
137         char *ret = __getcwd_r(ptr,buf,size);
138         if((long)ret != -1) return ret;
139         free(buf);
140         size *= 2;
141         if(ptr->_errno != ERANGE) return NULL;
142     }
143 }
144
145 pid_t _wait_r(struct _reent *ptr, int *status) {
146     return _waitpid_r(ptr,-1,status,0);
147 }
148
149 long _pathconf_r(struct _reent *ptr,const char *path, int name) {
150     switch(name) {
151         default:
152             fprintf(stderr,"WARNING: pathconf: Unknown \"name\": %d\n",name);
153             ptr->_errno = EINVAL;
154             return -1;
155     }
156 }
157
158 int _sysctl_r(struct _reent *ptr, int *name, int namelen, void *oldp, size_t *oldlen, void *newp, size_t newlen) {
159     if(name[0] != CTL_USER) return _sysctl(name,namelen,oldp,oldlen,newp,newlen);
160     if(newp != NULL) { ptr->_errno = EPERM; return -1; }
161     if(namelen != 2) { ptr->_errno = EINVAL; return -1; }
162     
163     switch(name[1]) {
164         default:
165             fprintf(stderr,"WARNING: sysctl: Unknown name: %d\n",name[1]);
166             ptr->_errno = EINVAL;
167             return -1;
168     }
169 }
170
171 void sync() {
172     /* do nothing*/
173 }
174
175 int fsync(int fd) {
176     /* do nothing */
177     return 0;
178 }
179
180 char *ttyname(int fd) {
181     return isatty(fd) ? "/dev/console" : NULL;
182 }
183
184 int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) {
185     _sig_func_ptr old;
186     _sig_func_ptr new;
187     if(act) {
188         if(act->sa_flags || act->sa_mask != ~((sigset_t)0)) { errno = EINVAL; return -1; }
189         old = signal(sig,act->sa_handler);
190     } else if(oact) {
191         old = signal(sig,SIG_DFL);
192         signal(sig,old);
193     }
194     if(oact) {
195         oact->sa_handler = old;
196         oact->sa_mask = 0;
197         oact->sa_mask = ~((sigset_t)0);
198     }
199     return 0;
200 }
201
202 int sigfillset(sigset_t *set) {
203     *set = ~((sigset_t)0);
204     return 0;
205 }
206
207 int sigemptyset(sigset_t *set) {
208     *set = (sigset_t) 0;
209     return 0;
210 }
211
212 DIR *opendir(const char *path) {
213     struct stat sb;
214     int fd;
215     DIR *dir;
216     
217     fd = open(path,O_RDONLY);
218     if(fd < 0) return NULL;
219     
220     if(fstat(fd,&sb) < 0 || !S_ISDIR(sb.st_mode)) {
221         close(fd);
222         errno = ENOTDIR;
223         return NULL;
224     }
225     
226     dir = malloc(sizeof(*dir));
227     if(dir == NULL) {
228         close(fd);
229         errno = ENOMEM;
230         return NULL;
231     }
232     dir->dd_fd = fd;
233     dir->dd_buf = malloc(sizeof(struct dirent));
234     dir->dd_size = sizeof(struct dirent);
235     if(dir->dd_buf == NULL) {
236         close(fd);
237         free(dir);
238         return NULL;
239     }
240     dir->dd_loc = 0;
241     dir->dd_len = 0;
242     return dir;
243 }
244
245 struct dirent *readdir(DIR *dir) {
246     struct dirent *dp;
247     errno = 0;
248     if(dir->dd_loc == 0 || dir->dd_loc == dir->dd_len) {
249         dir->dd_len = getdents(dir->dd_fd,dir->dd_buf,dir->dd_size,NULL);
250         dir->dd_loc = 0;
251         if(dir->dd_len <= 0) { dir->dd_len = 0; return NULL; }
252     }
253     dp = (struct dirent*) (dir->dd_buf + dir->dd_loc);
254     if(dp->d_reclen == 0 || dp->d_reclen > dir->dd_len - dir->dd_loc) return NULL;
255     dir->dd_loc += dp->d_reclen;
256     return dp;
257 }
258
259 int closedir(DIR *dir) {
260     int fd = dir->dd_fd;
261     free(dir->dd_buf);
262     free(dir);
263     return close(fd);
264 }
265
266 /*
267  * Networking/Socket stuff
268  */
269
270 /* This should really be part of the newlib _reent structure */
271 int h_errno;
272
273 char *inet_ntoa(struct in_addr in) {
274     static char buf[18];
275     const unsigned char *p = (void*) &in;
276     snprintf(buf,sizeof(buf),"%u.%u.%u.%u",p[0],p[1],p[2],p[3]);
277     return buf;
278 }
279
280 struct servent *getservbyname(const char *name,const char *proto) {
281     return NULL;
282 }
283
284 static const char *h_errlist[] = { "No Error","Unknown host", "Host name lookup failure","Unknown server error","No address associated with name" };
285
286 const char *hstrerror(int err) {
287     if(err < 0 || err > 4) return "Unknown Error";
288     return h_errlist[err];
289 }
290
291 void herror(const char *string) {
292     fprintf(stderr,"%s: %s\n",string,hstrerror(h_errno));
293 }
294
295 extern int _resolve_hostname(const char *, char *buf, size_t *size);
296
297 struct hostent *gethostbyname(const char *hostname) {
298 #define MAX_ADDRS 256
299     static struct hostent hostent;
300     static char saved_hostname[128];
301     static char *addr_list[MAX_ADDRS+1];
302     static char addr_list_buf[MAX_ADDRS*sizeof(struct in_addr)];
303     static char *aliases[1];
304     
305     unsigned char buf[MAX_ADDRS*sizeof(struct in_addr)];
306     size_t size = sizeof(buf);
307     int err,i,n=0;
308     
309     err = _resolve_hostname(hostname,buf,&size);
310     if(err != 0) { h_errno = err; return NULL; }
311     
312     memcpy(addr_list_buf,buf,size);
313     for(i=0;i<size;i += sizeof(struct in_addr)) addr_list[n++] = &addr_list_buf[i];
314     addr_list[n] = NULL;
315     strncpy(saved_hostname,hostname,sizeof(saved_hostname));
316     aliases[0] = NULL;
317     
318     hostent.h_name = saved_hostname;
319     hostent.h_aliases = aliases;
320     hostent.h_addrtype = AF_INET;
321     hostent.h_length = sizeof(struct in_addr);
322     hostent.h_addr_list = addr_list;
323     
324     return &hostent;
325 }
326
327 /*
328  * Other People's Code 
329  */
330
331 /* FreeBSD's dirname/basename */
332
333 /* FIXME: Put these in a header */
334
335 /*
336  * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
337  * All rights reserved.
338  *
339  * Redistribution and use in source and binary forms, with or without
340  * modification, are permitted provided that the following conditions
341  * are met:
342  * 1. Redistributions of source code must retain the above copyright
343  *    notice, this list of conditions and the following disclaimer.
344  * 2. Redistributions in binary form must reproduce the above copyright
345  *    notice, this list of conditions and the following disclaimer in the
346  *    documentation and/or other materials provided with the distribution.
347  * 3. The name of the author may not be used to endorse or promote products
348  *    derived from this software without specific prior written permission.
349  *
350  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
351  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
352  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
353  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
354  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
355  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
356  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
357  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
358  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
359  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
360  */
361
362 char *
363 dirname(path)
364 const char *path;
365 {
366     static char bname[MAXPATHLEN];
367     register const char *endp;
368     
369     /* Empty or NULL string gets treated as "." */
370     if (path == NULL || *path == '\0') {
371         (void)strcpy(bname, ".");
372         return(bname);
373     }
374     
375     /* Strip trailing slashes */
376     endp = path + strlen(path) - 1;
377     while (endp > path && *endp == '/')
378         endp--;
379     
380     /* Find the start of the dir */
381     while (endp > path && *endp != '/')
382         endp--;
383     
384     /* Either the dir is "/" or there are no slashes */
385     if (endp == path) {
386         (void)strcpy(bname, *endp == '/' ? "/" : ".");
387         return(bname);
388     } else {
389         do {
390             endp--;
391         } while (endp > path && *endp == '/');
392     }
393     
394     if (endp - path + 2 > sizeof(bname)) {
395         errno = ENAMETOOLONG;
396         return(NULL);
397     }
398     (void)strncpy(bname, path, endp - path + 1);
399     bname[endp - path + 1] = '\0';
400     return(bname);
401 }
402
403 char *
404 basename(path)
405 const char *path;
406 {
407     static char bname[MAXPATHLEN];
408     register const char *endp, *startp;
409     
410     /* Empty or NULL string gets treated as "." */
411     if (path == NULL || *path == '\0') {
412         (void)strcpy(bname, ".");
413         return(bname);
414     }
415     
416     /* Strip trailing slashes */
417     endp = path + strlen(path) - 1;
418     while (endp > path && *endp == '/')
419         endp--;
420     
421     /* All slashes becomes "/" */
422     if (endp == path && *endp == '/') {
423         (void)strcpy(bname, "/");
424         return(bname);
425     }
426     
427     /* Find the start of the base */
428     startp = endp;
429     while (startp > path && *(startp - 1) != '/')
430         startp--;
431     
432     if (endp - startp + 2 > sizeof(bname)) {
433         errno = ENAMETOOLONG;
434         return(NULL);
435     }
436     (void)strncpy(bname, startp, endp - startp + 1);
437     bname[endp - startp + 1] = '\0';
438     return(bname);
439 }
440
441 /* FreeBSD's uname */
442 int
443 uname(name)
444 struct utsname *name;
445 {
446         int mib[2], rval;
447         size_t len;
448         char *p;
449         int oerrno;
450     
451         rval = 0;
452     
453         mib[0] = CTL_KERN;
454         mib[1] = KERN_OSTYPE;
455         len = sizeof(name->sysname);
456         oerrno = errno;
457         if (sysctl(mib, 2, &name->sysname, &len, NULL, 0) == -1) {
458                 if(errno == ENOMEM)
459                         errno = oerrno;
460                 else
461                         rval = -1;
462         }
463         name->sysname[sizeof(name->sysname) - 1] = '\0';
464     
465         mib[0] = CTL_KERN;
466         mib[1] = KERN_HOSTNAME;
467         len = sizeof(name->nodename);
468         oerrno = errno;
469         if (sysctl(mib, 2, &name->nodename, &len, NULL, 0) == -1) {
470                 if(errno == ENOMEM)
471                         errno = oerrno;
472                 else
473                         rval = -1;
474         }
475         name->nodename[sizeof(name->nodename) - 1] = '\0';
476     
477         mib[0] = CTL_KERN;
478         mib[1] = KERN_OSRELEASE;
479         len = sizeof(name->release);
480         oerrno = errno;
481         if (sysctl(mib, 2, &name->release, &len, NULL, 0) == -1) {
482                 if(errno == ENOMEM)
483                         errno = oerrno;
484                 else
485                         rval = -1;
486         }
487         name->release[sizeof(name->release) - 1] = '\0';
488     
489         /* The version may have newlines in it, turn them into spaces. */
490         mib[0] = CTL_KERN;
491         mib[1] = KERN_VERSION;
492         len = sizeof(name->version);
493         oerrno = errno;
494         if (sysctl(mib, 2, &name->version, &len, NULL, 0) == -1) {
495                 if (errno == ENOMEM)
496                         errno = oerrno;
497                 else
498                         rval = -1;
499         }
500         name->version[sizeof(name->version) - 1] = '\0';
501         for (p = name->version; len--; ++p) {
502                 if (*p == '\n' || *p == '\t') {
503                         if (len > 1)
504                                 *p = ' ';
505                         else
506                                 *p = '\0';
507                 }
508         }
509     
510         mib[0] = CTL_HW;
511         mib[1] = HW_MACHINE;
512         len = sizeof(name->machine);
513         oerrno = errno;
514         if (sysctl(mib, 2, &name->machine, &len, NULL, 0) == -1) {
515                 if (errno == ENOMEM)
516                         errno = oerrno;
517                 else
518                         rval = -1;
519         }
520         name->machine[sizeof(name->machine) - 1] = '\0';
521         return (rval);
522 }
523
524 /* FreeBSD's daemon() - modified for nestedvm */
525 int
526 daemon(nochdir, noclose)
527 int nochdir, noclose;
528 {
529         int fd;
530     
531         switch (fork()) {
532         case -1:
533             return (-1);
534         case 0:
535             break;
536         default:
537             _exit(0);
538         }
539     
540         /*if (setsid() == -1)
541                 return (-1);*/
542     
543         if (!nochdir)
544                 (void)chdir("/");
545     
546         if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
547                 (void)dup2(fd, STDIN_FILENO);
548                 (void)dup2(fd, STDOUT_FILENO);
549                 (void)dup2(fd, STDERR_FILENO);
550                 if (fd > 2)
551                         (void)close(fd);
552         }
553         return (0);
554 }