/*
 *  This file is part of ixemul.library for the Amiga.
 *  Copyright (C) 1991, 1992  Markus M. Wild
 *  Portions Copyright (C) 1994 Rafael W. Luebbert
 *  Portions Copyright (C) 1996 Jeff Shepherd
 *
 *  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 License 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: getcrap.c,v 1.2 1994/06/19 14:04:21 rluebbert Exp $
 *
 *  $Log: getcrap.c,v $
 * Revision 1.2  1994/06/19  14:04:21  rluebbert
 * Appeasing HWGRCS
 *
 * Revision 1.1  1994/06/19  14:02:22  rluebbert
 * Initial revision
 *
 *
 */


/* stubs for group-file access functions */

#define KERNEL
#include "ixemul.h"
#include "kprintf.h"
#include <stdlib.h>

int getpid(void)
{
  return (int) FindTask (0);
}


int getpgrp(int pid)
{
#ifdef USE_NET
  extern int NET_getpgrp(int);
  register struct user *p = &u;

    if (p->u_ixnetbase) {
	return NET_getpgrp(pid);
   }
#endif
  /* this could change later.. but we'll see .. */
  return pid ? pid : (int) FindTask(0);
}


int getgroups(int gidsetlen, int *gidset)
{
#ifdef USE_NET
  extern int NET_getgroups(int, int *);
  register struct user *p = &u;

    if (p->u_ixnetbase) {
	return NET_getgroups(gidsetlen,gidset);
    }
#endif
      /* we return 1 group, group 0 (you really ARE root on the amiga:-)) */
      if (gidsetlen >= 1)
        {
          *gidset = 0;
          return 1;
        }

  errno = EINVAL;
  KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
  return -1;
}

int getrusage (int who, struct rusage *rusage)
{
  if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN)
    {
      errno = EINVAL;
      KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
      return -1;
    }

  *rusage = (who == RUSAGE_SELF) ? u.u_ru : u.u_cru;
  return 0;
}

#include <grp.h>
#include <stdio.h>
static FILE *_gr_fp;
static struct group _gr_group;
static int _gr_stayopen;
static int grscan(), start_gr();

#define MAXGRP		200
static char *members[MAXGRP];
#define MAXLINELENGTH	1024
static char line[MAXLINELENGTH];

struct group *getgrgid (gid_t gid)
{
  int rval;
#ifdef USE_NET
  extern struct group *NET_getgrgid(gid_t);
  register struct user *p = &u;

    if (p->u_ixnetbase) {
	return (struct group *)NET_getgrgid(gid);
    }
#endif
    if (!start_gr())
	return(NULL);

    rval = grscan(1, gid, NULL);
    if (!_gr_stayopen)
	endgrent();

    return(rval ? &_gr_group : NULL);

}

struct group *getgrnam (const char *name)
{
  int rval;
#ifdef USE_NET
  extern struct group *NET_getgrnam(const char *);
  register struct user *p = &u;
    if (p->u_ixnetbase) {
	return (struct group *)NET_getgrnam(name);
      }
#endif
    if (!start_gr())
	return(NULL);

    rval = grscan(1, 0, name);
    if (!_gr_stayopen)
	endgrent();

    return(rval ? &_gr_group : NULL);
}

struct group *
getgrent(void) {
#ifdef USE_NET
  extern struct group *NET_getgrent(void);
  register struct user *p = &u;

    if (p->u_ixnetbase) {
	return (struct group *)NET_getgrent();
    }
#endif
    if ((!_gr_fp && !start_gr()) || !grscan(0, 0, NULL))
	return(NULL);

    return(&_gr_group);
}

static int
start_gr(void)
{
    if (_gr_fp) {
	syscall(SYS_rewind,_gr_fp);
	return(1);
    }
    return((_gr_fp = (FILE *)syscall(SYS_fopen,_PATH_GROUP, "r")) ? 1 : 0);
}

int
setgrent(void)
{
#ifdef USE_NET
  extern int NET_setgrent(void);
  register struct user *p = &u;

    if (p->u_ixnetbase) {
	return NET_setgrent();
    }
#endif
    return(setgroupent(0));
}

int
setgroupent(int stayopen)
{
#ifdef USE_NET
    extern int NET_setgroupent(int);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	return NET_setgroupent(stayopen);
      }
#endif
    if (!start_gr())
	return(0);

    _gr_stayopen = stayopen;
    return(1);
}

void
endgrent(void)
{
#ifdef USE_NET
    extern void NET_endgrent(void);
    register struct user *p = &u;

    if (p->u_ixnetbase) {
	NET_endgrent();
	return;
    }
#endif
    if (_gr_fp) {
	(void)syscall(SYS_fclose,_gr_fp);
	_gr_fp = NULL;
    }
}

