コード例 #1
0
INT_32 procInitFs(VOID)
{
	struct proc_dir_entry *prEntry;

	if (init_net.proc_net == (struct proc_dir_entry *)NULL) {
		pr_err("init proc fs fail: proc_net == NULL\n");
		return -ENOENT;
	}

	/*
	 * Directory: Root (/proc/net/wlan0)
	 */

	gprProcRoot = proc_mkdir(PROC_ROOT_NAME, init_net.proc_net);
	if (!gprProcRoot) {
		pr_err("gprProcRoot == NULL\n");
		return -ENOENT;
	}
	proc_set_user(gprProcRoot, KUIDT_INIT(PROC_UID_SHELL), KGIDT_INIT(PROC_GID_WIFI));

	prEntry = proc_create(PROC_DBG_LEVEL_NAME, 0664, gprProcRoot, &dbglevel_ops);
	if (prEntry == NULL) {
		pr_err("Unable to create /proc entry dbgLevel\n\r");
		return -1;
	}
	proc_set_user(prEntry, KUIDT_INIT(PROC_UID_SHELL), KGIDT_INIT(PROC_GID_WIFI));
	return 0;
}				/* end of procInitProcfs() */
コード例 #2
0
ファイル: system_keyring.c プロジェクト: AlexShiLucky/linux
/*
 * Create the trusted keyrings
 */
static __init int system_trusted_keyring_init(void)
{
	pr_notice("Initialise system trusted keyrings\n");

	builtin_trusted_keys =
		keyring_alloc(".builtin_trusted_keys",
			      KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
			      ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
			      KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH),
			      KEY_ALLOC_NOT_IN_QUOTA,
			      NULL, NULL);
	if (IS_ERR(builtin_trusted_keys))
		panic("Can't allocate builtin trusted keyring\n");

#ifdef CONFIG_SECONDARY_TRUSTED_KEYRING
	secondary_trusted_keys =
		keyring_alloc(".secondary_trusted_keys",
			      KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
			      ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
			       KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH |
			       KEY_USR_WRITE),
			      KEY_ALLOC_NOT_IN_QUOTA,
			      get_builtin_and_secondary_restriction(),
			      NULL);
	if (IS_ERR(secondary_trusted_keys))
		panic("Can't allocate secondary trusted keyring\n");

	if (key_link(secondary_trusted_keys, builtin_trusted_keys) < 0)
		panic("Can't link trusted keyrings\n");
#endif

	return 0;
}
コード例 #3
0
ファイル: tests.c プロジェクト: eworm-de/bus1
static void bus1_test_user(void)
{
	struct bus1_user *user1, *user2;
	kuid_t uid1 = KUIDT_INIT(1), uid2 = KUIDT_INIT(2);

	/* drop the NULL user */
	bus1_user_unref(NULL);

	/* create a user */
	user1 = bus1_user_ref_by_uid(uid1);
	WARN_ON(!user1);
	WARN_ON(__kuid_val(user1->uid) != 1);
	WARN_ON(user1->id != 0);
	WARN_ON(atomic_read(&user1->n_slices) !=
					atomic_read(&user1->max_slices));
	WARN_ON(atomic_read(&user1->n_handles) !=
					atomic_read(&user1->max_handles));
	WARN_ON(atomic_read(&user1->n_inflight_bytes) !=
					atomic_read(&user1->max_bytes));
	WARN_ON(atomic_read(&user1->n_inflight_fds) !=
					atomic_read(&user1->max_fds));

	/* create a different user */
	user2 = bus1_user_ref_by_uid(uid2);
	WARN_ON(!user2);
	WARN_ON(user1 == user2);
	WARN_ON(__kuid_val(user2->uid) != 2);
	WARN_ON(user2->id != 1);
	WARN_ON(atomic_read(&user2->n_slices) !=
					atomic_read(&user2->max_slices));
	WARN_ON(atomic_read(&user2->n_handles) !=
					atomic_read(&user2->max_handles));
	WARN_ON(atomic_read(&user2->n_inflight_bytes) !=
					atomic_read(&user2->max_bytes));
	WARN_ON(atomic_read(&user2->n_inflight_fds) !=
					atomic_read(&user2->max_fds));

	/* drop the second user */
	user2 = bus1_user_unref(user2);
	WARN_ON(user2);

	/* take another ref on the first user */
	user2 = bus1_user_ref(user1);
	WARN_ON(user1 != user2);

	/* drop the ref again */
	user2 = bus1_user_unref(user2);
	WARN_ON(user2);

	/* look up the first user again by uid */
	user2 = bus1_user_ref_by_uid(uid1);
	WARN_ON(user1 != user2);

	WARN_ON(bus1_user_unref(user1));
	WARN_ON(bus1_user_unref(user2));
}
コード例 #4
0
static void bluesleep_proc_set_uid_gid(struct proc_dir_entry *ent)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
	proc_set_user(ent, KUIDT_INIT(AID_BLUETOOTH),
		      KGIDT_INIT(AID_NET_BT_STACK));
