/*
 *  linux/ibcs/utsname.c
 *
 *  Copyright (C) 1994 Mike Jagdis (jaggy@purplet.demon.co.uk)
 *
 *  The SVR4 utsname support is based on the code originally in svr4.c
 *  which was:
 *
 *  Copyright (C) 1994 Eric Youngdale.
 */

#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/personality.h>
#include <linux/utsname.h>
#include <asm/segment.h>

#include <ibcs/ibcs.h>


struct sco_utsname {
	char sysname[9];
	char nodename[9];
	char release[16];
	char kernelid[20];
	char machine[9];
	char bustype[9];
	char sysserial[10];
	unsigned short sysorigin;
	unsigned short sysoem;
	char numusers[9];
	unsigned short numcpu;
};

struct v7_utsname {
	char sysname[9];
	char nodename[9];
	char release[9];
	char version[9];
	char machine[9];
};

#define SVR4_NMLN 257
struct svr4_utsname {
	char sysname[SVR4_NMLN];
	char nodename[SVR4_NMLN];
	char release[SVR4_NMLN];
	char version[SVR4_NMLN];
	char machine[SVR4_NMLN];
};


#define set_utsfield(to, from) \
	{ \
		int len = (sizeof(to) > sizeof(from) ? sizeof(from) : sizeof(to)); \
		memcpy_tofs(to, from, len); \
		put_fs_byte('\0', to+len-1); \
	}


int
sco_utsname(unsigned long addr)
{
	int error;
	struct sco_utsname *it = (struct sco_utsname *)addr;

	/* This shouldn't be invoked by anything that isn't running
	 * in the SCO personality. I can envisage a program that uses
	 * this to test if it is running on SCO or not. It probably
	 * won't happen but let's make sure it doesn't anyway...
	 */
	if (current->personality != (PER_SCOSVR3))
		return -ENOSYS;

	error = verify_area(VERIFY_WRITE, it, sizeof (struct sco_utsname));
	if (error)
		return error;

	set_utsfield(it->sysname, system_utsname.nodename);
	set_utsfield(it->nodename, system_utsname.nodename);
	set_utsfield(it->release, system_utsname.release);
	set_utsfield(it->kernelid, system_utsname.version);
	set_utsfield(it->machine, system_utsname.machine);
	if (EISA_bus) {
		set_utsfield(it->bustype, "EISA");
	} else {
		set_utsfield(it->bustype, "ISA");
	}
	set_utsfield(it->sysserial, "public");
	put_fs_word(0xffff, &it->sysorigin);
	put_fs_word(0xffff, &it->sysoem);
	set_utsfield(it->numusers, "unlim");
	put_fs_word(1, &it->numcpu);

	return 0;
}


int
v7_utsname(unsigned long addr)
{
	int error;
	struct v7_utsname *it = (struct v7_utsname *)addr;

	error = verify_area(VERIFY_WRITE, it, sizeof (struct v7_utsname));
	if (error)
		return error;

	set_utsfield(it->sysname, system_utsname.nodename);
	set_utsfield(it->nodename, system_utsname.nodename);
	set_utsfield(it->release, system_utsname.release);
	set_utsfield(it->version, system_utsname.version);
	set_utsfield(it->machine, system_utsname.machine);

	return 0;
}


int
abi_utsname(unsigned long addr)
{
	int error;
	struct svr4_utsname *it = (struct svr4_utsname *)addr;

	error = verify_area(VERIFY_WRITE, it, sizeof (struct svr4_utsname));
	if (error)
		return error;

	set_utsfield(it->sysname, system_utsname.sysname);
	set_utsfield(it->nodename, system_utsname.nodename);
	set_utsfield(it->release, system_utsname.release);
	set_utsfield(it->version, system_utsname.version);
	set_utsfield(it->machine, system_utsname.machine);

	return 0;
}
