/*
 *  linux/ibcs/sysfs.c
 *
 *  Copyright (C) 1994  Mike Jagdis (jaggy@purplet.demon.co.uk)
 *
 * $Id: sysfs.c,v 1.2 1994/03/28 15:17:38 mike Exp $
 * $Source: /var/CVS/ibcs/sysfs.c,v $
 */


#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/segment.h>
#include <linux/ptrace.h>
#include <linux/config.h>
#include <linux/fcntl.h>

#include <asm/segment.h>
#include <asm/system.h>
#include <linux/fs.h>
#include <linux/sys.h>

#include <ibcs/ibcs.h>

#ifdef IBCS_TRACE
#include <ibcs/trace.h>
#endif


/* Declared in linux/fs/filesystems.c.
 * We rely on the table of filesystems being statically allocate as an
 * array at compile time. When (and if) we go to a modular system we will
 * have to change this code appropriately.
 */
extern struct file_system_type file_systems[];


#define GETFSIND	1
#define GETFSTYP	2
#define GETNFSTYP	3


int ibcs_sysfs(struct pt_regs * regs) {
	int	cmd;
	struct file_system_type *fs;
	int error;
	int n_fs;

	cmd = get_fs_long(((unsigned long *) regs->esp) + 1);

	if (cmd == GETFSIND) {
		char *fsname, *kfsname;

		fsname = (char *)get_fs_long(((unsigned long *) regs->esp) + 2);
		error = getname(fsname, &kfsname);
		if (error)
			return (error);
		n_fs = 1;
		for (fs=file_systems; fs->name; fs++,n_fs++)
			if (!strcmp(fs->name, kfsname)) {
				putname(kfsname);
				return (n_fs);
			}
		putname(kfsname);
		return (-EINVAL);
	}

	n_fs = 0;
	for (fs=file_systems; fs->name; fs++,n_fs++);

	if (cmd == GETNFSTYP) {
		return (n_fs);
	}

	if (cmd == GETFSTYP) {
		int fs_ind;
		char *buf;
		char *p;

		fs_ind = get_fs_long(((unsigned long *) regs->esp) + 2) - 1;
		if (fs_ind < 0 || fs_ind >= n_fs
		|| !file_systems[fs_ind].name)
			return (-EINVAL);

		buf = (char *)get_fs_long(((unsigned long *) regs->esp) + 3);

		error = verify_area(VERIFY_WRITE, buf,
				strlen(file_systems[fs_ind].name));
		if (error)
			return error;

		p = file_systems[fs_ind].name;
		do {
			put_fs_byte(*p, buf++);
		} while (*p++);

		return (0);
	}

#ifdef IBCS_TRACE
	if ((ibcs_trace & TRACE_API) || ibcs_func_p->trace) {
		printk(KERN_DEBUG "iBCS2 unsupported sysfs call %d\n", cmd);
	}
#endif

	return -EINVAL;
}