#else
	ent->uid = AID_BLUETOOTH;
	ent->gid = AID_NET_BT_STACK;
#endif
}
コード例 #5
0
ファイル: persistent.c プロジェクト: avagin/linux
/*
 * Create the persistent keyring register for the current user namespace.
 *
 * Called with the namespace's sem locked for writing.
 */
static int key_create_persistent_register(struct user_namespace *ns)
{
	struct key *reg = keyring_alloc(".persistent_register",
					KUIDT_INIT(0), KGIDT_INIT(0),
					current_cred(),
					((KEY_POS_ALL & ~KEY_POS_SETATTR) |
					 KEY_USR_VIEW | KEY_USR_READ),
					KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
	if (IS_ERR(reg))
		return PTR_ERR(reg);

	ns->persistent_keyring_register = reg;
	return 0;
}
コード例 #6
0
/*
 * Load the compiled-in keys
 */
static __init int system_trusted_keyring_init(void)
{
    pr_notice("Initialise system trusted keyring\n");

    system_trusted_keyring =
        keyring_alloc(".system_keyring",
                      KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
                      ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
                       KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH),
                      KEY_ALLOC_NOT_IN_QUOTA, NULL);
    if (IS_ERR(system_trusted_keyring))
        panic("Can't allocate system trusted keyring\n");

    set_bit(KEY_FLAG_TRUSTED_ONLY, &system_trusted_keyring->flags);
    return 0;
}
コード例 #7
0
ファイル: modsign_pubkey.c プロジェクト: AllenDou/linux
/*
 * Load the compiled-in keys
 */
static __init int module_verify_init(void)
{
	pr_notice("Initialise module verification\n");

	modsign_keyring = key_alloc(&key_type_keyring, ".module_sign",
				    KUIDT_INIT(0), KGIDT_INIT(0),
				    current_cred(),
				    (KEY_POS_ALL & ~KEY_POS_SETATTR) |
				    KEY_USR_VIEW | KEY_USR_READ,
				    KEY_ALLOC_NOT_IN_QUOTA);
	if (IS_ERR(modsign_keyring))
		panic("Can't allocate module signing keyring\n");

	if (key_instantiate_and_link(modsign_keyring, NULL, 0, NULL, NULL) < 0)
		panic("Can't instantiate module signing keyring\n");

	return 0;
}
コード例 #8
0
ファイル: digsig.c プロジェクト: AlexShiLucky/linux
static int __integrity_init_keyring(const unsigned int id, key_perm_t perm,
				    struct key_restriction *restriction)
{
	const struct cred *cred = current_cred();
	int err = 0;

	keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0),
				    KGIDT_INIT(0), cred, perm,
				    KEY_ALLOC_NOT_IN_QUOTA, restriction, NULL);
	if (IS_ERR(keyring[id])) {
		err = PTR_ERR(keyring[id]);
		pr_info("Can't allocate %s keyring (%d)\n",
			keyring_name[id], err);
		keyring[id] = NULL;
	}

	return err;
}
コード例 #9
0
ファイル: digsig.c プロジェクト: mikuhatsune001/linux2.6.32
int integrity_init_keyring(const unsigned int id)
{
	const struct cred *cred = current_cred();
	int err = 0;

	keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0),
				    KGIDT_INIT(0), cred,
				    ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
				     KEY_USR_VIEW | KEY_USR_READ |
				     KEY_USR_WRITE | KEY_USR_SEARCH),
				    KEY_ALLOC_NOT_IN_QUOTA, NULL);
	if (!IS_ERR(keyring[id]))
		set_bit(KEY_FLAG_TRUSTED_ONLY, &keyring[id]->flags);
	else {
		err = PTR_ERR(keyring[id]);
		pr_info("Can't allocate %s keyring (%d)\n",
			keyring_name[id], err);
		keyring[id] = NULL;
	}
	return err;
}
コード例 #10
0
ファイル: fib_rules.c プロジェクト: avagin/linux
 *
 * Authors:	Thomas Graf <*****@*****.**>
 */

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/module.h>
#include <net/net_namespace.h>
#include <net/sock.h>
#include <net/fib_rules.h>
#include <net/ip_tunnels.h>

static const struct fib_kuid_range fib_kuid_range_unset = {
	KUIDT_INIT(0),
	KUIDT_INIT(~0),
};

