Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

#include "lib.h"
#include <unistd.h>
#include <errno.h>
#include <stdarg.h>
#include "sys9.h"

/*
 * BUG: advisory locking not implemented
 */

#define OFL (O_ACCMODE|O_NONBLOCK|O_APPEND)

int
fcntl(int fd, int cmd, ...)
{
        int arg, i, ans, err;
        Fdinfo *fi, *fans;
        va_list va;
        unsigned long oflags;

        err = 0;
        ans = 0;
        va_start(va, cmd);
        arg = va_arg(va, int);
        va_end(va);
        fi = &_fdinfo[fd];
        if(fd<0 || fd>=OPEN_MAX || !(fi->flags&FD_ISOPEN))
                err = EBADF;
        else switch(cmd){
                case F_DUPFD:
                        if(fi->flags&(FD_BUFFERED|FD_BUFFEREDX)){
                                err = EGREG;    /* dup of buffered fd not implemented */
                                break;
                        }
                        oflags = fi->oflags;
                        for(i = (arg>0)? arg : 0; i<OPEN_MAX; i++)
                                if(!(_fdinfo[i].flags&FD_ISOPEN))
                                        break;
                        if(i == OPEN_MAX)
                                err = EMFILE;
                        else {
                                ans = _DUP(fd, i);
                                if(ans != i){
                                        if(ans < 0){
                                                _syserrno();
                                                err = errno;
                                        }else
                                                err = EBADF;
                                }else{
                                        fans = &_fdinfo[ans];
                                        fans->flags = fi->flags&~FD_CLOEXEC;
                                        fans->oflags = oflags;
                                        fans->uid = fi->uid;
                                        fans->gid = fi->gid;
                                }
                        }
                        break;
                case F_GETFD:
                        ans = fi->flags&FD_CLOEXEC;
                        break;
                case F_SETFD:
                        fi->flags = (fi->flags&~FD_CLOEXEC)|(arg&FD_CLOEXEC);
                        break;
                case F_GETFL:
                        ans = fi->oflags&OFL;
                        break;
                case F_SETFL:
                        fi->oflags = (fi->oflags&~OFL)|(arg&OFL);
                        break;
                case F_GETLK:
                case F_SETLK:
                case F_SETLKW:
                        err = EINVAL;
                        break;
                }
        if(err){
                errno = err;
                ans = -1;
        }
        return ans;
}