diff options
author | Miles Bader <miles@gnu.org> | 1995-03-31 20:31:10 +0000 |
---|---|---|
committer | Miles Bader <miles@gnu.org> | 1995-03-31 20:31:10 +0000 |
commit | 8f2d613931c56e11652968db19b8d2fff3062f70 (patch) | |
tree | f16eb2b36fc7fd2a73cf0066aeb3eae6b5cfd04d | |
parent | 0f40a399103893c73274af1b7a5e8ddafc71d963 (diff) |
Initial revision
-rw-r--r-- | libihash/ihash.c | 292 | ||||
-rw-r--r-- | libihash/ihash.h | 94 | ||||
-rw-r--r-- | libihash/primes.c | 135 | ||||
-rw-r--r-- | libshouldbeinlibc/=argz.c | 74 | ||||
-rw-r--r-- | libshouldbeinlibc/=argz.h | 33 | ||||
-rw-r--r-- | utils/settrans.c | 180 |
6 files changed, 808 insertions, 0 deletions
diff --git a/libihash/ihash.c b/libihash/ihash.c new file mode 100644 index 00000000..92f29ecb --- /dev/null +++ b/libihash/ihash.c @@ -0,0 +1,292 @@ +/* Integer-keyed hash table functions. + + Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + Written by Michael I. Bushnell; revised by Miles Bader <miles@gnu>. + + 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 the GNU Hurd; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <string.h> +#include <stdlib.h> + +#include "ihash.h" + +/* ---------------------------------------------------------------- */ + +/* When an entry in a hashtable's TAB array is HASH_EMPTY, that location is + available, and none of the other arrays are valid at that index. */ +#define HASH_EMPTY 0 + +/* When an entry in a hashtable's TAB array is HASH_DEL, that location is + available, and none of the other arrays are valid at that index. The + difference from HASH_EMPTY is that searches continue though HASH_DEL and + stop at HASH_EMPTY. */ +#define HASH_DEL ((void *) -1) + +/* Returns an initial index in HT for the key ID, for search for an entry. */ +#define HASH(ht, id) ((id) % (ht)->size) +/* Returns subsequent indices in HT for the key ID, given the previous one. */ +#define REHASH(ht, id, h) (((id) + (h)) % (ht)->size) + +/* ---------------------------------------------------------------- */ + +static inline int +index_empty(ihash_t ht, int index) +{ + return ht->tab[index] == HASH_EMPTY || ht->tab[index] == HASH_DEL; +} + +static inline int +index_valid(ihash_t ht, int index, int id) +{ + return !index_empty(ht, index) && ht->ids[index] == id; +} + +/* Given a hash table HT, and a key ID, finds the index in the table of that + key. You must subsequently check to see whether the given index is valid + (with index_valid() or index_empty()). */ +static inline int +find_index(ihash_t ht, int id) +{ + int h, firsth = -1; + + for (h = HASH(ht, id); + ht->tab[h] != HASH_EMPTY && ht->ids[h] != id && h != firsth; + h = REHASH(ht, id, h)) + if (firsth == -1) + firsth = h; + + return h; +} + +/* ---------------------------------------------------------------- */ + +/* Create an integer hash table and return it in HT. If a memory allocation + error occurs, ENOMEM is returned, otherwise 0. */ +error_t +ihash_create(ihash_t *ht) +{ + *ht = malloc(sizeof(struct ihash)); + if (*ht == NULL) + return ENOMEM; + (*ht)->size = 0; + return 0; +} + +/* Free HT and all resources it consumes. */ +void +ihash_free(ihash_t ht) +{ + void (*cleanup)(void *value, void *arg) = ht->cleanup; + + if (cleanup) + { + int i; + void *arg = ht->cleanup_arg; + for (i = 0; i < ht->size; i++) + if (!index_empty(ht, i)) + (*cleanup)(ht->tab[i], arg); + } + + if (ht->size > 0) + { + free(ht->tab); + free(ht->ids); + free(ht->locps); + } + + free(ht); +} + +/* Sets HT's element cleanup function to CLEANUP, and its second argument to + ARG. CLEANUP will be called on the value of any element to be + subsequently overwritten or deleted, with ARG as the second argument. */ +void +ihash_set_cleanup(ihash_t ht, + void (*cleanup)(void *value, void *arg), + void *arg) +{ + ht->cleanup = cleanup; + ht->cleanup_arg = arg; +} + +/* ---------------------------------------------------------------- */ + +/* Add ITEM to the hash table HT under the key ID. LOCP is the address of a + pointer located in ITEM; If non-NULL, LOCP should point to a variable of + type void **, and will be filled with a pointer that may be used as an + argument to ihash_locp_remove(). The variable pointed to by LOCP may be + written to subsequently between this called and when the element is + deleted, so you can't stash its value elsewhere and hope to use the + stashed value with ihash_locp_remove(). If a memory allocation error + occurs, ENOMEM is returned, otherwise 0. */ +error_t +ihash_add(ihash_t ht, int id, void *item, void ***locp) +{ + if (ht->size) + { + int h, firsth = -1; + + /* Search for for an empty or deleted space. */ + for (h = HASH(ht, id); + ht->tab[h] != HASH_EMPTY && ht->tab[h] != HASH_DEL && h != firsth; + h = REHASH(ht, id, h)) + if (firsth == -1) + firsth = h; + + if (index_empty(ht, h) || ht->ids[h] == id) + { + if (!index_empty(ht, h) && ht->cleanup) + ht->cleanup(ht->tab[h], ht->cleanup_arg); + + ht->tab[h] = item; + ht->ids[h] = id; + ht->locps[h] = locp; + + if (locp) + *locp = &ht->tab[h]; + + return 0; + } + } + + { + int i; + void **entry; + int old_size = ht->size; + void **old_tab = ht->tab; + void ****old_locps = ht->locps; + int *old_ids = ht->ids; + + ht->size = nextprime (2 * old_size); + ht->tab = malloc(ht->size * sizeof (void *)); + ht->locps = malloc (ht->size * sizeof (void ***)); + ht->ids = malloc (ht->size * sizeof (int)); + + if (ht->tab == NULL || ht->locps == NULL || ht->ids == NULL) + /* Memory allocation error; back out our changes and fail... */ + { + if (ht->tab) free(ht->tab); + if (ht->locps) free(ht->locps); + if (ht->ids) free(ht->ids); + + ht->size = old_size; + ht->tab = old_tab; + ht->locps = old_locps; + ht->ids = old_ids; + + return ENOMEM; + } + + for (i = ht->size, entry = ht->tab; i > 0; i--, entry++) + *entry = HASH_EMPTY; + + /* We have to rehash this again? */ + if (old_size > 0) + for (i = 0; i < old_size; i++) + if (old_tab[i] != HASH_EMPTY && old_tab[i] != HASH_DEL) + ihash_add(ht, old_ids[i], old_tab[i], old_locps[i]); + + /* Finally add the new element! */ + ihash_add(ht, id, item, locp); + + if (old_size > 0) + { + free(old_tab); + free(old_locps); + free(old_ids); + } + + return 0; + } +} + +/* Find and return the item in hash table HT with key ID, or NULL if it + doesn't exist. */ +void * +ihash_find (ihash_t ht, int id) +{ + if (ht->size == 0) + return 0; + else + { + int index = find_index(ht, id); + return index_valid(ht, index, id) ? ht->tab[index] : 0; + } +} + +/* ---------------------------------------------------------------- */ + +/* Call function FUN of one arg for each element of HT. FUN's only arg is a + pointer to the value stored in the hash table. If FUN ever returns + non-zero, then iteration stops and ihash_iterate returns that value, + otherwise it (eventually) returns 0. */ +error_t +ihash_iterate(ihash_t ht, error_t (*fun)(void *)) +{ + int i; + for (i = 0; i < ht->size; i++) + if (!index_empty(ht, i)) + { + error_t err = fun(ht->tab[i]); + if (err) + return err; + } + return 0; +} + +/* Remove the entry at LOCP from the hashtable HT. LOCP is as returned from + an earlier call to ihash_add(). This call should be faster than + ihash_remove(). HT can be NULL, in which case the call still succeeds, + but no cleanup can be done. */ +void +ihash_locp_remove(ihash_t ht, void **locp) +{ + void *tag = HASH_DEL; + + if (ht != NULL) + { + int index = locp - ht->tab; + int next_index = REHASH(ht, ht->ids[index], index); + + if (ht && ht->cleanup) + ht->cleanup(*locp, ht->cleanup_arg); + + /* If the next position in this hash chain is empty, then we don't need + to use HASH_DEL (which only serves to prevent breaking the chain to + preserve lookups past this point). */ + if (ht->tab[next_index] == HASH_EMPTY) + tag = HASH_EMPTY; + } + + *locp = tag; +} + +/* Remove the entry with a key of ID from HT. If anything was actually + removed, 1 is returned, otherwise (if there was no such element), 0. */ +int +ihash_remove(ihash_t ht, int id) +{ + int index = find_index(ht, id); + if (index_valid(ht, index, id)) + { + ihash_locp_remove(ht, &ht->tab[index]); + return 1; + } + else + return 0; +} diff --git a/libihash/ihash.h b/libihash/ihash.h new file mode 100644 index 00000000..ae8f0f38 --- /dev/null +++ b/libihash/ihash.h @@ -0,0 +1,94 @@ +/* Integer-keyed hash table functions. + + Copyright (C) 1995 Free Software Foundation, Inc. + + Written by Miles Bader <miles@gnu.ai.mit.edu> + + This program 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. + + This program 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. */ + +#ifndef __IHASH_H__ +#define __IHASH_H__ + +/* ---------------------------------------------------------------- */ + +typedef struct ihash *ihash_t; + +struct ihash +{ + /* An array storing the elements in the hash table (each a void *). */ + void **tab; + + /* An array storing the integer key for each element. */ + int *ids; + + /* An array storing pointers to the `location pointers' for each element. + These are used as cookies for quick 'n' easy removal. */ + void ****locps; /* four, count them, four stars */ + + /* The length of all these arrays. */ + int size; + + /* When freeing or overwriting an element, this function, if non-NULL, is + called with the value as the first argument, and CLEANUP_ARG as the + second argument. */ + void (*cleanup)(void *element, void *arg); + void *cleanup_arg; +}; + +/* Create an integer hash table and return it in HT. If a memory allocation + error occurs, ENOMEM is returned, otherwise 0. */ +error_t ihash_create(ihash_t *ht); + +/* Free HT and all resources it consumes. */ +void ihash_free(ihash_t ht); + +/* Sets HT's element cleanup function to CLEANUP, and its second argument to + ARG. CLEANUP will be called on the value of any element to be + subsequently overwritten or deleted, with ARG as the second argument. */ +void ihash_set_cleanup(ihash_t ht, + void (*cleanup)(void *value, void *arg), + void *arg); + +/* Add ITEM to the hash table HT under the key ID. LOCP is the address of a + pointer located in ITEM; If non-NULL, LOCP should point to a variable of + type void **, and will be filled with a pointer that may be used as an + argument to ihash_locp_remove() [the variable pointed to by LOCP may be + written to subsequently between this call and when the element is + deleted, so you can't stash its value elsewhere and hope to use the + stashed value with ihash_locp_remove()]. If a memory allocation error + occurs, ENOMEM is returned, otherwise 0. */ +error_t ihash_add(ihash_t ht, int id, void *item, void ***locp); + +/* Find and return the item in hash table HT with key ID, or NULL if it + doesn't exist. */ +void *ihash_find(ihash_t ht, int id); + +/* Call function FUN of one arg for each element of HT. FUN's only arg is a + pointer to the value stored in the hash table. If FUN ever returns + non-zero, then iteration stops and ihash_iterate returns that value, + otherwise it (eventually) returns 0. */ +error_t ihash_iterate(ihash_t ht, error_t (*fun)(void *)); + +/* Remove the entry with a key of ID from HT. If anything was actually + removed, 1 is returned, otherwise (if there was no such element), 0. */ +int ihash_remove(ihash_t ht, int id); + +/* Remove the entry at LOCP from the hashtable HT. LOCP is as returned from + an earlier call to ihash_add(). This call should be faster than + ihash_remove(). HT can be NULL, in which case the call still succeeds, + but no cleanup can be done. */ +void ihash_locp_remove(ihash_t ht, void **ht_locp); + +#endif /* __IHASH_H__ */ diff --git a/libihash/primes.c b/libihash/primes.c new file mode 100644 index 00000000..d0fc4d0c --- /dev/null +++ b/libihash/primes.c @@ -0,0 +1,135 @@ +/* Prime number generation + Copyright (C) 1994 Free Software Foundation + + This program 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. + + This program 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 <stdlib.h> +#include <limits.h> +#include <string.h> +#include <assert.h> + +#define BITS_PER_UNSIGNED (8 * sizeof (unsigned)) +#define SQRT_INT_MAX (1 << (BITS_PER_UNSIGNED / 2)) + +/* Return the next prime greater than or equal to N. */ +int +nextprime (unsigned n) +{ + /* Among other things, We guarantee that, for all i (0 <= i < primes_len), + primes[i] is a prime, + next_multiple[i] is a multiple of primes[i], + next_multiple[i] > primes[primes_len - 1], + next_multiple[i] is not a multiple of two unless primes[i] == 2, and + next_multiple[i] is the smallest such value. */ + static unsigned *primes, *next_multiple; + static int primes_len; + static int primes_size; + static unsigned next_sieve; /* always even */ + unsigned max_prime; + + if (! primes) + { + primes_size = 128; + primes = (unsigned *) malloc (primes_size * sizeof (*primes)); + next_multiple = (unsigned *) malloc (primes_size + * sizeof (*next_multiple)); + + primes[0] = 2; next_multiple[0] = 6; + primes[1] = 3; next_multiple[1] = 9; + primes[2] = 5; next_multiple[2] = 15; + primes_len = 3; + + next_sieve = primes[primes_len - 1] + 1; + } + + if (n <= primes[0]) + return primes[0]; + + while (n > (max_prime = primes[primes_len - 1])) + { + /* primes doesn't contain any prime large enough. Sieve from + max_prime + 1 to 2 * max_prime, looking for more primes. */ + unsigned start = next_sieve; + unsigned end = start + max_prime + 1; + char *sieve = (char *) alloca ((end - start) * sizeof (*sieve)); + int i; + + assert (sieve); + + bzero (sieve, (end - start) * sizeof (*sieve)); + + /* Make the sieve indexed by prime number, rather than + distance-from-start-to-the-prime-number. When we're done, + sieve[P] will be zero iff P is prime. + + ANSI C doesn't define what this means. Fuck them. */ + sieve -= start; + + /* Set sieve[i] for all composites i, start <= i < end. + Ignore multiples of 2. */ + for (i = 1; i < primes_len; i++) + { + unsigned twice_prime = 2 * primes[i]; + unsigned multiple; + + for (multiple = next_multiple[i]; + multiple < end; + multiple += twice_prime) + sieve[multiple] = 1; + next_multiple[i] = multiple; + } + + for (i = start + 1; i < end; i += 2) + if (! sieve[i]) + { + if (primes_len >= primes_size) + { + primes_size *= 2; + primes = (int *) realloc (primes, + primes_size * sizeof (*primes)); + next_multiple + = (int *) realloc (next_multiple, + primes_size * sizeof (*next_multiple)); + } + primes[primes_len] = i; + if (i >= SQRT_INT_MAX) + next_multiple[primes_len] = INT_MAX; + else + next_multiple[primes_len] = i * i; + primes_len++; + } + + next_sieve = end; + } + + /* Now we have at least one prime >= n. Find the smallest such. */ + { + int bottom = 0; + int top = primes_len; + + while (bottom < top) + { + int mid = (bottom + top) / 2; + + if (primes[mid] < n) + bottom = mid + 1; + else + top = mid; + } + + return primes[top]; + } +} + diff --git a/libshouldbeinlibc/=argz.c b/libshouldbeinlibc/=argz.c new file mode 100644 index 00000000..68fd6f5f --- /dev/null +++ b/libshouldbeinlibc/=argz.c @@ -0,0 +1,74 @@ +/* Routines for dealing with '\0' separated arg vectors. + + Copyright (C) 1995 Free Software Foundation, Inc. + + Written by Miles Bader <miles@gnu.ai.mit.edu> + + This program 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. + + This program 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 <stdlib.h> +#include <string.h> +#include <errno.h> + +/* ---------------------------------------------------------------- */ + +/* Make a '\0' separated arg vector from a unix argv vector, returning it in + ARGZ, and the total length in LEN. If a memory allocation error occurs, + ENOMEM is returned, otherwise 0. */ +error_t +argz_create(char **argv, char **argz, int *len) +{ + int tlen = 0; + char **argp; + + for (argp = argv; *argp != NULL; argp++) + tlen += strlen(*argp) + 1; + + *len = tlen; + + if (tlen == 0) + *argz = NULL; + else + { + *argz = malloc(tlen); + if (*argz == NULL) + return ENOMEM; + + while (tlen > 0) + { + tlen -= strlen(*--argp) + 1; + strcpy(*argz + tlen, *argp); + } + } + + return 0; +} + +/* ---------------------------------------------------------------- */ + +/* Make '\0' separated arg vector ARGZ printable by converting all the '\0's + except the last into spaces. */ +void +argz_stringify(char *argz, int len) +{ + while (len > 0) + { + int part_len = strlen(argz); + argz += part_len; + len -= part_len + 1; + if (len > 0) + *argz++ = ' '; + } +} diff --git a/libshouldbeinlibc/=argz.h b/libshouldbeinlibc/=argz.h new file mode 100644 index 00000000..f518bb1e --- /dev/null +++ b/libshouldbeinlibc/=argz.h @@ -0,0 +1,33 @@ +/* Routines for dealing with '\0' separated arg vectors. + + Copyright (C) 1995 Free Software Foundation, Inc. + + Written by Miles Bader <miles@gnu.ai.mit.edu> + + This program 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. + + This program 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. */ + +#ifndef __ARGZ_H__ +#define __ARGZ_H__ + +/* Make a '\0' separated arg vector from a unix argv vector, returning it in + ARGZ, and the total length in LEN. If a memory allocation error occurs, + ENOMEM is returned, otherwise 0. The result can be destroyed using free. */ +error_t argz_create(char **argv, char **argz, int *len); + +/* Make '\0' separated arg vector ARGZ printable by converting all the '\0's + except the last into spaces. */ +void argz_stringify(char *argz, int len); + +#endif /* __ARGZ_H__ */ diff --git a/utils/settrans.c b/utils/settrans.c new file mode 100644 index 00000000..e5f79847 --- /dev/null +++ b/utils/settrans.c @@ -0,0 +1,180 @@ +/* Set a file's translator. + + Copyright (C) 1995 Free Software Foundation, Inc. + + Written by Miles Bader <miles@gnu.ai.mit.edu> + + This program 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. + + This program 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 <hurd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <getopt.h> +#include <fcntl.h> +#include <unistd.h> + +#include <error.h> +#include <argz.h> +#include <start-trans.h> + +/* ---------------------------------------------------------------- */ + +#define USAGE "Usage: %s [OPTION...] FILE [TRANSLATOR...]\n" + +static void +usage(status) + int status; +{ + if (status != 0) + fprintf(stderr, "Try `%s --help' for more information.\n", + program_invocation_name); + else + { + printf(USAGE, program_invocation_name); + printf("\ +\n\ + -a, --active Set FILE's active translator\n\ + -p, --passive Set FILE's passive translator\n\ + -c, --create Create FILE if it doesn't exist\n\ + -f, --force Set the translator even if one already exists\n\ + -k, --keep-active Keep any currently running active translator\n\ + when setting the passive translator\n\ + -L, --dereference If a translator exists, put the new one on top\n\ + -t, --list Show FILE's passive translator\n\ + --help Give this help list\n\ +"); + } + + exit(status); +} + +#define SHORT_OPTIONS "apcfkLt?" + +static struct option options[] = +{ + {"active", no_argument, 0, 'a'}, + {"passive", no_argument, 0, 'p'}, + {"keep-active", no_argument, 0, 'k'}, + {"create", no_argument, 0, 'c'}, + {"force", no_argument, 0, 'f'}, + {"dereference", no_argument, 0, 'L'}, + {"list", no_argument, 0, 't'}, + {"help", no_argument, 0, '?'}, + {0, 0, 0, 0} +}; + +/* ---------------------------------------------------------------- */ + +void +main(int argc, char *argv[]) +{ + int opt; + error_t err; + + /* The filesystem node we're putting a translator on. */ + char *node_name; + file_t node; + + /* The translator's arg vector, in '\0' separated format. */ + char *argz = 0; + int argz_len = 0; + + /* The control port for any active translator we start up. */ + fsys_t active_control = MACH_PORT_NULL; + + /* Flags to pass to file_set_translator. By default we only set a + translator if there's no existing one. */ + int flags = FS_TRANS_SET | FS_TRANS_EXCL; + + /* Various option flags. */ + int passive = 0, active = 0, create = 0, force = 0, deref = 0, list = 0; + int keep_active = 0; + + /* Parse our options... */ + while ((opt = getopt_long(argc, argv, "+" SHORT_OPTIONS, options, 0)) != EOF) + switch (opt) + { + case 'a': active = 1; break; + case 'p': passive = 1; break; + case 'f': force = 1; break; + case 'k': keep_active = 1; break; + case 'c': create = 1; break; + case 'L': deref = 1; break; + case 't': list = 1; break; + case '?': usage(0); + default: usage(1); + } + + if (optind == argc) + { + fprintf(stderr, + "%s: Missing filename argument\n", program_invocation_name); + usage(1); + } + + node_name = argv[optind++]; + + if (!active && !passive) + passive = 1; + + node = + file_name_lookup(node_name, + (deref ? 0 : O_NOTRANS) | (create ? O_CREAT : 0), + 0666); + if (node == MACH_PORT_NULL) + error(1, errno, "%s", node_name); + + if (list) + /* Print out NODE's translator instead of setting it. */ + { + char buf[1024], *trans = buf; + int len = sizeof(buf); + + err = file_get_translator(node, &trans, &len); + if (err) + error(2, err, "%s", node_name); + + argz_stringify(trans, len); + printf("%s\n", trans); + } + else + { + err = argz_create(argv + optind, &argz, &argz_len); + if (err) + error(3, err, "Can't create argz vector"); + + if (active && argz_len > 0) + err = start_translator(node, argz, argz_len, 60000, &active_control); + if (err) + error(4, err, "%s", argz); + + if (force) + /* Kill any existing translators. */ + flags &= ~FS_TRANS_EXCL; + + err = + file_set_translator(node, + passive ? flags : 0, + (active || !keep_active) ? flags : 0, + 0, + argz, argz_len, + active_control, MACH_MSG_TYPE_MOVE_SEND); + if (err) + error(5, err, "%s", node_name); + } + + exit(0); +} |