bool fib_rule_matchall(const struct fib_rule *rule)
{
	if (rule->iifindex || rule->oifindex || rule->mark || rule->tun_id ||
	    rule->flags)
		return false;
	if (rule->suppress_ifgroup != -1 || rule->suppress_prefixlen != -1)
		return false;
	if (!uid_eq(rule->uid_range.start, fib_kuid_range_unset.start) ||
	    !uid_eq(rule->uid_range.end, fib_kuid_range_unset.end))
		return false;
	if (fib_rule_port_range_set(&rule->sport_range))
		return false;
コード例 #11
0
kuid_t make_kuid(struct user_namespace *ns, uid_t uid)
{
	/* Map the uid to a global kernel uid */
	return KUIDT_INIT(uid);
}
コード例 #12
0
/* static unsigned long cl_shutdown_state[MAX_NUM_INSTANCE_MTK_COOLER_SHUTDOWN] = { 0 }; */
static struct sd_state cl_sd_state[MAX_NUM_INSTANCE_MTK_COOLER_SHUTDOWN];

#if defined(MTK_COOLER_SHUTDOWN_SIGNAL)

static unsigned int tm_pid;
static unsigned int tm_input_pid;
static unsigned int mtk_cl_sd_rst;
static struct task_struct g_task;
static struct task_struct *pg_task = &g_task;

static int sd_debouncet = 1;
/* static int sd_cnt = 0; */
static int sd_happened;
static kuid_t uid = KUIDT_INIT(0);
static kgid_t gid = KGIDT_INIT(1000);

static ssize_t _mtk_cl_sd_rst_write(struct file *filp, const char __user *buf, size_t len,
				    loff_t *data)
{
	int ret = 0;
	char tmp[MAX_LEN] = { 0 };

	/* write data to the buffer */
	if (copy_from_user(tmp, buf, len))
		return -EFAULT;

	ret = kstrtouint(tmp, 10, &mtk_cl_sd_rst);
	if (ret)
		WARN_ON(1);
コード例 #13
0
ファイル: tests.c プロジェクト: eworm-de/bus1
static void bus1_test_quota(void)
{
	struct bus1_peer_info peer = {};
	struct bus1_user *owner, *user1, *user2;
	int r;

	/* init and destroy */
	bus1_user_quota_destroy(NULL);

	bus1_user_quota_init(&peer.quota);
	WARN_ON(peer.quota.n_stats != 0);
	WARN_ON(peer.quota.stats != NULL);

	bus1_user_quota_destroy(&peer.quota);

	/* charge and discharge */

	user1 = bus1_user_ref_by_uid(KUIDT_INIT(1));
	WARN_ON(!user1);
	user2 = bus1_user_ref_by_uid(KUIDT_INIT(2));
	WARN_ON(!user2);
	owner = bus1_user_ref_by_uid(KUIDT_INIT(3));
	WARN_ON(!owner);

	bus1_user_quota_init(&peer.quota);
	WARN_ON(peer.quota.stats != NULL);
	WARN_ON(peer.quota.n_stats != 0);

	mutex_init(&peer.lock);
	peer.user = owner;
	mutex_lock(&peer.lock);
	bus1_pool_create_for_peer(&peer);

	/* charge nothing: allocates the user stats, charge one message */
	r = bus1_user_quota_charge(&peer, user1, 0, 0, 0);
	WARN_ON(r < 0);
	WARN_ON(atomic_read(&owner->n_slices) !=
				atomic_read(&owner->max_slices) - 1);
	WARN_ON(atomic_read(&owner->n_handles) !=
				atomic_read(&owner->max_handles));
	WARN_ON(atomic_read(&owner->n_inflight_bytes) !=
				atomic_read(&owner->max_bytes));
	WARN_ON(atomic_read(&owner->n_inflight_fds) !=
				atomic_read(&owner->max_fds));
	WARN_ON(peer.quota.n_stats < 1);
	WARN_ON(peer.quota.stats == NULL);
	WARN_ON(peer.quota.stats[0].n_slices != 1);
	WARN_ON(peer.quota.stats[0].n_handles != 0);
	WARN_ON(peer.quota.stats[0].n_bytes != 0);
	WARN_ON(peer.quota.stats[0].n_fds != 0);

	bus1_user_quota_discharge(&peer, user1, 0, 0, 0);
	WARN_ON(atomic_read(&owner->n_slices) !=
				atomic_read(&owner->max_slices));
	WARN_ON(atomic_read(&owner->n_handles) !=
				atomic_read(&owner->max_handles));
	WARN_ON(atomic_read(&owner->n_inflight_bytes) !=
				atomic_read(&owner->max_bytes));
	WARN_ON(atomic_read(&owner->n_inflight_fds) !=
				atomic_read(&owner->max_fds));
	WARN_ON(peer.quota.n_stats < 1);
	WARN_ON(peer.quota.stats == NULL);
	WARN_ON(peer.quota.stats[0].n_slices != 0);
	WARN_ON(peer.quota.stats[0].n_handles != 0);
	WARN_ON(peer.quota.stats[0].n_bytes != 0);
	WARN_ON(peer.quota.stats[0].n_fds != 0);

	/* exceed the quota: nothing happens */
	r = bus1_user_quota_charge(&peer, user1, -1, 0, 0);
	WARN_ON(r != -EDQUOT);
	WARN_ON(atomic_read(&owner->n_slices) !=
				atomic_read(&owner->max_slices));
	WARN_ON(atomic_read(&owner->n_handles) !=
				atomic_read(&owner->max_handles));
	WARN_ON(atomic_read(&owner->n_inflight_bytes) !=
				atomic_read(&owner->max_bytes));
	WARN_ON(atomic_read(&owner->n_inflight_fds) !=
				atomic_read(&owner->max_fds));
	WARN_ON(peer.quota.n_stats < 1);
	WARN_ON(peer.quota.stats == NULL);
	WARN_ON(peer.quota.stats[0].n_slices != 0);
	WARN_ON(peer.quota.stats[0].n_handles != 0);
	WARN_ON(peer.quota.stats[0].n_bytes != 0);
	WARN_ON(peer.quota.stats[0].n_fds != 0);

	r = bus1_user_quota_charge(&peer, user1, 0, -1, 0);
	WARN_ON(r != -EDQUOT);
	WARN_ON(atomic_read(&owner->n_slices) !=
				atomic_read(&owner->max_slices));
	WARN_ON(atomic_read(&owner->n_handles) !=
				atomic_read(&owner->max_handles));
	WARN_ON(atomic_read(&owner->n_inflight_fds) !=
				atomic_read(&owner->max_fds));
	WARN_ON(peer.quota.n_stats < 1);
	WARN_ON(peer.quota.stats == NULL);
	WARN_ON(peer.quota.stats[0].n_slices != 0);
	WARN_ON(peer.quota.stats[0].n_handles != 0);
	WARN_ON(peer.quota.stats[0].n_bytes != 0);
	WARN_ON(peer.quota.stats[0].n_fds != 0);

	r = bus1_user_quota_charge(&peer, user1, 0, 0, -1);
	WARN_ON(r != -EDQUOT);
	WARN_ON(atomic_read(&owner->n_slices) !=
				atomic_read(&owner->max_slices));
	WARN_ON(atomic_read(&owner->n_handles) !=
				atomic_read(&owner->max_handles));
	WARN_ON(atomic_read(&owner->n_inflight_fds) !=
				atomic_read(&owner->max_fds));
	WARN_ON(peer.quota.n_stats < 1);
	WARN_ON(peer.quota.stats == NULL);
	WARN_ON(peer.quota.stats[0].n_slices != 0);
	WARN_ON(peer.quota.stats[0].n_handles != 0);
	WARN_ON(peer.quota.stats[0].n_bytes != 0);
	WARN_ON(peer.quota.stats[0].n_fds != 0);

	/* verify the limits: size */
	r = bus1_user_quota_charge(&peer, user1,
				   atomic_read(&owner->max_bytes) / 4, 0, 0);
	WARN_ON(r < 0);
	WARN_ON(atomic_read(&owner->n_slices) !=
				atomic_read(&owner->max_slices) - 1);
	WARN_ON(atomic_read(&owner->n_handles) !=
				atomic_read(&owner->max_handles));
	WARN_ON(atomic_read(&owner->n_inflight_fds) !=
				atomic_read(&owner->max_fds));
	WARN_ON(peer.quota.n_stats < 1);
	WARN_ON(peer.quota.stats == NULL);
	WARN_ON(peer.quota.stats[0].n_slices != 1);
	WARN_ON(peer.quota.stats[0].n_handles != 0);
	WARN_ON(peer.quota.stats[0].n_bytes !=
					atomic_read(&owner->max_bytes) / 4);
	WARN_ON(peer.quota.stats[0].n_fds != 0);

	r = bus1_user_quota_charge(&peer, user1,
				   atomic_read(&owner->max_bytes) / 4 + 1,
				   0, 0);
	WARN_ON(r != -EDQUOT);

	r = bus1_user_quota_charge(&peer, user2,
				   atomic_read(&owner->max_bytes) / 4 + 1,
				   0, 0);
	WARN_ON(r < 0);
	WARN_ON(atomic_read(&owner->n_slices) !=
				atomic_read(&owner->max_slices) - 2);
	WARN_ON(atomic_read(&owner->n_handles) !=
				atomic_read(&owner->max_handles));
	WARN_ON(atomic_read(&owner->n_inflight_fds) !=
				atomic_read(&owner->max_fds));
	WARN_ON(peer.quota.n_stats < 2);
	WARN_ON(peer.quota.stats == NULL);
	WARN_ON(peer.quota.stats[1].n_slices != 1);
	WARN_ON(peer.quota.stats[1].n_handles != 0);
	WARN_ON(peer.quota.stats[1].n_bytes !=
					atomic_read(&owner->max_bytes) / 4 + 1);
	WARN_ON(peer.quota.stats[1].n_fds != 0);

	r = bus1_user_quota_charge(&peer, user1,
				   atomic_read(&owner->max_bytes) / 4, 0, 0);
	WARN_ON(r != -EDQUOT);

	bus1_user_quota_discharge(&peer, user2,
				  atomic_read(&owner->max_bytes) / 4 + 1,
				  0, 0);
	WARN_ON(atomic_read(&owner->n_slices) !=
				atomic_read(&owner->max_slices) - 1);
	WARN_ON(atomic_read(&owner->n_handles) !=
				atomic_read(&owner->max_handles));
	WARN_ON(atomic_read(&owner->n_inflight_fds) !=
				atomic_read(&owner->max_fds));
	WARN_ON(peer.quota.n_stats < 2);
	WARN_ON(peer.quota.stats == NULL);
	WARN_ON(peer.quota.stats[1].n_slices != 0);
	WARN_ON(peer.quota.stats[1].n_handles != 0);
	WARN_ON(peer.quota.stats[1].n_bytes != 0);
	WARN_ON(peer.quota.stats[1].n_fds != 0);

	r = bus1_user_quota_charge(&peer, user1,
				   atomic_read(&owner->max_bytes) / 4, 0, 0);
	WARN_ON(r < 0);
	WARN_ON(atomic_read(&owner->n_slices) !=
				atomic_read(&owner->max_slices) - 2);
	WARN_ON(atomic_read(&owner->n_handles) !=
				atomic_read(&owner->max_handles));
	WARN_ON(atomic_read(&owner->n_inflight_fds) !=
				atomic_read(&owner->max_fds));
	WARN_ON(peer.quota.n_stats < 1);
	WARN_ON(peer.quota.stats == NULL);
	WARN_ON(peer.quota.stats[0].n_slices != 2);
	WARN_ON(peer.quota.stats[0].n_handles != 0);
	WARN_ON(peer.quota.stats[0].n_bytes !=
					atomic_read(&owner->max_bytes) / 2);
	WARN_ON(peer.quota.stats[0].n_fds != 0);

	r = bus1_user_quota_charge(&peer, user1,
				   atomic_read(&owner->max_bytes) / 4, 0, 0);
	WARN_ON(r != -EDQUOT);

	r = bus1_user_quota_charge(&peer, user2,
				   atomic_read(&owner->max_bytes) / 4 + 1,
				   0, 0);
	WARN_ON(r != -EDQUOT);

	r = bus1_user_quota_charge(&peer, user2,
				   atomic_read(&owner->max_bytes) / 4, 0, 0);
	WARN_ON(r < 0);
	WARN_ON(atomic_read(&owner->n_slices) !=
				atomic_read(&owner->max_slices) - 3);
	WARN_ON(atomic_read(&owner->n_handles) !=
				atomic_read(&owner->max_handles));
	WARN_ON(atomic_read(&owner->n_inflight_fds) !=
				atomic_read(&owner->max_fds));
	WARN_ON(peer.quota.n_stats < 2);
	WARN_ON(peer.quota.stats == NULL);
	WARN_ON(peer.quota.stats[1].n_slices != 1);
	WARN_ON(peer.quota.stats[1].n_handles != 0);
	WARN_ON(peer.quota.stats[1].n_bytes !=
					atomic_read(&owner->max_bytes) / 4);
	WARN_ON(peer.quota.stats[1].n_fds != 0);

	bus1_user_quota_discharge(&peer, user1,
				  atomic_read(&owner->max_bytes) / 4, 0, 0);
	bus1_user_quota_discharge(&peer, user1,
				  atomic_read(&owner->max_bytes) / 4, 0, 0);
	bus1_user_quota_discharge(&peer, user2,
				  atomic_read(&owner->max_bytes) / 4, 0, 0);
	WARN_ON(atomic_read(&owner->n_slices) !=
				atomic_read(&owner->max_slices));
	WARN_ON(atomic_read(&owner->n_handles) !=
				atomic_read(&owner->max_handles));
	WARN_ON(atomic_read(&owner->n_inflight_fds) !=
				atomic_read(&owner->max_fds));
	WARN_ON(peer.quota.n_stats < 2);
	WARN_ON(peer.quota.stats == NULL);
	WARN_ON(peer.quota.stats[0].n_slices != 0);
	WARN_ON(peer.quota.stats[0].n_handles != 0);
	WARN_ON(peer.quota.stats[0].n_bytes != 0);
	WARN_ON(peer.quota.stats[0].n_fds != 0);
	WARN_ON(peer.quota.stats[1].n_slices != 0);
	WARN_ON(peer.quota.stats[1].n_handles != 0);
	WARN_ON(peer.quota.stats[1].n_bytes != 0);
	WARN_ON(peer.quota.stats[1].n_fds != 0);

	bus1_pool_destroy(&peer.pool);
	mutex_unlock(&peer.lock);
	bus1_user_quota_destroy(&peer.quota);
	WARN_ON(bus1_user_unref(user1));
	WARN_ON(bus1_user_unref(user2));
	WARN_ON(bus1_user_unref(owner));
}
コード例 #14
0
static int _stp_create_procfs(const char *path, int num,
			      const struct file_operations *fops, int perm,
			      void *data) 
{  
	const char *p; char *next;
	struct proc_dir_entry *last_dir, *de;

	if (num >= STP_MAX_PROCFS_FILES) {
		_stp_error("Requested file number %d is larger than max (%d)\n", 
			   num, STP_MAX_PROCFS_FILES);
		return -1;
	}

	last_dir = _stp_proc_root;

	/* if no path, use default one */
	if (strlen(path) == 0)
		p = "command";
	else
		p = path;
	
#ifdef _STP_ALLOW_PROCFS_PATH_SUBDIRS
	while ((next = strchr(p, '/'))) {
		if (_stp_num_pde == STP_MAX_PROCFS_FILES)
			goto too_many;
		*next = 0;
		de = _stp_procfs_lookup(p, last_dir);
		if (de == NULL) {
			last_dir = proc_mkdir(p, last_dir);
			if (!last_dir) {
				_stp_error("Could not create directory \"%s\"\n", p);
				goto err;
			}
			_stp_pde[_stp_num_pde++] = last_dir;
#ifdef STAPCONF_PROCFS_OWNER
			last_dir->owner = THIS_MODULE;
#endif
			proc_set_user(last_dir, KUIDT_INIT(_stp_uid),
				      KGIDT_INIT(_stp_gid));
		}
		else {
			last_dir = de;
		}
		p = next + 1;
	}
#else  /* !_STP_ALLOW_PROCFS_PATH_SUBDIRS */
	if (strchr(p, '/') != NULL) {
		_stp_error("Could not create path \"%s\","
			   " contains subdirectories\n", p);
		goto err;
	}
#endif	/* !_STP_ALLOW_PROCFS_PATH_SUBDIRS */
	
	if (_stp_num_pde == STP_MAX_PROCFS_FILES)
		goto too_many;
	
	de = proc_create_data(p, perm, last_dir, fops, data);
	if (de == NULL) {
		_stp_error("Could not create file \"%s\" in path \"%s\"\n",
			   p, path);
		goto err;
	}
#ifdef STAPCONF_PROCFS_OWNER
	de->owner = THIS_MODULE;
#endif
	proc_set_user(de, KUIDT_INIT(_stp_uid), KGIDT_INIT(_stp_gid));
	_stp_pde[_stp_num_pde++] = de;
	return 0;
	
too_many:
	_stp_error("Attempted to open too many procfs files. Maximum is %d\n",
		   STP_MAX_PROCFS_FILES);
err:
	_stp_close_procfs();
	return -1;
}