From 9428a3639e3c47cc54ffe62eaca57f1f616b9aad Mon Sep 17 00:00:00 2001 From: Miles Bader Date: Thu, 20 Feb 1997 02:28:26 +0000 Subject: Initial checkin. --- libstore/task.c | 204 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 libstore/task.c (limited to 'libstore') diff --git a/libstore/task.c b/libstore/task.c new file mode 100644 index 00000000..b5289480 --- /dev/null +++ b/libstore/task.c @@ -0,0 +1,204 @@ +/* Mach task store backend + + Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc. + + Written by Miles Bader + + This task is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include + +#include + +#include "store.h" + +static process_t +proc_server () +{ + static process_t proc = MACH_PORT_NULL; + if (proc == MACH_PORT_NULL) + proc = getproc (); + return proc; +} + +static error_t +topen (const char *name, task_t *task) +{ + char *name_end; + pid_t pid = strtoul (name, &name_end, 0); + + if (*name == '\0' || *name_end != '\0') + return EINVAL; + + return proc_pid2task (proc_server (), pid, task); +} + +static void +tclose (struct store *store) +{ + mach_port_deallocate (mach_task_self (), store->port); + store->port = MACH_PORT_NULL; +} + +static error_t +task_read (struct store *store, + off_t addr, size_t index, size_t amount, void **buf, size_t *len) +{ + size_t bsize = store->block_size; + return vm_read (store->port, addr * bsize, amount, (vm_address_t *)buf, len); +} + +static error_t +task_write (struct store *store, + off_t addr, size_t index, void *buf, size_t len, size_t *amount) +{ + size_t bsize = store->block_size; + error_t err = vm_write (store->port, addr * bsize, (vm_address_t)buf, len); + if (! err) + *amount = len; + return err; +} + +static error_t +task_decode (struct store_enc *enc, const struct store_class *const *classes, + struct store **store) +{ + return store_std_leaf_decode (enc, _store_task_create, store); +} + +static error_t +task_open (const char *name, int flags, + const struct store_class *const *classes, + struct store **store) +{ + return store_task_open (name, flags, store); +} + +static error_t +task_set_flags (struct store *store, int flags) +{ + if ((flags & ~(STORE_INACTIVE | STORE_ENFORCED)) != 0) + /* Trying to set flags we don't support. */ + return EINVAL; + + if ((flags & STORE_ENFORCED) + && (store->num_runs > 0 + || store->runs[0].start != 0 + || store->runs[0].length != (VM_MAX_ADDRESS >> store->log2_block_size))) + /* Kernel only enforces the whole thing... */ + return EINVAL; + + if (flags & STORE_INACTIVE) + tclose (store); + + store->flags |= flags; /* When inactive, anything goes. */ + + return 0; +} + +static error_t +task_clear_flags (struct store *store, int flags) +{ + error_t err = 0; + if ((flags & ~(STORE_INACTIVE | STORE_ENFORCED)) != 0) + err = EINVAL; + if (!err && (flags & STORE_INACTIVE)) + err = store->name ? topen (store->name, &store->port) : ESRCH; + if (! err) + store->flags &= ~flags; + return err; +} + +struct store_class +store_task_class = +{ + STORAGE_TASK, "task", task_read, task_write, + store_std_leaf_allocate_encoding, store_std_leaf_encode, task_decode, + task_set_flags, task_clear_flags, 0, 0, 0, task_open +}; + +/* Return a new store in STORE referring to the mach task TASK. Consumes + the send right TASK. */ +error_t +store_task_create (task_t task, int flags, struct store **store) +{ + struct store_run run; + + run.start = 0; + run.length = VM_MAX_ADDRESS / vm_page_size; + + flags |= STORE_ENFORCED; /* 'cause it's the whole task. */ + + return _store_task_create (task, flags, vm_page_size, &run, 1, store); +} + +/* Like store_task_create, but doesn't query the task for information. */ +error_t +_store_task_create (task_t task, int flags, size_t block_size, + const struct store_run *runs, size_t num_runs, + struct store **store) +{ + error_t err = 0; + + if ((block_size & (block_size - 1)) == 0 && block_size >= vm_page_size) + { + *store = + _make_store (&store_task_class, + task, flags, block_size, runs, num_runs, 0); + if (! *store) + err = ENOMEM; + } + else + err = EINVAL; /* block size not a power of two */ + + if (! err) + { + pid_t pid; + + err = proc_task2pid (proc_server (), task, &pid); + if (! err) + { + char buf[20]; + snprintf (buf, sizeof buf, "%u", pid); + err = store_set_name (*store, buf); + } + + if (err) + store_free (*store); + } + + return err; +} + +/* Open the task NAME, and return the corresponding store in STORE. */ +error_t +store_task_open (const char *name, int flags, struct store **store) +{ + task_t task; + error_t err = topen (name, &task); + + if (! err) + { + err = store_task_create (task, flags, store); + if (err) + mach_port_deallocate (mach_task_self (), task); + } + + return err; +} -- cgit v1.2.3