/*
 *  This file is part of ixemul.library for the Amiga.
 *  Copyright (C) 1991, 1992  Markus M. Wild
 *  Portions Copyright (C) 1994 Rafael W. Luebbert
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library General Public Licengse for more details.
 *
 *  You should have received a copy of the GNU Library General Public
 *  License along with this library; if not, write to the Free
 *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *  $Id: kern_descrip.c,v 1.3 1994/06/19 15:13:31 rluebbert Exp $
 *
 *  $Log: kern_descrip.c,v $
 *  Revision 1.3  1994/06/19  15:13:31	rluebbert
 *  *** empty log message ***
 *
 * Revision 1.1  1992/05/14  19:55:40  mwild
 * Initial revision
 *
 *
 *  Since the code originated from Berkeley, the following copyright
 *  header applies as well. The code has been changed, it's not the
 *  original Berkeley code!
 */

/*
 * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution is only permitted until one year after the first shipment
 * of 4.4BSD by the Regents.  Otherwise, redistribution and use in source and
 * binary forms are permitted provided that: (1) source distributions retain
 * this entire copyright notice and comment, and (2) distributions including
 * binaries display the following acknowledgement:  This product includes
 * software developed by the University of California, Berkeley and its
 * contributors'' in the documentation or other materials provided with the
 * distribution and in all advertising materials mentioning features or use
 * of this software.  Neither the name of the University nor the names of
 * its contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 *	@(#)kern_descrip.c      7.16 (Berkeley) 6/28/90
 */

/* modified by Jeff Shepherd to allow use of sockets
 * replaces functions normally found in ixemul.library
 * makes it easier than making a new library
 */
#define KERNEL
#include <library/ixemul.h>
#include <sys/socket.h>
#include <proto/socket.h>
#include <proto/usergroup.h>
#include <clib/exec_protos.h>
#include <sys/syslog.h>

#define USE_NEW

#define usr (*((struct user *)((struct Task *)(FindTask(0))->tc_TrapData)))
#undef u_save
#define u_save (*((struct user *)((struct Task *)(FindTask(0))->tc_TrapData)))
extern int gcc_fstat (unsigned fdes, struct stat *sb);

void
ix_lock_base ()
{
  u_save.u_oldmask = u_save.p_sigmask;
  u_save.p_sigmask = ~0;
  ObtainSemaphore (& ix.ix_semaph);
}

void
ix_unlock_base ()
{
  ReleaseSemaphore (& ix.ix_semaph);
  u_save.p_sigmask = u_save.u_oldmask;
}



extern struct ixemul_base *ixemulbase;

/*
 * Descriptor management.
 */

/*
 * System calls on descriptors.
 */
/* ARGSUSED */
int
dup (int i)
{
  struct file *fp=u.u_ofile[i];
  int fd, error;


  if (i >= NOFILE || fp == NULL)
    {
      errno = EBADF;
      return -1;
    }

  if (fp->f_flags == DTYPE_SOCKET)
    { /* for sockets */
      syslog(LOG_DEBUG,"dup for sockets");
      return Dup2Socket(i, -1);
    }

  syslog(LOG_DEBUG,"dup for file");
  if (error = ufalloc (0, &fd))
    {
      errno = error;
      return -1;
    }

  u.u_ofile[fd] = fp;
  u.u_pofile[fd] = u.u_pofile[i] &~ UF_EXCLOSE;
  fp->f_count++;

  if (fd > u.u_lastfile) u.u_lastfile = fd;

  errno = 0;
  return fd;
}


/*
 * Duplicate a file descriptor to a particular value.
 */
/* ARGSUSED */
#ifdef USE_NEW_DUP2
int
dup2 (unsigned i, unsigned j)
{
  register struct file *fp= u.u_ofile[i];
  register struct file *tofp = u.u_ofile[j];
  int error;

  if (i >= NOFILE || j >= NOFILE)
    {
      errno = EBADF;
      return -1;
    }


  if (j < 0 || j >= NOFILE)
    {
      errno = EBADF;
      return -1;
    }

  errno = 0;
  if (i == j) return (int)j;

  #if 1
  /* socket */
  if (fp && fp->f_type == DTYPE_SOCKET) {
    syslog(LOG_DEBUG,"dup2 for sockets");
    return Dup2Socket(i, j);
  }

  syslog(LOG_DEBUG,"dup2 for files");
  #endif

  ix_lock_base ();

  if (u.u_ofile[j] && u.u_ofile[j]->f_close)
    u.u_ofile[j]->f_close (u.u_ofile[j]);

  u.u_ofile[j] = fp;
  u.u_pofile[j] = u.u_pofile[i] &~ UF_EXCLOSE;
  fp->f_count++;
  if (j > u.u_lastfile)
    u.u_lastfile = j;

  ix_unlock_base ();

  /*
   * dup2() must suceed even though the close had an error.
   */
  errno = 0;		/* XXX */

  #if 0
  if (fp->f_type == DTYPE_SOCKET) {
    syslog(LOG_DEBUG,"dup2 for sockets");
    return Dup2Socket(i, j);
  }
 #endif

  return (int)j;

}
#endif

/*
 * Return status information about a file descriptor.
 */
/* ARGSUSED */
int
fstat (unsigned fdes, struct stat *sb)
{
  struct file *f = usr.u_ofile[fdes];

  if (fdes >= NOFILE || f == NULL)
    {
      errno = EBADF;
      return -1;
    }

    if (f->f_type == DTYPE_SOCKET) {
       long value;
       long size = sizeof(value);

       bzero(sb, sizeof(*sb));

       /* st->st_dev = ??? */
       sb->st_mode = S_IFSOCK | S_IRUSR | S_IWUSR;
       sb->st_uid = geteuid();
       sb->st_gid = getegid();

       if (getsockopt(fdes, SOL_SOCKET, SO_SNDBUF, &value, &size) == 0)
	 sb->st_blksize = value;
       return 0;
    }/* if */

    return gcc_fstat(fdes,sb);
}