static int
grscan(search, gid, name)
	register int search, gid;
	register char *name;
{
    register char *cp, **m;
    char *bp;
    char *fgets(), *strsep(), *index();

    for (;;) {
	if (!syscall(SYS_fgets,line, sizeof(line), _gr_fp))
	    return(0);

	bp = line;
	/* skip lines that are too big */
	if (!index(line, '\n')) {
	    int ch;

	    while ((ch = getc(_gr_fp)) != '\n' && ch != EOF)
		;
	    continue;
    }

	_gr_group.gr_name = strsep(&bp, ":\n");
	if (search && name && strcmp(_gr_group.gr_name, name))
	    continue;

	_gr_group.gr_passwd = strsep(&bp, ":\n");
	if (!(cp = strsep(&bp, ":\n")))
	    continue;

	_gr_group.gr_gid = atoi(cp);
	if (search && name == NULL && _gr_group.gr_gid != gid)
	    continue;

	for (m = _gr_group.gr_mem = members;; ++m) {
	    if (m == &members[MAXGRP - 1]) {
		*m = NULL;
		break;
	    }

	    if ((*m = strsep(&bp, ", \n")) == NULL)
		break;
	}
	return(1);
    }
    /* NOTREACHED */
}

#include <pwd.h>

struct passwd *
getpwent(void)
{
#ifdef USE_NET
    extern struct passwd *NET_getpwent(void);
    register struct user *p = &u;
    if (p->u_ixnetbase) {
	return NET_getpwent();
    }
    else
#endif
    { /* no TCP/IP stack */
	char *name = getenv("USER");
	if (name)
	    return (struct passwd *)syscall(SYS_getpwnam,name);
	else
	    return (struct passwd *)syscall(SYS_getpwnam,"root");
    }
}

struct passwd *getpwuid (uid_t uid)
{
  char *name;
  struct passwd *retval;
#ifdef USE_NET
  extern struct passwd *NET_getpwuid(uid_t);
  register struct user *p = &u;

    if (p->u_ixnetbase) {
	return (struct passwd *)NET_getpwuid(uid);
    }
#endif
  if ((name = (char *)syscall(SYS_getenv, "USER")))
    retval = (struct passwd *)syscall(SYS_getpwnam, name);
  else
    retval = (struct passwd *)syscall(SYS_getpwnam, "root");
  retval->pw_uid = uid;
  return retval;
}

struct passwd *getpwnam (const char *name)
{
#ifdef USE_NET
  extern struct passwd *NET_getpwnam(const char *);
  register struct user *p = &u;

    if (p->u_ixnetbase) {
	return (struct passwd *)NET_getpwnam(name);
    }
    else
#endif
    {
    /* this is not quite safe, since this library function could be called
     * in parallel with different names.. well, I don't consider this worth
     * doing `right', it's here to be able to link some programs ;-)
     */
    static struct passwd pw = {
	0,		/* pw_name */
        "*",		/* pw_passwd */
        0,		/* pw_uid */
        0,		/* pw_gid */
        0, 		/* pw_change */
        0,		/* pw_class */
	0,		/* pw_dir */
	0,		/* pw_gecos */
	"c:execute",    /* pw_shell */
	0		/* pw_expire */
    };
    pw.pw_name = (char *)name;


    if (!(pw.pw_dir = (char *)syscall(SYS_getenv, "HOME"))) {
      pw.pw_dir = "SYS:";
    }

    if (!(pw.pw_gecos = (char *)syscall(SYS_getenv, "REALNAME"))) {
      pw.pw_gecos = "amiga user";
    }
  return &pw;
    }
}


char hostname[64] = "localhost";

int gethostname (char *name, int namelen)
{
#ifdef USE_NET
  extern int NET_gethostname(char *, int);
  register struct user *p = &u;

    if (p->u_ixnetbase) {
	return NET_gethostname(name,namelen);
    }
#endif
  strncpy (name, hostname, namelen);
  return 0;
}

int sethostname (char *name, int namelen)
{
#ifdef USE_NET
  extern int NET_sethostname(char *, int);
  register struct user *p = &u;

    if (p->u_ixnetbase) {
	return NET_sethostname(name,namelen);
    }
    else
#endif
    {
      int len = namelen < sizeof (hostname) - 1 ? namelen : sizeof (hostname) - 1;

      strncpy (hostname, name, len);
      hostname[len] = 0;
    }
  return 0;
}
