aboutsummaryrefslogtreecommitdiff
path: root/libshouldbeinlibc
diff options
context:
space:
mode:
Diffstat (limited to 'libshouldbeinlibc')
-rw-r--r--libshouldbeinlibc/=argz.c190
-rw-r--r--libshouldbeinlibc/=argz.h89
-rw-r--r--libshouldbeinlibc/=envz.c171
-rw-r--r--libshouldbeinlibc/=envz.h55
-rw-r--r--libshouldbeinlibc/=line.c147
-rw-r--r--libshouldbeinlibc/=line.h128
-rw-r--r--libshouldbeinlibc/=path-lookup.c120
-rw-r--r--libshouldbeinlibc/ChangeLog1315
-rw-r--r--libshouldbeinlibc/Makefile40
-rw-r--r--libshouldbeinlibc/cacheq.c143
-rw-r--r--libshouldbeinlibc/cacheq.h87
-rw-r--r--libshouldbeinlibc/canon-host.c58
-rw-r--r--libshouldbeinlibc/exec-reauth.c106
-rw-r--r--libshouldbeinlibc/fsysops.c95
-rw-r--r--libshouldbeinlibc/idvec-auth.c79
-rw-r--r--libshouldbeinlibc/idvec-funcs.c2
-rw-r--r--libshouldbeinlibc/idvec-impgids.c123
-rw-r--r--libshouldbeinlibc/idvec-rep.c164
-rw-r--r--libshouldbeinlibc/idvec-verify.c362
-rw-r--r--libshouldbeinlibc/idvec.c338
-rw-r--r--libshouldbeinlibc/idvec.h218
-rw-r--r--libshouldbeinlibc/lcm.c46
-rw-r--r--libshouldbeinlibc/localhost.c66
-rw-r--r--libshouldbeinlibc/maptime-funcs.c5
-rw-r--r--libshouldbeinlibc/maptime.c79
-rw-r--r--libshouldbeinlibc/maptime.h52
-rw-r--r--libshouldbeinlibc/options.c231
-rw-r--r--libshouldbeinlibc/options.h79
-rw-r--r--libshouldbeinlibc/portinfo.c158
-rw-r--r--libshouldbeinlibc/portinfo.h58
-rw-r--r--libshouldbeinlibc/portxlate.c174
-rw-r--r--libshouldbeinlibc/portxlate.h67
-rw-r--r--libshouldbeinlibc/shared-dom.c57
-rw-r--r--libshouldbeinlibc/termsize.c54
-rw-r--r--libshouldbeinlibc/timefmt.c358
-rw-r--r--libshouldbeinlibc/timefmt.h58
-rw-r--r--libshouldbeinlibc/ugids-argp.c154
-rw-r--r--libshouldbeinlibc/ugids-auth.c53
-rw-r--r--libshouldbeinlibc/ugids-imply.c35
-rw-r--r--libshouldbeinlibc/ugids-merge.c109
-rw-r--r--libshouldbeinlibc/ugids-posix.c95
-rw-r--r--libshouldbeinlibc/ugids-rep.c118
-rw-r--r--libshouldbeinlibc/ugids-subtract.c130
-rw-r--r--libshouldbeinlibc/ugids-verify-auth.c190
-rw-r--r--libshouldbeinlibc/ugids-verify.c70
-rw-r--r--libshouldbeinlibc/ugids-xinl.c25
-rw-r--r--libshouldbeinlibc/ugids.c97
-rw-r--r--libshouldbeinlibc/ugids.h214
-rw-r--r--libshouldbeinlibc/wire.c163
-rw-r--r--libshouldbeinlibc/wire.h27
-rw-r--r--libshouldbeinlibc/xportinfo.c69
51 files changed, 7121 insertions, 0 deletions
diff --git a/libshouldbeinlibc/=argz.c b/libshouldbeinlibc/=argz.c
new file mode 100644
index 00000000..fd90a1e2
--- /dev/null
+++ b/libshouldbeinlibc/=argz.c
@@ -0,0 +1,190 @@
+/* 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;
+}
+
+/* ---------------------------------------------------------------- */
+
+/* Returns the number of strings in ARGZ. */
+int
+argz_count (char *argz, int len)
+{
+ int count = 0;
+ while (len > 0)
+ {
+ int part_len = strlen(argz);
+ argz += part_len + 1;
+ len -= part_len + 1;
+ count++;
+ }
+ return count;
+}
+
+/* ---------------------------------------------------------------- */
+
+/* Puts pointers to each string in ARGZ into ARGV, which must be large enough
+ to hold them all. */
+void
+argz_extract (char *argz, int len, char **argv)
+{
+ while (len > 0)
+ {
+ int part_len = strlen(argz);
+ *argv++ = argz;
+ argz += part_len + 1;
+ len -= part_len + 1;
+ }
+}
+
+/* ---------------------------------------------------------------- */
+
+/* Make '\0' separated arg vector ARGZ printable by converting all the '\0's
+ except the last into the character SEP. */
+void
+argz_stringify(char *argz, int len, int sep)
+{
+ while (len > 0)
+ {
+ int part_len = strlen(argz);
+ argz += part_len;
+ len -= part_len + 1;
+ if (len > 0)
+ *argz++ = sep;
+ }
+}
+
+/* Add BUF, of length BUF_LEN to the argz vector in ARGZ & ARGZ_LEN. */
+error_t
+argz_append (char **argz, unsigned *argz_len, char *buf, unsigned buf_len)
+{
+ unsigned new_argz_len = *argz_len + buf_len;
+ char *new_argz = realloc (*argz, new_argz_len);
+ if (new_argz)
+ {
+ bcopy (buf, new_argz + *argz_len, buf_len);
+ *argz = new_argz;
+ *argz_len = new_argz_len;
+ return 0;
+ }
+ else
+ return ENOMEM;
+}
+
+/* Add STR to the argz vector in ARGZ & ARGZ_LEN. This should be moved into
+ argz.c in libshouldbelibc. */
+error_t
+argz_add (char **argz, unsigned *argz_len, char *str)
+{
+ return argz_append (argz, argz_len, str, strlen (str) + 1);
+}
+
+/* Delete ENTRY from ARGZ & ARGZ_LEN, if any. */
+void
+argz_delete (char **argz, unsigned *argz_len, char *entry)
+{
+ if (entry)
+ /* Get rid of the old value for NAME. */
+ {
+ unsigned entry_len = strlen (entry) + 1;
+ *argz_len -= entry_len;
+ bcopy (entry + entry_len, entry, *argz_len - (entry - *argz));
+ if (*argz_len == 0)
+ {
+ free (*argz);
+ *argz = 0;
+ }
+ }
+}
+
+/* Insert ENTRY into ARGZ & ARGZ_LEN before BEFORE, which should be an
+ existing entry in ARGZ; if BEFORE is NULL, ENTRY is appended to the end.
+ Since ARGZ's first entry is the same as ARGZ, argz_insert (ARGZ, ARGZ_LEN,
+ ARGZ, ENTRY) will insert ENTRY at the beginning of ARGZ. If BEFORE is not
+ in ARGZ, EINVAL is returned, else if memory can't be allocated for the new
+ ARGZ, ENOMEM is returned, else 0. */
+error_t
+argz_insert (char **argz, unsigned *argz_len, char *before, char *entry)
+{
+ if (! before)
+ return argz_add (argz, argz_len, entry);
+
+ if (before < *argz || before >= *argz + *argz_len)
+ return EINVAL;
+
+ if (before > *argz)
+ /* Make sure before is actually the beginning of an entry. */
+ while (before[-1])
+ before--;
+
+ {
+ unsigned after_before = *argz_len - (before - *argz);
+ unsigned entry_len = strlen (entry) + 1;
+ unsigned new_argz_len = *argz_len + entry_len;
+ char *new_argz = realloc (*argz, new_argz_len);
+
+ if (new_argz)
+ {
+ before = new_argz + (before - *argz);
+ bcopy (before, before + entry_len, after_before);
+ bcopy (entry, before, entry_len);
+ *argz = new_argz;
+ *argz_len = new_argz_len;
+ return 0;
+ }
+ else
+ return ENOMEM;
+ }
+}
diff --git a/libshouldbeinlibc/=argz.h b/libshouldbeinlibc/=argz.h
new file mode 100644
index 00000000..1de0cd64
--- /dev/null
+++ b/libshouldbeinlibc/=argz.h
@@ -0,0 +1,89 @@
+/* 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);
+
+/* Returns the number of strings in ARGZ. */
+int argz_count (char *argz, int len);
+
+/* Puts pointers to each string in ARGZ into ARGV, which must be large enough
+ to hold them all. */
+void argz_extract (char *argz, int len, char **argv);
+
+/* Make '\0' separated arg vector ARGZ printable by converting all the '\0's
+ except the last into the character SEP. */
+void argz_stringify(char *argz, int len, int sep);
+
+/* Add BUF, of length BUF_LEN to the argz vector in ARGZ & ARGZ_LEN. */
+error_t
+argz_append (char **argz, unsigned *argz_len, char *buf, unsigned buf_len);
+
+/* Add STR to the argz vector in ARGZ & ARGZ_LEN. This should be moved into
+ argz.c in libshouldbelibc. */
+error_t argz_add (char **argz, unsigned *argz_len, char *str);
+
+/* Delete ENTRY from ARGZ & ARGZ_LEN, if any. */
+void argz_delete (char **argz, unsigned *argz_len, char *entry);
+
+/* Insert ENTRY into ARGZ & ARGZ_LEN before BEFORE, which should be an
+ existing entry in ARGZ; if BEFORE is NULL, ENTRY is appended to the end.
+ Since ARGZ's first entry is the same as ARGZ, argz_insert (ARGZ, ARGZ_LEN,
+ ARGZ, ENTRY) will insert ENTRY at the beginning of ARGZ. If BEFORE is not
+ in ARGZ, EINVAL is returned, else if memory can't be allocated for the new
+ ARGZ, ENOMEM is returned, else 0. */
+error_t
+argz_insert (char **argz, unsigned *argz_len, char *before, char *entry);
+
+/* Returns the next entry in ARGZ & ARGZ_LEN after ENTRY, or NULL if there
+ are no more. If entry is NULL, then the first entry is returned. This
+ behavior allows two convenient iteration styles:
+
+ char *entry = 0;
+ while (entry = argz_next (argz, argz_len, entry))
+ ...;
+
+ or
+
+ char *entry;
+ for (entry = argz; entry; entry = argz_next (argz, argz_len, entry))
+ ...;
+*/
+extern inline char *
+argz_next (char *argz, unsigned argz_len, char *entry)
+{
+ if (entry)
+ if (entry >= argz + argz_len)
+ return 0;
+ else
+ return entry + strlen (entry) + 1;
+ else
+ if (argz_len > 0)
+ return argz;
+ else
+ return 0;
+}
+
+#endif /* __ARGZ_H__ */
diff --git a/libshouldbeinlibc/=envz.c b/libshouldbeinlibc/=envz.c
new file mode 100644
index 00000000..4d0816e4
--- /dev/null
+++ b/libshouldbeinlibc/=envz.c
@@ -0,0 +1,171 @@
+/* Routines for dealing with '\0' separated environment vectors
+
+ Copyright (C) 1995, 1996 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 <malloc.h>
+#include <string.h>
+
+#include "envz.h"
+
+/* The character separating names from values in an envz. */
+#define SEP '='
+
+/* Returns a pointer to the entry in ENVZ for NAME, or 0 if there is none.
+ If NAME contains the separator character, only the portion before it is
+ used in the comparison. */
+char *
+envz_entry (char *envz, unsigned envz_len, char *name)
+{
+ while (envz_len)
+ {
+ char *p = name;
+ char *entry = envz; /* Start of this entry. */
+
+ /* See how far NAME and ENTRY match. */
+ while (envz_len && *p == *envz && *p && *p != SEP)
+ p++, envz++, envz_len--;
+
+ if ((*envz == '\0' || *envz == SEP) && (*p == '\0' || *p == SEP))
+ /* Bingo! */
+ return entry;
+
+ /* No match, skip to the next entry. */
+ while (envz_len && *envz)
+ envz++, envz_len--;
+ if (envz_len)
+ envz++, envz_len--; /* skip '\0' */
+ }
+
+ return 0;
+}
+
+/* Returns a pointer to the value portion of the entry in ENVZ for NAME, or 0
+ if there is none. */
+char *
+envz_get (char *envz, unsigned envz_len, char *name)
+{
+ char *entry = envz_entry (envz, envz_len, name);
+ if (entry)
+ {
+ while (*entry && *entry != SEP)
+ entry++;
+ if (*entry)
+ entry++;
+ else
+ entry = 0; /* A null entry. */
+ }
+ return entry;
+}
+
+/* Remove the entry for NAME from ENVZ & ENVZ_LEN, if any. */
+void
+envz_remove (char **envz, unsigned *envz_len, char *name)
+{
+ char *entry = envz_entry (*envz, *envz_len, name);
+ if (entry)
+ argz_delete (envz, envz_len, entry);
+}
+
+/* Adds an entry for NAME with value VALUE to ENVZ & ENVZ_LEN. If an entry
+ with the same name already exists in ENVZ, it is removed. If VALUE is
+ NULL, then the new entry will a special null one, for which envz_get will
+ return NULL, although envz_entry will still return an entry; this is handy
+ because when merging with another envz, the null entry can override an
+ entry in the other one. Null entries can be removed with envz_strip (). */
+error_t
+envz_add (char **envz, unsigned *envz_len, char *name, char *value)
+{
+ envz_remove (envz, envz_len, name);
+
+ if (value)
+ /* Add the new value, if there is one. */
+ {
+ unsigned name_len = strlen (name);
+ unsigned value_len = strlen (value);
+ unsigned old_envz_len = *envz_len;
+ unsigned new_envz_len = old_envz_len + name_len + 1 + value_len + 1;
+ char *new_envz = realloc (*envz, new_envz_len);
+
+ if (new_envz)
+ {
+ bcopy (name, new_envz + old_envz_len, name_len);
+ new_envz[old_envz_len + name_len] = SEP;
+ bcopy (value, new_envz + old_envz_len + name_len + 1, value_len);
+ new_envz[new_envz_len - 1] = 0;
+
+ *envz = new_envz;
+ *envz_len = new_envz_len;
+
+ return 0;
+ }
+ else
+ return ENOMEM;
+ }
+ else
+ /* Add a null entry. */
+ return argz_add (envz, envz_len, name);
+}
+
+/* Adds each entry in ENVZ2 to ENVZ & ENVZ_LEN, as if with envz_add(). If
+ OVERRIDE is true, then values in ENVZ2 will supercede those with the same
+ name in ENV, otherwise not. */
+error_t
+envz_merge (char **envz, unsigned *envz_len, char *envz2, unsigned envz2_len,
+ int override)
+{
+ error_t err = 0;
+
+ while (envz2_len && ! err)
+ {
+ char *old = envz_entry (*envz, *envz_len, envz2);
+ size_t new_len = strlen (envz2) + 1;
+
+ if (! old)
+ err = argz_append (envz, envz_len, envz2, new_len);
+ else if (override)
+ {
+ argz_delete (envz, envz_len, old);
+ err = argz_append (envz, envz_len, envz2, new_len);
+ }
+
+ envz2 += new_len;
+ envz2_len -= new_len;
+ }
+
+ return err;
+}
+
+/* Remove null entries. */
+void
+envz_strip (char **envz, unsigned *envz_len)
+{
+ char *entry = *envz;
+ unsigned left = *envz_len;
+ while (left)
+ {
+ unsigned entry_len = strlen (entry) + 1;
+ left -= entry_len;
+ if (! index (entry, SEP))
+ /* Null entry. */
+ bcopy (entry, entry + entry_len, left);
+ else
+ entry += entry_len;
+ }
+ *envz_len = entry - *envz;
+}
diff --git a/libshouldbeinlibc/=envz.h b/libshouldbeinlibc/=envz.h
new file mode 100644
index 00000000..55224c72
--- /dev/null
+++ b/libshouldbeinlibc/=envz.h
@@ -0,0 +1,55 @@
+/* Routines for dealing with '\0' separated environment 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 __ENVZ_H__
+#define __ENVZ_H__
+
+#include <errno.h>
+
+/* Envz's are argz's too, and should be created etc., using the same
+ routines. */
+#include <argz.h>
+
+/* Returns a pointer to the entry in ENVZ for NAME, or 0 if there is none. */
+char *envz_entry (char *envz, unsigned envz_len, char *name);
+
+/* Returns a pointer to the value portion of the entry in ENVZ for NAME, or 0
+ if there is none. */
+char *envz_get (char *envz, unsigned envz_len, char *name);
+
+/* Adds an entry for NAME with value VALUE to ENVZ & ENVZ_LEN. If an entry
+ with the same name already exists in ENVZ, it is removed. If VALUE is
+ NULL, then the new entry will a special null one, for which envz_get will
+ return NULL, although envz_entry will still return an entry; this is handy
+ because when merging with another envz, the null entry can override an
+ entry in the other one. Null entries can be removed with envz_strip (). */
+error_t envz_add (char **envz, unsigned *envz_len, char *name, char *value);
+
+/* Adds each entry in ENVZ2 to ENVZ & ENVZ_LEN, as if with envz_add(). If
+ OVERRIDE is true, then values in ENVZ2 will supercede those with the same
+ name in ENV, otherwise not. */
+error_t
+envz_merge (char **envz, unsigned *envz_len, char *envz2, unsigned envz2_len,
+ int override);
+
+/* Remove null entries. */
+void envz_strip (char **envz, unsigned *envz_len);
+
+#endif /* __ENVZ_H__ */
diff --git a/libshouldbeinlibc/=line.c b/libshouldbeinlibc/=line.c
new file mode 100644
index 00000000..1c8eab8e
--- /dev/null
+++ b/libshouldbeinlibc/=line.c
@@ -0,0 +1,147 @@
+/* Simple output formatting functions
+
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This file 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 <malloc.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <line.h>
+
+/* Return a new line structure, which will output to STREAM. WIDTH is the
+ maximum number of characters per line. If enough memory can't be
+ allocated, 0 is returned. */
+struct line *
+make_line (FILE *stream, unsigned width)
+{
+ struct line *line = malloc (sizeof (struct line));
+ if (line)
+ {
+ line->buf = malloc (width + 2);
+ if (line->buf)
+ {
+ line->max = line->buf + width;
+ line->point = line->buf;
+ line->stream = stream;
+ }
+ else
+ {
+ free (line);
+ line = 0;
+ }
+ }
+ return line;
+}
+
+/* Free LINE and any resources it uses. */
+void
+line_free (struct line *line)
+{
+ if (line->point > line->buf)
+ line_newline (line, 0);
+ free (line->buf);
+ free (line);
+}
+
+/* Adds the text in STR to LINE, wrapping words as necessary to fit.
+ LMARGIN is the left margin used when wrapping; whitespace is deleted at
+ wrap-points. Newlines in STR are honoured by adding a newline and
+ indenting to LMARGIN; any following whitespace is kept. */
+void
+line_fill (struct line *line, const char *str, unsigned lmargin)
+{
+ while (*str)
+ {
+ const char *word_end = str;
+
+ while (*word_end == ' ')
+ word_end++;
+
+ if (*word_end == '\n')
+ {
+ if (line_column (line) > lmargin)
+ line_newline (line, lmargin);
+ str = word_end + 1;
+ }
+ else if (*word_end)
+ {
+ const char *word_start = word_end;
+ while (*word_end && !isspace (*word_end))
+ word_end++;
+ if (line_left (line, word_end - str) >= 0)
+ {
+ line_write (line, str, word_end - str);
+ str = word_end;
+ }
+ else
+ /* Word won't fit on the current line, move to the next one. */
+ {
+ line_newline (line, lmargin);
+ str = word_start; /* Omit spaces when wrapping. */
+ }
+ }
+ }
+}
+
+/* Clean up after a printf to LINE, to take care of any newlines that might
+ have been added. ADDED is the amount the printf has added to the line.
+ We take care of updating LINE's point. */
+void
+_line_cleanup_printf (struct line *line, unsigned added)
+{
+ char *point = line->point, *new_point = point + added, *last_nl = new_point;
+
+ while (last_nl > point)
+ if (*--last_nl == '\n')
+ /* There's a newline; deal. */
+ {
+ last_nl++;
+ fwrite (line->buf, 1, last_nl - line->buf, line->stream);
+ if (last_nl < new_point)
+ bcopy (last_nl, line->buf, new_point - last_nl);
+ new_point -= (last_nl - line->buf);
+ break;
+ }
+
+ line->point = new_point;
+}
+
+/* Add STR, of length LEN, to LINE. */
+void
+line_write (struct line *line, const char *str, unsigned len)
+{
+ const char *end = memchr (str, '\n', len) ?: str + len;
+ unsigned line_len = end - str;
+ char *p = line->point, *max = line->max;
+ if (line_len > max - p)
+ line_len = max - p;
+ bcopy (str, p, line_len);
+ p += line_len;
+ if (line_len == len)
+ line->point = p;
+ else
+ {
+ char *buf = line->buf;
+ fwrite (buf, 1, p - buf, line->stream);
+ line->point = buf;
+ line_write (line, end + 1, len - line_len - 1);
+ }
+}
diff --git a/libshouldbeinlibc/=line.h b/libshouldbeinlibc/=line.h
new file mode 100644
index 00000000..54ab15de
--- /dev/null
+++ b/libshouldbeinlibc/=line.h
@@ -0,0 +1,128 @@
+/* Simple output formatting functions
+
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This file 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. */
+
+#ifndef __LINE_H__
+#define __LINE_H__
+
+#include <stdio.h>
+
+struct line
+{
+ char *buf;
+ char *point, *max;
+ FILE *stream;
+};
+
+extern void
+_line_cleanup_printf (struct line *line, unsigned added);
+
+/* Printf FMT & ARGS to LINE. */
+/* XXX This implementation is kind of bogus because it pretends to deal with
+ newlines in the output, but it just uses LINE's buffer for the output and
+ anything past the end of the buffer will get chopped. A terminating
+ newline will work ok though. */
+#define line_printf(line, fmt, args...) \
+ ({ struct line *_line = (line); \
+ _line_cleanup_printf (_line, \
+ snprintf (_line->point, _line->max - _line->point, (fmt) , ##args)); \
+ })
+
+/* Returns the amount of free space in line after adding AMOUNT characters to
+ it (which will be negative if this would overflow). */
+extern inline int
+line_left (struct line *line, unsigned amount)
+{
+ return line->max - line->point - amount;
+}
+
+/* Return the column position of LINE's output point, which starts at 0. */
+extern inline unsigned
+line_column (struct line *line)
+{
+ return line->point - line->buf;
+}
+
+/* Add enough spaces to LINE to move the point to column TARGET. */
+
+
+extern inline void
+line_indent_to (struct line *line, int target)
+{
+ while (line->point < line->buf + target && line->point < line->max)
+ *line->point++ = ' ';
+}
+
+/* Emit the current contents of LINE and a newline to its stream, and fill
+ LINE with LMARGIN spaces. */
+extern inline void
+line_newline (struct line *line, int lmargin)
+{
+ *line->point++ = '\n';
+ *line->point = '\0';
+ fputs (line->buf, line->stream);
+ line->point = line->buf;
+ if (lmargin)
+ line_indent_to (line, lmargin);
+}
+
+/* If LINE isn't before or at column position LMARGIN, then add a newline
+ and indent to that position. */
+extern inline void
+line_freshline (struct line *line, int lmargin)
+{
+ if (line_column (line) > lmargin)
+ line_newline (line, lmargin);
+}
+
+/* Add a character to LINE, unless it's full. */
+extern inline int
+line_putc (struct line *line, int ch)
+{
+ if (ch == '\n')
+ line_newline (line, 0);
+ else if (line->point < line->max)
+ *line->point++ = ch;
+ return ch;
+}
+
+/* Adds the text in STR to LINE, wrapping words as necessary to fit. LMARGIN
+ is the left margin used when wrapping. */
+void line_fill (struct line *line, const char *str, unsigned lmargin);
+
+/* Add STR, of length LEN, to LINE. */
+void line_write (struct line *line, const char *str, unsigned len);
+
+/* Add STR to LINE. */
+extern inline void line_puts (struct line *line, const char *str)
+{
+ line_write (line, str, strlen (str));
+}
+
+/* Return a new line structure, which will output to STREAM. WIDTH is the
+ maximum number of characters per line. If enough memory can't be
+ allocated, 0 is returned. */
+struct line *make_line (FILE *stream, unsigned width);
+
+/* Free LINE and any resources it uses. */
+void line_free (struct line *line);
+
+#endif /* __LINE_H__ */
diff --git a/libshouldbeinlibc/=path-lookup.c b/libshouldbeinlibc/=path-lookup.c
new file mode 100644
index 00000000..b89f8d4d
--- /dev/null
+++ b/libshouldbeinlibc/=path-lookup.c
@@ -0,0 +1,120 @@
+/* Filename lookup using a search path
+
+ 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 <string.h>
+#include <hurd.h>
+#include <hurd/lookup.h>
+
+/* If FILE_NAME contains a '/', or PATH is NULL, call FUN with FILE_NAME, and
+ return the result (if PREFIXED_NAME is non-NULL, setting *PREFIXED_NAME to
+ NULL). Otherwise, call FUN repeatedly with FILE_NAME prefixed with each
+ successive `:' separated element of PATH, returning whenever FUN returns
+ 0 (if PREFIXED_NAME is non-NULL, setting *PREFIXED_NAME to the resulting
+ prefixed path). If FUN never returns 0, return the first non-ENOENT
+ return value, or ENOENT if there is none. */
+error_t
+file_name_path_scan (const char *file_name, const char *path,
+ error_t (*fun)(const char *name),
+ char **prefixed_name)
+{
+ if (path == NULL || index (file_name, '/'))
+ {
+ if (prefixed_name)
+ *prefixed_name = 0;
+ return (*fun)(file_name);
+ }
+ else
+ {
+ error_t real_err = 0;
+ size_t file_name_len = strlen (file_name);
+
+ for (;;)
+ {
+ error_t err;
+ const char *next = index (path, ':') ?: path + strlen (path);
+ size_t pfx_len = next - path;
+ char pfxed_name[pfx_len + 2 + file_name_len + 1];
+
+ if (pfx_len == 0)
+ pfxed_name[pfx_len++] = '.';
+ else
+ bcopy (path, pfxed_name, pfx_len);
+ if (pfxed_name[pfx_len - 1] != '/')
+ pfxed_name[pfx_len++] = '/';
+ bcopy (file_name, pfxed_name + pfx_len, file_name_len + 1);
+
+ err = (*fun)(pfxed_name);
+ if (err == 0)
+ {
+ if (prefixed_name)
+ *prefixed_name = strdup (pfxed_name);
+ return 0;
+ }
+ if (!real_err && err != ENOENT)
+ real_err = err;
+
+ if (*next == '\0')
+ return real_err ?: ENOENT;
+ else
+ path = next + 1;
+ }
+ }
+}
+
+/* Lookup FILE_NAME and return the node opened with FLAGS & MODE in result
+ (see hurd_file_name_lookup for details), but a simple filename (without
+ any directory prefixes) will be consectutively prefixed with the pathnames
+ in the `:' separated list PATH until one succeeds in a successful lookup.
+ If none succeed, then the first error that wasn't ENOENT is returned, or
+ ENOENT if no other errors were returned. If PREFIXED_NAME is non-NULL,
+ then if RESULT is looked up directly, *PREFIXED_NAME is set to NULL, and
+ if it is looked up using a prefix from PATH, *PREFIXED_NAME is set to
+ malloced storage containing the prefixed name. */
+error_t
+hurd_file_name_path_lookup (error_t (*use_init_port)
+ (int which,
+ error_t (*operate) (mach_port_t)),
+ file_t (*get_dtable_port) (int fd),
+ const char *file_name, const char *path,
+ int flags, mode_t mode,
+ file_t *result, char **prefixed_name)
+{
+ error_t lookup (const char *name)
+ {
+ return
+ __hurd_file_name_lookup (use_init_port, get_dtable_port,
+ name, flags, mode, result);
+ }
+ return file_name_path_scan (file_name, path, lookup, prefixed_name);
+}
+
+mach_port_t
+file_name_path_lookup (const char *file_name, const char *path,
+ int flags, mode_t mode, char **prefixed_name)
+{
+ error_t err;
+ file_t result;
+
+ err = hurd_file_name_path_lookup (&_hurd_ports_use, &__getdport,
+ file_name, path, flags, mode,
+ &result, prefixed_name);
+
+ return err ? (__hurd_fail (err), MACH_PORT_NULL) : result;
+}
diff --git a/libshouldbeinlibc/ChangeLog b/libshouldbeinlibc/ChangeLog
new file mode 100644
index 00000000..fd6ec7c8
--- /dev/null
+++ b/libshouldbeinlibc/ChangeLog
@@ -0,0 +1,1315 @@
+2000-01-29 Roland McGrath <roland@baalperazim.frob.com>
+
+ * maptime.h: Include <errno.h> for error_t decl.
+
+1999-10-29 Roland McGrath <roland@baalperazim.frob.com>
+
+ * wire.c: Use a weak reference to _DYNAMIC.
+
+1999-09-29 Mark Kettenis <kettenis@gnu.org>
+
+ * idvec.c (idvec_setid): Switch last two arguments in call to
+ idvec_insert_only.
+ * idvec.h: Doc fix.
+
+1999-09-27 Thomas Bushnell, BSG <tb@mit.edu>
+
+ * idvec.c (idvec_setid): Implement Posix saved set-user id
+ correctly.
+ (idvec_insert_only): Doc fix.
+ Reported by Mark Kettenis <kettenis@wins.uva.nl>.
+
+1999-08-23 Roland McGrath <roland@baalperazim.frob.com>
+
+ * wire.c (map_extent): Use p_memsz instead of p_filesz.
+ (loaded): Return zero if _DYNAMIC has address zero (i.e., static link).
+
+1999-08-19 Roland McGrath <roland@baalperazim.frob.com>
+
+ * mktime.c: File removed. Current libc code is good.
+ * Makefile (SRCS): Remove mktime.c.
+
+1999-07-11 Roland McGrath <roland@baalperazim.frob.com>
+
+ * portinfo.h: Don't include <sys/types.h>, <sys/mman.h>.
+ This is an exported header, and its decls don't need them.
+ * portinfo.c: Include them here instead.
+ * xportinfo.c: And here.
+
+1999-07-11 Thomas Bushnell, BSG <tb@mit.edu>
+
+ * ugids-argp.c (parse_opt): Clarify if-then-else structure by
+ adding more braces.
+
+ * portinfo.h: Include <sys/types.h>.
+ * portxlate.c: Likewise.
+ * portinfo.c: (print_port_info): Cast first arg of munmap correctly.
+ (print_task_ports_info): Likewise.
+ * xportinfo.c (print_xlated_task_ports_info): Likewise.
+ * idvec-auth.c (idvec_merge_auth): Likewise.
+ * portxlate.c (port_name_xlator_create): Likewise.
+ (port_name_xlator_free): Likewise.
+
+1999-07-10 Roland McGrath <roland@baalperazim.frob.com>
+
+ * portinfo.h: Add #include <sys/mman.h> for munmap decl.
+ * fsysops.c: Likewise.
+ * idvec-auth.c: Likewise.
+ * portxlate.c: Likewise.
+
+1999-07-03 Thomas Bushnell, BSG <tb@mit.edu>
+
+ * fsysops.c (fsys_get_readonly): Use munmap instead of vm_deallocate.
+ * idvec-auth.c (idvec_merge_auth): Likewise.
+ * portinfo.c (print_port_info): Likewise.
+ (print_task_ports_info): Likewise.
+ * portxlate.c (port_name_xlator_create): Likewise.
+ (port_name_xlator_free): Likewise.
+ * xportinfo.c (print_xlated_task_ports_info): Likewise.
+
+1999-05-23 Roland McGrath <roland@baalperazim.frob.com>
+
+ * idvec-verify.c (SHADOW_PASSWORD_STRING): New macro.
+ (verify_id): Check for shadow password immediately after getpwuid_r
+ call, and replace PW->pw_passwd pointer with SP->sp_pwdp.
+ This is ok since the only use will be later in the function,
+ and we give the lookup buffer function scope.
+ (verify_passwd): Don't call CHECK_SHADOW for main passwd,
+ only when rechecking for wheel-group hack.
+
+1999-05-20 Roland McGrath <roland@baalperazim.frob.com>
+
+ * idvec-verify.c (verify_passwd): Avoid nonreentrant getpwuid.
+ If pw_passwd is "x", use getspnam_r and use its sp_pwdp if it succeeds.
+
+1998-12-21 Mark Kettenis <kettenis@phys.uva.nl>
+
+ * ugids-verify-auth.c: Include <hurd/password.h> again and remove
+ temporary definitions of password_check_user and
+ password_check_group.
+
+1998-11-29 Mark Kettenis <kettenis@phys.uva.nl>
+
+ * idvec-verify.c (verify_passwd): Grant access when the password
+ in the passwd DB is empty.
+ (verify_id): Also call verify_fn when the password in the password
+ DB is empty.
+
+1999-02-12 Gordon Matzigkeit <gord@trick.fig.org>
+
+ * Makefile (LCLHDRS): Purge argp-fmtstream.h and argp-namefrob.h.
+
+1998-11-30 Mark Kettenis <kettenis@phys.uva.nl>
+
+ * ugids-verify-auth.c (svma_state_add_auths): Allocate correct
+ number of bytes for new auth port array.
+ (server_verify_make_auth): Set check to password_check_group if
+ is_group is true and to password_check_user if not. Not the other
+ way around.
+
+1998-09-26 Mark Kettenis <kettenis@phys.uva.nl>
+
+ * cacheq.c (cacheq_set_length): Fix the limit of the destination
+ entries. Decide that there is no following entry if the current
+ entry is equal or greater than this limit.
+
+1998-10-20 Roland McGrath <roland@baalperazim.frob.com>
+
+ * idvec-verify.c (verify_id): Add braces to silence gcc warning.
+
+1998-10-19 Roland McGrath <roland@baalperazim.frob.com>
+
+ * exec-reauth.c (exec_reauth): Add braces to silence gcc warning.
+ * idvec-rep.c (idvec_rep): Likewise.
+ * idvec-verify.c (verify_id): Likewise.
+ * portinfo.c (print_port_info): Likewise.
+ * ugids-verify-auth.c (ugids_verify_make_auth): Likewise.
+
+1998-09-04 Roland McGrath <roland@baalperazim.frob.com>
+
+ * ugids-verify-auth.c (ugids_verify_make_auth): Fix typos in
+ svma_state change of 1998-08-11.
+
+ * idvec.c, idvec-auth.c (id_t): Remove typedef; use uid_t everywhere.
+ The name `id_t' is coopted in libc now for the SVID `waitid' interface.
+
+ * Makefile (SRCS): Remove argz-replace.c and argp-*.c from the list.
+ (installhdrs): Remove argp.h from the list.
+
+1998-08-12 Roland McGrath <roland@baalperazim.frob.com>
+
+ * argz-replace.c: Removed, now in libcwhereitshouldbe.
+
+ * argp-ba.c, argp-eexst.c, argp-ex1.c, argp-ex2.c, argp-ex3.c,
+ argp-ex4.c, argp-fmtstream.c, argp-fmtstream.h argp-fs-xinl.c,
+ argp-help.c, argp-namefrob.h argp-parse.c, argp-pv.c, argp-pvh.c,
+ argp-test.c, argp-xinl.c, argp.h: Removed, now in libcwhereitshouldbe.
+
+1998-08-11 Roland McGrath <roland@baalperazim.frob.com>
+
+ * ugids-verify-auth.c: Leave #include <hurd/password.h> there, but
+ commented out for the time being.
+ (password_check_user, password_check_group): Make symbols weak; these
+ are temporary defns until we get back in synch with libc.
+
+ * ugids-verify-auth.c (ugids_verify_make_auth): Properly initialize
+ SVMA_STATE members if they will be used.
+
+Wed Jul 29 16:25:50 1998 Thomas Bushnell, BSG <tb@mit.edu>
+
+ * ugids-verify-auth.c: Don't include <hurd/password.h> for now.
+
+1997-09-26 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * idvec-verify.c (verify_passwd, get_passwd): New functions.
+ (idvec_verify): Change type of GETPASS_FN arg.
+ Add GETPASS_HOOK, VERIFY_FN, and VERIFY_HOOK args & use them.
+ (verify_id): Change type of GETPASS_FN arg.
+ Add GETPASS_HOOK, VERIFY_FN, and VERIFY_HOOK args.
+ Remove WHEEL_UID arg.
+ Use VERIFY_FN & VERIFY_HOOK instead of doing password comparison
+ ourselves.
+ * ugids.h (ugids_verify_make_auth): New declaration.
+ (ugids_verify): Change type of GETPASS_FN arg.
+ Add GETPASS_HOOK, VERIFY_FN, and VERIFY_HOOK args.
+ (ugids_make_auth): Change FROM arg into an array, & add NUM_FROM.
+ * ugids-verify.c (ugids_verify): Change type of GETPASS_FN arg.
+ Add GETPASS_HOOK, VERIFY_FN, and VERIFY_HOOK args.
+ * ugids-verify-auth.c: New file.
+ * ugids-auth.c (ugids_make_auth): Change FROM arg into an array, &
+ add NUM_FROM arg.
+ * Makefile (SRCS): Add ugids-verify-auth.c.
+
+1997-09-25 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * idvec.h (idvec_verify): Change type of GETPASS_FN arg.
+ Add GETPASS_HOOK, VERIFY_FN, and VERIFY_HOOK args.
+
+1997-08-18 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * mktime.c: A copy of libc's time/mktime.c with the
+ overflow-detection code ifdefd out, to avoid problems with
+ floating point.
+ * Makefile (SRCS): Add mktime.c (temporarily).
+
+1997-07-28 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * ugids-posix.c (ugids_set_posix_user): Ignore errors from
+ idvec_merge_implied_gids.
+ * ugids.c (ugids_add_user): Likewise.
+ * idvec-impgids.c (idvec_merge_implied_gids): Do all ids in UIDS
+ even if one returns an error.
+
+1997-07-23 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * maptime.c (maptime_map): Allow MTIME to be mapped anywhere.
+
+1997-07-22 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * maptime.c (maptime_map): For the device-file case, don't use
+ wierd file_get_storage_info method for getting device port, just
+ use io_map to get a memory object directly from the file.
+
+ * argz-replace.c: New file (until the libc version is more widely available).
+ * Makefile (SRCS): Add argz-replace.c (temporarily).
+
+1997-06-21 17:35 Ulrich Drepper <drepper@cygnus.com>
+
+ * argp.h: Remove extra #endif. Pretty print.
+
+1997-06-13 10:06 Richard Henderson <rth@tamu.edu>
+
+ * argp-parse.c: [_LIBC] <libc-lock.h> -> <bits/libc-lock.h>.
+ * argp-fmtstream.h: Standardize the multiple-include protect (for libc).
+ * argp.h: Likewise.
+
+1997-06-13 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-parse.c (argp_version_parser): Include `(PROGRAM ERROR)' in
+ the no-version error text to indicate that something's fucked.
+ [!_] (N_): New macro.
+ (argp_default_options, argp_version_options): Wrap doc strings in N_().
+
+1997-06-12 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-parse.c (parser_parse_opt): Detect and report unhandled
+ options here.
+ (parser_parse_args): Function removed.
+ (parser_parse_arg): Handle ARGP_KEY_ARGS here.
+ Adjust NEXT pointer back if we fail to parse any args.
+ (parser_parse_next): Don't use parser_parse_args. Leave state
+ NEXT frobbing to parser_parse_arg.
+
+1997-06-12 21:22 Ulrich Drepper <drepper@cygnus.com>
+
+ * argp-help.c (argp_args_usage): Don't modify `fdoc' value since
+ it is used to distinguish filtered strings from unmodifed strings.
+
+1997-06-12 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * maptime.h: Include <sys/time.h>.
+
+1997-06-11 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp.h (ARGP_KEY_ARGS, ARGP_KEY_FINI): New macros.
+ * argp-parse.c (parser_parse_next): Try parser_parse_args if other
+ methods fail.
+ (parser_parse_arg): New function.
+ (parser_finalize): Do another pass over the parsers with ARGP_KEY_FINI.
+
+Wed Jun 4 15:05:10 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp.h, argp-help.c, argp-parse.c: Sync with libc version (there
+ were minor whitespace differences, etc).
+
+ * argp-help.c (_help): Use uparams.usage_indent instead of the
+ USAGE_INDENT macro.
+
+Thu May 29 15:00:07 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * idvec-verify.c (idvec_verify): Fix detection of multiple ids.
+
+Tue May 27 14:16:08 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-help.c (argp_args_usage): Supply correct argp to filter_doc.
+
+Sun May 25 21:57:08 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-parse.c (parser_init): For the special case where no
+ parsing function is supplied for an argp, propagate its input to
+ its first child, if any.
+
+ * argp.h (struct argp_state): `argp' field renamed to `root_argp'.
+ * argp-help.c (__argp_state_help, argp_args_usage, hol_help):
+ Replace references to STATE->argp with STATE->root_argp.
+ * argp-parse.c (parser_init): Likewise.
+
+Fri May 23 10:23:51 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * idvec.h (idvec_contains): Now an inline function.
+ (idvec_equal): New inline function.
+ * idvec.c (idvec_tail): Function removed (now inline in idvec.h).
+ * ugids-imply.c, ugids-posix.c: New files.
+ * Makefile (SRCS): Add ugids-imply.c & ugids-posix.c.
+
+Thu May 22 11:38:01 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * idvec.c (idvec_subtract, idvec_keep): New functions.
+ (idvec_contains, idvec_tail_contains): Make IDVEC arg const.
+ (idvec_tail_contains): Rewrite.
+ (idvec_set_ids, idvec_merge_ids): Make IDS arg const.
+ (idvec_set, idvec_merge): Make NEW arg const.
+ * idvec.h (idvec_subtract, idvec_keep, idvec_rep, idvec_uids_rep,
+ idvec_gids_rep, idvec_merge_implied_gids, idvec_verify):
+ New declarations.
+ (idvec_fini): New macro.
+ (idvec_contains, idvec_tail_contains): Make IDVEC arg const.
+ (idvec_set_ids, idvec_merge_ids): Make IDS arg const.
+ (idvec_set, idvec_merge): Make NEW arg const.
+ (idvec_is_empty): New function.
+ (IDVEC_INIT): New macro.
+ * idvec-impgids.c, idvec-verify.c, idvec_rep.c: New files.
+ * ugids.h, ugids.c, ugids-subtract.c, ugids-verify.c,
+ ugids-argp.c, ugids-rep.c, ugids-auth.c, ugids-xinl.c,
+ ugids-merge.c: New files.
+ * Makefile (SRCS): Add idvec-impgids.c, idvec-verify.c,
+ idvec-rep.c, ugids.c, ugids-subtract.c, ugids-verify.c,
+ ugids-argp.c, ugids-rep.c, ugids-auth.c, ugids-xinl.c,
+ & ugids-merge.c.
+ (installhdrs): Add ugids.h.
+
+Wed May 21 17:53:30 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-help.c (hol_add_cluster): Initialize CL->depth.
+
+Tue May 20 14:01:00 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-help.c (_help): Supply STATE to argp_args_usage.
+ (argp_args_usage): Add filtering of the args doc string.
+ (comma): Print cluster headers for the first entry too.
+ * argp.h (ARGP_KEY_HELP_ARGS_DOC): New macro.
+
+1997-04-09 01:24 Ulrich Drepper <drepper@cygnus.com>
+
+ * argp-fmtstream.c: Add casts to prevent warnings.
+ * argp-fmtstream.h: Likewise.
+ * argp-help.c: Likewise.
+
+1997-02-27 16:26 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+
+ * argp-parse.c (parser_finalize): Always set *END_INDEX if
+ supplied.
+
+Thu May 8 17:15:31 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp.h [!__error_t_defined] (__error_t_defined): Define.
+ * argp-help.c (canon_doc_option): Correct ctype tests.
+
+Wed Mar 5 16:49:51 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-help.c (__argp_state_help): Use ARGP_ERR_EXIT_STATUS when
+ exiting due to an error.
+ * argp.h (argp_err_exit_status): New variable.
+ * argp-eexst.c: New file.
+ * Makefile (SRCS): Add argp-eexst.c.
+
+Fri Feb 21 10:41:02 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp.h (OPTION_NO_USAGE): New macro.
+ * argp-help.c (usage_long_opt, usage_argful_short_opt,
+ add_argless_short_opt): Implement OPTION_NO_USAGE.
+
+Thu Feb 20 15:56:16 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * idvec.c (idvec_insert_only): Handle POS >= IDVEC->num correctly.
+ (idvec_insert, idvec_remove): Handle POS > IDVEC->num correctly.
+
+ * argp-fmtstream.c (__argp_fmtstream_update): Account for case
+ where NEXTLINE points one past the end of the active buffer.
+
+ * argp-help.c <stddef.h>: New include.
+ (__argp_failure): Only exit if STATE says it's ok.
+ (print_header, hol_entry_help): Use UPARAMS fields rather than
+ constants.
+ (_help): Call fill_in_uparams if necessary.
+ (struct hol_help_state): New type.
+ (struct pentry_state): Add hhstate field. Remove prev_entry &
+ sep_groups fields.
+ (hol_entry_help): Add HHSTATE parameter. Remove prev_entry &
+ sep_groups parameters.
+ Suppress duplicate arguments if requested, and note the fact.
+ (print_header, comma): Use PEST->hhstate fields.
+ (hol_help): Add HHSTATE variable & pass to hol_entry_help.
+ Remove LAST_ENTRY & SEP_GROUPS variables.
+ If any suplicate arguments were suppressed, print explanatory note.
+ (filter_doc): Replace PEST parameter with STATE.
+ (struct uparams): New type.
+ (uparams): New variable.
+ (struct uparam_name): New type.
+ (uparam_names): New variable.
+ (fill_in_uparams): New function.
+ (__argp_failure, __argp_error, __argp_state_help): Make STATE
+ parameter const.
+ * argp.h (argp_state_help, __argp_state_help, argp_usage,
+ __argp_usage, argp_error, __argp_error, argp_failure,
+ __argp_failure): Make STATE parameter const.
+ (ARGP_KEY_HELP_DUP_ARGS_NOTE): New macro.
+
+ * argp.h (argp_program_bug_address): Make const.
+
+Wed Feb 19 18:48:15 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-pv.c (argp_program_version): Make const.
+ * argp-ba.c (argp_program_bug_address): Make const.
+ * argp-ex2.c, argp-ex3.c, argp-ex4.c (argp_program_version,
+ argp_program_bug_address): Make const.
+
+ * argp-parse.c (argp_default_parser): Set STATE->name for OPT_PROGNAME.
+ (parser_init): Use the basename for PARSER->state.name.
+ * argp-help.c (__argp_error, __argp_failure, __argp_state_help):
+ Use PROGRAM_INVOCATION_SHORT_NAME instead of PROGRAM_INVOCATION_NAME.
+
+ * argp-parse.c (parser_init): Set PARSER->state.flags.
+ Make check whether PARSER has the prog name in argv[0] at the
+ proper place.
+
+Mon Feb 17 13:33:11 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-parse.c (parser_parse_next, parser_init): Remove __
+ prefixes from references to getopt functions variables (OPT*).
+ (argp_version_parser, parser_finalize): Use _ instead of gettext.
+ (gettext): Macro removed.
+ * argp-namefrob.h (__getopt_long, __getopt_long_only, __optind,
+ __optarg, __opterr, __optopt): Macros removed.
+
+Sun Feb 16 00:04:07 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-help.c (space): New function.
+ (usage_argful_short_opt): Use space.
+ (argp_doc): Deal with help filters. Add STATE param.
+ (argp_hol): Passin ARGP to make_hol, not ARGP->options.
+ (struct hol_entry): Add argp field.
+ (make_hol): Make this first parameter ARGP instead of OPT. Set
+ each entry's argp field.
+ (filter_doc): New function.
+ (print_header): Filter STR if necesary.
+ (hol_add_cluster): Add ARGP argument.
+ (argp_hol): Pass ARGP to hol_add_cluster.
+ (struct hol_cluster): Add argp field.
+ (hol_entry_help): Add STATE param. Do user filtering if necessary.
+ (struct pentry_state): Add state field.
+ (hol_help): Add STATE param.
+ (_help): Renamed from __argp_help. Add STATE argument, which pass
+ on appropiately.
+ (__argp_help): Now a wrapper that calls _help.
+ (__argp_state_help): Call _help instead of __argp_help.
+
+ * argp-parse.c (parser_init): Set PARSER->state.pstate.
+ (struct group): Add argp field.
+ (convert_options): Set it.
+ (__argp_input): New function.
+ * argp-namefrob.h (__argp_input): New macro.
+
+Sat Feb 15 22:00:42 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp.h (struct argp): Add help_filter field.
+ (struct argp_state): Add pstate field.
+
+Fri Feb 14 18:00:52 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-help.c, argp-parse.c [!_] (_): New macro.
+ [!_ && HAVE_LIBINTL_H] <libintl.h>: New include.
+ * argp-help.c (hol_entry_help, __argp_help, argp_args_usage, argp_doc,
+ usage_long_opt, arg, hol_entry_help): Call gettext in appropriate
+ places.
+ * argp-parse.c (parser_finalize, argp_version_parser): Likewise.
+
+ * argp-help.c: Incorporate gettext changes from drepper.
+
+Thu Feb 13 16:46:59 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-parse.c, argp-help.c, argp-fmtstream.c, argp-pvh.c,
+ argp-test.c, argp-fs-xinl.c, argp-xinl.c
+ [HAVE_CONFIG_H] <config.h>: New include.
+
+Wed Feb 12 00:35:21 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-fmtstream.c (_GNU_SOURCE): New macro.
+ <ctype.h>: New include.
+ [!isblank] (isblank): New macro.
+ * argp-fmtstream.h <ctype.h>: Include removed.
+
+ * argp-parse.c (parser_parse_next): Decrement PARSER->state.next
+ if we consumed an arg we didn't end up parsing.
+ Set ARG_EBADKEY ourselves in all cases.
+ (parser_parse_arg, parser_parse_opt): Get rid of ARG_EBADKEY param.
+
+ * argp-parse.c (__progname, __progname_full): Decls removed.
+ (argp_default_parser): Use PROGRAM_INVOCATION_NAME &
+ PROGRAM_INVOCATION_SHORT_NAME, not __PROGNAME_FULL & __PROGNAME.
+
+ * argp-help.c (__progname, __progname_full): Decls removed.
+ (__argp_failure, __argp_error, __argp_state_help): Use
+ PROGRAM_INVOCATION_NAME instead of __PROGNAME_FULL.
+ (__argp_error): Use STATE->name if it's available.
+ * argp-namefrob.h (__progname_full): Macro removed.
+
+ * argp.h (ARGP_KEY_END, ARGP_KEY_NO_ARGS, ARGP_KEY_INIT,
+ ARGP_KEY_SUCCESS, ARGP_KEY_ERROR): Change values.
+
+ * argp-help.c (make_hol): Initalize clusters field.
+ (argp_args_usage): Don't trash memory.
+
+Tue Feb 11 19:16:39 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-help.c (argp_args_levels): New function.
+ (argp_args_usage): Add LEVELS & ADVANCE arguments, and implement
+ multi-pattern output.
+ (__argp_help): Print multiple argument patterns if there are any.
+ * argp-test.c (args_doc): Add an alternative args pattern.
+ (parse_opt): Enforce it.
+
+ * argp-parse.c: Largely rewritten to clean up the code, avoid
+ using nested functions, and adapt namespace and locking in
+ preparation for moving into libc.
+
+ * argp-help.c (make_hol): Make static.
+ Increment default group for option headers.
+ (until_short): Return correct key.
+ (group_cmp): Put group 0 before other groups, not in the middle.
+ (hol_entry_cmp): Use __strcasecmp instead of strcasecmp.
+ (hol_entry_cmp, usage_argful_short_opt, usage_long_opt):
+ Don't use ?: operator.
+ (__argp_help): Renamed from argp_help.
+ (__argp_state_help): Renamed from argp_state_help.
+ (__argp_error): Renamed from argp_error.
+ (__argp_failure): Renamed from argp_failure.
+ [weak_alias] (argp_help, argp_state_help, argp_error, argp_failure):
+ New weak aliases.
+ (__progname, __progname_full): New declarations.
+ (__argp_state_help, __argp_error, __argp_failure): Use
+ __PROGNAME_FULL instead of PROGRAM_INVOCATION_NAME.
+ "argp-namefrob.h": New include.
+
+ * argp.h [HAVE_CONFIG_H] <config.h>: New include.
+ [__GNU_LIBRARY__] <sys/cdefs.h>: New include.
+ [!__const] (__const): New macro.
+ (struct argp_option, struct argp, struct argp_child, struct
+ argp_state): Use __const instead of const.
+ (__argp_parse, __argp_help, __argp_state_help, __argp_error,
+ __argp_usage, __argp_failure, __option_is_short, __option_is_end):
+ New declarations.
+ (argp_parse, argp_help, argp_state_help, argp_error,
+ argp_usage, argp_failure, _option_is_short, _option_is_end):
+ Use __P macro for function declarations.
+ (argp_usage, _option_is_end, _option_is_short): Inline definitions
+ replaced by __-prefixed versions, and protected by __OPTIMIZE__.
+ [__OPTIMIZE__ && !_LIBC] (__argp_usage, __argp_state_help,
+ __option_is_short, __option_is_end): Add redefs (& later undefs)
+ of __ versions of inline definitions so they define the correct
+ name for the environment (libc vs. non-libc).
+
+ * argp-fmtstream.c, argp-fmtstream.h, argp-fs-xinl.c, argp-xinl.c,
+ argp-namefrob.h, argp-test.c: New files.
+ * argp.c: File removed.
+ * Makefile (SRCS): Add argp-fmtstream.c, argp-fs-xinl.c, and argp-xinl.c.
+ Remove argp.c.
+ (installhdrs): Define explicitly.
+ (LCLHDRS): Define in terms of $(installhdrs) + others.
+ (CFLAGs): Add -DHAVE_LINEWRAP_H & -DHAVE_CTHREADS_H.
+
+Mon Feb 10 22:19:46 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-help.c (indent_to, arg, struct pentry_state, print_header,
+ comma, hol_entry_help, hol_help, usage_argful_short_opt,
+ usage_long_opt, hol_usage, argp_args_usage, argp_doc, argp_help):
+ Use argp_fmtstream_t & associated functions instead of stdio
+ streams.
+ "argp-fmtstream.h": New include.
+ <linewrap.h>: Include removd.
+
+ * argp-help.c (hol_append): Use memcpy instead of bcopy.
+ (argp_doc): Use strchr instead of index.
+ (make_hol): Make static.
+ * argp-parse.c (argp_default_parser): Use strrchr instead of rindex.
+ (argp_parse): Use strchr instead of index, memset instead of bzero.
+ * argp-parse2.c (parser_init, argp_parse): Use memset instead of bzero.
+ (argp_default_parser): Use strrchr instead of rindex.
+ (parser_parse_opt): Use strchr instead of index.
+
+Sun Feb 9 10:53:20 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp.h (ARGP_LONG_ONLY, ARGP_HELP_LONG_ONLY): New macros.
+ * argp-parse.c (argp_parse): Support ARGP_LONG_ONLY.
+ * argp-parse2.c (parser_parse_next): Likewise.
+ * argp-help.c (argp_state_help): Add ARGP_HELP_LONG_ONLY to FLAGS
+ if STATE has ARGP_LONG_ONLY set.
+
+ * argp-help.c (hol_entry_help): Correctly output odoc options.
+ Use un-nested helper functions, with state block.
+ (arg, print_header, comma): New functions (were nested in
+ hol_entry_help)
+ (struct pentry_state): New type.
+ (add_argless_short_opt, usage_argful_short_opt, usage_long_opt):
+ New functions (were nested in hol_usage).
+ (hol_usage): Use un-nested functions.
+ * argp-help.c (hol_entry_short_iterate, hol_entry_long_iterate):
+ Add COOKIE argument, also to signature of FUNC.
+ (until_short): Add COOKIE argument.
+
+Sat Feb 8 17:18:43 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp.h (OPTION_DOC): New macro.
+ * argp-parse.c (argp_parse): Don't parse OPTION_DOC options.
+ * argp-parse2.c (convert_options): Likewise.
+ * argp-help.c (odoc): New macro.
+ (oshort): Exclude options for which odoc is true.
+ (canon_doc_option): New function.
+ (hol_entry_cmp): Correctly place odoc options.
+
+ * argp-help.c (hol_entry_qcmp): New function.
+ (hol_sort): Remove cmp and use hol_entry_qcmp instead.
+ (until_short): New function, from old nested function func1 in
+ hol_entry_first_short. Only return short key when oshort is true.
+ (hol_entry_first_short): Remove func1 and use until_short insteadd.
+
+Tue Nov 12 19:22:58 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * idvec.h (idvec_set, idvec_set_ids): New functions.
+ * idvec.c (idvec_set, idvec_set_ids): Ditto.
+
+Tue Nov 5 21:16:10 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * idvec.h (idvec_setid): Doc fix.
+
+Thu Oct 24 15:15:27 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-help.c (hol_entry_help: comma): Only print cluster headers for
+ real clusters.
+ Emit a newline after cluster headers.
+
+Wed Oct 23 13:58:22 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-help.c (argp_args_usage, argp_doc): Use the new type of
+ argp child vector.
+
+Tue Oct 22 15:35:56 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-help.c (make_hol): Accept new CLUSTER argument,
+ and fill in the corresponding entry fields with it.
+ (hol_sort): Use hol_entry_cmp.
+ (hol_entry_cmp, group_cmp, hol_cluster_cmp, hol_cluster_base,
+ hol_add_cluster): New functions.
+ (hol_free): Free clusters.
+ (hol_append): Deal with clusters.
+ Always use hol_free to free MORE, and just mark it's entries as
+ invalid if we steal them.
+ (argp_hol): Add, and use the new CLUSTER argument.
+ Use the new type of argp child vector, and make clusters.
+ (argp_help): Pass new CLUSTER argument to argp_hol.
+ (hol_entry_help): Add gunk to print cluster headers.
+ * argp.h (struct argp_child): New type.
+ (struct argp): Change type of CHILDREN field to `struct argp_child *'.
+ * argp-parse.c (argp_parse): Convert to use the new type of argp
+ children vectors.
+
+Mon Oct 21 22:00:44 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * argp.h: Add extern inline protection.
+ * idvec.h: Likewise.
+ * maptime.h: Likewise.
+ * argp.c, idvec-funcs.c, maptime-funcs.c: New files.
+ * Makefile (SRCS): Add argp.c, idvec-funcs.c, and
+ maptime-funcs.c.
+
+Mon Oct 14 18:06:19 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-parse.c (argp_parse): Don't consume non-option arguments
+ that aren't recognized by any parser.
+ Allocate enough space for TOP_ARGP's parent list to include the
+ version parser.
+
+Thu Sep 19 17:48:14 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * fsysops.c (fsys_update): Renamed from fsys_remount.
+ Use --update, not --remount.
+
+Fri Aug 30 20:44:44 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-help.c (argp_help): Print documentation only according to
+ the ARGP_HELP_*_DOC bits in FLAGS.
+ Possibly print bug report address if ARGP_HELP_BUG_ADDR is set.
+ Replace FIRST by ANYTHING (sense inverted).
+ * argp.h (ARGP_HELP_PRE_DOC, ARGP_HELP_POST_DOC, ARGP_HELP_DOC,
+ ARGP_HELP_BUG_ADDR): New macros.
+ (ARGP_HELP_STD_HELP): Include ARGP_HELP_DOC & ARGP_HELP_BUG_ADDR.
+ (argp_program_bug_address): New declaration.
+ (ARGP_HELP_EXIT_ERR, ARGP_HELP_EXIT_OK): Values changed.
+ * Makefile (SRCS): Add argp-ba.c.
+
+Tue Aug 20 17:12:42 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-help.c (argp_doc): Add FIRST_ONLY argument.
+ Don't output a blank line for empty post-docs.
+ (argp_help): Use it. Move first call to argp_doc after newline.
+
+Mon Aug 19 14:45:30 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-help.c (argp_help): Add note about --usage to `Try...' msg.
+ Supply new args to argp_doc, and additional call before arg help.
+ (argp_doc): Add the POST and PRE_BLANK arguments, & return val.
+
+Wed Jul 31 15:24:09 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * wire.c (_start): No longer declared as weak, now that everything
+ is getting recompiled anyway.
+
+Fri Jul 26 20:57:53 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * timefmt.c (fmt_past_time): Always use WIDTH+1 as strftime's limit.
+
+Thu Jul 25 23:10:35 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * timefmt.c (fmt_past_time): Terminate SEPS.
+
+ * argp-help.c (hol_entry_help): Never return without restoring margins.
+
+Mon Jul 22 23:41:38 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * timefmt.c (fmt_past_time): Try several separators when
+ concatenating dates & times.
+
+Fri Jul 19 17:23:18 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-help.c (hol_usage): Allocate enough space in
+ SHORT_NO_ARG_OPTS for the '\0' terminator.
+
+Tue Jul 16 00:24:18 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-help.c (argp_help): Set the lmargin after printing the
+ start of the usage message, so that it won't get indented.
+
+Wed Jul 10 12:16:57 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-parse.c (argp_version_options, argp_version_parser): Use an
+ uppercase 'V' for short version option.
+
+ * argp-help.c (argp_help): "OPTIONS..." -> "OPTION...".
+
+Sat Jul 6 16:17:53 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-parse.c (argp_version_parser): Output ARGP_PROGRAM_VERSION
+ to STATE->out_stream, not stdout. Supply that stream and STATE to
+ ARGP_PROGRAM_VERSION_HOOK.
+ * argp.h (argp_program_version_hook): Add argument types.
+ * argp-pv.c (argp_program_version): Doc updated.
+ * argp-pvh.c (argp_program_version_hook): Type & doc updated.
+ "argp.h": New include.
+
+Fri Jul 5 17:13:12 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * timefmt.c (fmt_past_time): Get rid of extraneous `f' in fmt string.
+
+Thu Jun 27 17:09:30 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-parse.c (argp_parse): Zero the CHILD_INPUTS vector.
+
+Fri Jun 21 17:15:31 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-parse.c (argp_parse): Use group_parse instead of calling
+ group parser directly for long options.
+
+Wed Jun 19 13:11:15 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * fsysops.c: New file.
+ * Makefile (SRCS): Add fsysops.c.
+
+Tue Jun 18 21:09:52 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-help.c (argp_failure): If FMT is 0, don't print `: MSG'.
+
+Sun Jun 16 19:25:10 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * Makefile (SRCS): Remove line.c.
+ (LCLHDRS): Remove line.h.
+
+ * argp-help.c (argp_help, argp_state_help, argp_error, argp_failure):
+ Handle null streams.
+
+ * argp.h (struct argp_state): Add NAME, ERR_STREAM, & OUT_STREAM
+ fields.
+ (argp_failure): New declaration.
+ (ARGP_NO_HELP, ARGP_NO_EXIT): Fix values (were hex, but with
+ decimal value!).
+ (argp_help): Add NAME argument.
+ * argp-parse.c (argp_default_parser): Output to STATE->out_stream.
+ (argp_parse): Initialize new fields in STATE.
+ Output errors to STATE.err_stream. Handle null streams.
+
+ * argp-help.c (argp_help): Add and use NAME argument.
+ (argp_error): Use STATE->err_stream instead of STDERR.
+ (argp_state_help): Supply NAME argument to argp_help.
+ (argp_failure): New function.
+
+Thu May 30 18:10:35 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-help.c (indent_to): Terminate.
+
+Tue May 28 18:05:40 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * timefmt.c (fmt_seconds): Don't print two decimal points.
+
+Wed May 22 00:11:24 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-parse.c (argp_default_parser): Break after --HANG.
+
+ * argp-help.c (hol_usage): Prefix each option desc with a space.
+ Do manual wrapping of descs with an embedded space.
+ Don't set wrap margin (done elsewhere now).
+ (argp_args_usage): Do manual line wrapping because of embedded spaces.
+ (argp_help): Set wrap & left margins when printing usage.
+
+ * argp-parse.c (argp_parse): Only print a `Try...' message if the
+ error was a parsing error.
+
+Tue May 14 21:59:43 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * timefmt.c (add_field): Correctly decrement *SECS by amount printed.
+
+ * timefmt.c (fmt_named_interval): Use fraction digit in more cases.
+ Always pick the last suffix if we can't find any that fits.
+ Use new tv_ functions.
+ (tv_is_zero, tv_is_ge): New functions.
+
+Fri May 10 23:17:38 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp.h (ARGP_ERR_UNKNOWN): New define.
+ * argp-parse.c (EBADKEY): New define.
+ (argp_default_parser, argp_version_parser, argp_parse): Use
+ EBADKEY instead of EINVAL. Turn any EBADKEY that makes it to the
+ end back into EINVAL.
+
+Thu May 9 11:30:47 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * maptime.c (maptime_map): Use new file_get_storage_info interface.
+
+ * argp-help.c (argp_help): Just assign STREAM instead of using 2 vars.
+
+Thu May 9 11:00:52 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * exec-reauth.c (exec_reauth): Use new args to
+ auth_user_authenticate.
+
+ * timefmt.c (fmt_past_time): Cast arg to localtime appropriately.
+
+ * argp-help.c (argp_args_usage): add_usage_item -> fprintf.
+ (argp_help): Don't shadow arg; change parm STREAM to be STREAMARG
+ and adjust initialization of STREAM variable to use the renamed
+ parm.
+
+Tue May 7 14:58:48 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * timefmt.c (fmt_past_time): Suppress leading noise in some formats.
+
+ * argp-help.c (hol_usage): Set the wmargin, not the lmargin.
+ (hol_help): Set the wmargin as well as the lmargin.
+ * argp-help.c <linewrap.h>: New include.
+ (lmargin): Function deleted.
+ (hol_entry_help, hol_usage): Use line_wrap_set_lmargin instead.
+
+Mon May 6 12:46:16 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-help.c <line.h>: Include removed.
+ (lmargin, indent_to): New functions.
+ (argp_usage_arg): Function removed.
+ (hol_entry_help, hol_help, hol_usage, argp_args_usage, argp_doc,
+ argp_help): Use stdio streams and line_wrap_ functions instead of
+ line_ functions.
+
+Sat May 4 05:32:28 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
+
+ * rwlock.h: Moved to ../libthreads.
+ * Makefile (LCLHDRS): Remove rwlock.h.
+
+Fri May 3 18:10:41 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
+
+ * path-lookup.c: File removed.
+ * Makefile (SRCS): Remove path-lookup.c.
+
+ * argz.c, argz.h, envz.c, envz.h: Files removed.
+ * Makefile (SRCS): Remove argz.c, envz.c.
+ (LCLHDRS): Remove argz.h, envz.h.
+
+Thu May 2 00:31:32 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-parse.c (_argp_hang): New variable.
+ (OPT_HANG): New macro.
+ (argp_default_options, argp_default_parser): Add hidden --HANG option.
+ (argp_default_parser): New function.
+ (argp_version_options, argp_version_argp): New variables.
+ (argp_parse): Use ARGP_VERSION_ARGP when appropiate.
+ * argp.h (argp_program_version, argp_program_version_hook): New decls.
+ * Makefile (SRCS): Add argp-pv.c & argp-pvh.c.
+ * argp-pv.c, argp-pvh.c: New files.
+
+Tue Apr 30 20:25:12 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * timefmt.c (fmt_past_time): New function.
+ (fmt_minutes, fmt_seconds): New args, rewrite.
+ (add_field): New function.
+ (fmt_frac_value, append_fraction): Functions removed.
+ * timefmt.h (fmt_past_time): New declaration.
+ (fmt_minutes, fmt_seconds): Update.
+
+ * argp-parse.c (argp_parse): Work with ARGP == 0.
+
+Mon Apr 29 15:34:00 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * cacheq.c, cacheq.h: New files.
+ * Makefile (SRCS): Add cacheq.c.
+ (LCLHDRS): Add cacheq.h.
+
+Thu Apr 25 00:09:48 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
+
+ * idvec.c (idvec_free_contents): New function.
+ * idvec.h (idvec_free_contents): Declare it.
+
+Thu Apr 11 15:23:15 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * wire.c (wire_segment_internal): Cast values nicely in `poke'
+ loop.
+
+Wed Apr 3 12:57:39 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp.h (argp_parse): Change HOOK argument to INPUT.
+ (struct argp_state): Rename HOOK & CHILD_HOOKS to INPUT & CHILD_INPUTS;
+ add HOOK field again.
+ * argp-parse.c (argp_parse): Change HOOK argument to INPUT.
+ Don't propagate back return values when we're done.
+ (struct group): Rename HOOK & CHILD_HOOKS to INPUT & CHILD_INPUTS;
+ add HOOK field again.
+ (group_parse): Restore and save value of GROUP's hook field into
+ STATE around calling the parser. Don't save changed value of INPUT.
+
+Tue Apr 2 18:25:51 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * lcm.c: New file.
+ * Makefile (SRCS): Add lcm.c.
+
+Thu Mar 28 19:06:12 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * portinfo.c, xportinfo.c, portinfo.h: New files.
+ * portxlate.c, portxlate.h: New files.
+ * Makefile (LCLHDRS): Add portinfo.h, portxlate.h.
+ (SRCS): Add portinfo.c, xportinfo.c, portxlate.c.
+
+Tue Mar 26 17:43:51 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * wire.c: Add a weak reference to _start, so we don't have to
+ compile all users of this library.
+
+Mon Mar 25 18:38:23 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * timefmt.c (fmt_named_interval): Rationalize WIDTH.
+
+Mon Mar 25 16:11:49 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * wire.h, wire.c: New files.
+ * Makefile (SRCS): Add wire.c.
+ (LCLHDRS): Add wire.h.
+
+Mon Mar 25 16:06:40 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * envz.c (envz_merge): NEW_LEN is a size, not a char.
+
+Mon Mar 18 14:09:18 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp.h (struct argp_state): Add HOOK and CHILD_HOOKS fields.
+ Rename the PARENTS field to be CHILDREN (the most common use is
+ initialization, so this change shouldn't have much effect).
+ (ARGP_KEY_BEGIN, ARGP_KEY_ERROR): New macros.
+ * argp-parse.c (struct group): Add PARENT, PARENT_INDEX, HOOK, and
+ CHILD_HOOKS fields.
+ (argp_parse): Add HOOK argument.
+ Implement passing hook values to parsers, and propagating them
+ between parents and children.
+ * argp-help.c (argp_doc, argp_args_usage, argp_hol): Rename
+ PARENTS field to CHILDREN.
+
+ * argp-help.c (argp_error): Take an argp_state instead of an argp,
+ and only doing anything if ARGP_NO_ERRS isn't set in it.
+ (argp_state_help): New function.
+ (argp_help): Don't interpret exiting options anymore.
+ * argp-parse.c (argp_default_options): Add --usage option.
+ (argp_default_parser): Use argp_state_help, so we don't need to
+ screw with exit options anymore.
+ Add usage option.
+ (argp_parse): When printing `too many arguments', test
+ ARGP_NO_ERRS instead of ARGP_NO_HELP.
+ * argp.h (argp_state_help): New function.
+ (argp_usage, argp_error): Change arguments.
+
+Fri Mar 1 18:59:40 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-help.c (hol_entry_help): Don't print extraneous blank lines.
+
+Wed Feb 28 18:44:38 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-parse.c (argp_parse): Print an error message if appropiate
+ when we know there are too many arguments.
+
+ * argp-help.c (hol_entry_help): Handle null group headers nicely.
+
+Wed Feb 28 16:09:27 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * maptime.c (maptime_map): mapped_time_value arg is volatile data.
+ * maptime.h (maptime_map): Likewise.
+
+Sat Feb 17 21:34:18 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * shared-dom.c, localhost.c: New file.
+ * Makefile (SRCS): Add shared-dom.c and localhost.c.
+
+Fri Feb 16 15:54:22 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * maptime.c, maptime.h: New files.
+ * Makefile (SRCS, LCLHDRS): Add maptime.c and maptime.h respectively.
+
+ * timefmt.c (fmt_named_interval): Correct backwards comparison.
+
+Thu Feb 15 15:18:34 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * canon-host.c: New file.
+ * Makefile (SRCS): Add canon-host.c.
+
+ * argp-parse.c (argp_parse): Correctly deal with errors from
+ getopt, and allow the user to use '?' as a short option.
+ (KEY_ERR): New macro.
+ (argp_default_options, argp_default_parser): Use -? as the short
+ option for --help.
+
+Wed Feb 14 14:33:48 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-parse.c (argp_parse): Make things a bit more readable by
+ using the TRY_GETOPT variable in place of opt == EOF.
+ Use KEY_END, KEY_ARG, and QUOTE.
+ Clear STATE.quoted if STATE.next has been moved back before it.
+ (KEY_END): New macro, in place of EOF.
+ (KEY_ARG, QUOTE): New macros.
+
+Mon Feb 12 15:08:33 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-parse.c (argp_parse): Don't parse args in order by
+ default. Honor ARGP_NO_ARGS.
+ Deal correctly when the user turns a non-option arg into an option
+ in re-ordering mode.
+ * argp.h (struct argp_state): Add `quoted' field.
+
+Thu Feb 8 19:35:49 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-parse.c (argp_parse): When a non-option arg fails to be
+ parsed with EINVAL, set ARG_EINVAL true, and leave ERR as is until
+ just before we return.
+ Put process_arg() in the right scope.
+
+Wed Feb 7 23:08:33 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-parse.c (argp_parse): Deal with getopt returning EOF early
+ because of `--'.
+
+ * argp-parse.c (argp_parse): Make STATE.arg_num per-group.
+ (struct group): Renamed process_arg field to args_processed (a count).
+
+Mon Feb 5 13:39:57 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp.h (struct argp_state): Add ARG_NUM field.
+ * argp-parse.c (argp_parse): Implement the ARG_NUM field.
+
+ * argp.h (struct argp, struct argp_state, argp_parse, argp_help,
+ argp_usage, argp_error, _option_is_short, _option_is_end): Add `const'
+ where appropriate.
+ * argp-parse.c (argp_default_options, argp_default_argp,
+ argp_parse, find_long_option): Likewise.
+ * argp-help.c (struct hol_entry, make_hol,
+ hol_entry_short_iterate, hol_entry_long_iterate,
+ hol_entry_first_short, hol_entry_first_long, hol_find_entry,
+ hol_sort, hol_entry_help, argp_hol, argp_args_usage, argp_doc,
+ argp_help, argp_error): Likewise.
+ * line.h (line_write, line_fill, line_puts): Likewise.
+ * line.c (line_write, line_fill): Likewise.
+
+Sat Feb 3 02:00:06 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * idvec.c (idvec_merge_ids): Correctly add all IDS, even if some
+ duplicates are avoided.
+
+Tue Jan 23 15:02:03 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-help.c (hol_entry_help): Correctly print group headers, and
+ precede them with a blank line.
+ (hol_set_group): Renamed from hol_set_sort_class.
+ (argp_help): Use hol_set_group instead of hol_set_sort_class.
+ (struct hol_entry, make_hol, hol_sort, hol_set_group): Rename the
+ `set_class' field to be `group'.
+ (hol_help, hol_entry_help): After a group header has been printed,
+ separate subsequent groups with a blank line.
+
+Mon Jan 15 11:01:15 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * path-lookup.c (hurd_file_name_path_lookup, file_name_path_lookup):
+ Add PREFIXED_NAME (return) argument.
+ (file_name_path_scan): New function.
+ (hurd_file_name_path_lookup): Use file_name_path_scan().
+
+Tue Jan 2 01:24:57 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-parse.c (argp_default_options, argp_default_parser): Add
+ --program-name (hidden) option.
+ (OPT_PROGNAME): New macro.
+
+ * idvec.c (idvec_merge_ids): Preserve duplicates internal to IDS.
+ (idvec_ensure): Alloc NUM ids, not NUM chars!
+ (idvec_remove): Correctly copy ids when deleting.
+ * idvec.h (idvec_merge, idvec_delete): New declarations.
+
+ * idvec-auth.c (idvec_merge_auth): Fix various small typos.
+
+ * argz.c (argz_delete): If the result is empty, free it.
+
+ * exec-reauth.c (exec_reauth): Doc fix.
+
+ * argz.h (argz_delete): Renamed from argz_remove.
+ * argz.c (argz_delete): Ditto.
+ (argz_insert): Deref ARGZ where necessary.
+ * envz.c (envz_merge): Rename argz_remove to argz_delete.
+
+Mon Jan 1 17:48:34 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * idvec.c (idvec_remove, idvec_insert_only): New functions.
+ (idvec_setid): Use idvec_insert_only() instead of idvec_insert_new().
+ * idvec.h (idvec_remove, idvec_insert_only): New declarations.
+
+ * Makefile (SRCS): Add exec-reauth.c.
+
+ * idvec.c (idvec_free_wrapper, idvec_free, idvec_ensure,
+ idvec_grow, idvec_tail_contains, idvec_add_new, idvec_insert_new,
+ idvec_merge_ids, idvec_setid): New functions.
+ (idvec_insert): Rewritten to use idvec_grow().
+ * idvec-auth.c (idvec_merge_auth): New function.
+ * idvec.h (idvec_free_wrapper, idvec_free, idvec_ensure,
+ idvec_grow, idvec_tail_contains, idvec_add_new, idvec_insert_new,
+ idvec_merge_ids, idvec_setid, idvec_merge_auth): New declarations.
+ * Makefile (SRCS): Added idvec-auth.c.
+
+Fri Dec 29 12:15:00 1995 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-parse.c (_argp_unlock_xxx): New function.
+
+Thu Dec 21 10:18:04 1995 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * idvec.h (struct idvec): Renamed from struct ivec. `ints' field
+ renamed to `ids'.
+ (make_idvec, idvec_insert, idvec_add, idvec_contains):
+ All renamed from the corresponding `ivec' declaration, and types,
+ variable names, etc, changed accordingly.
+ * idvec.c (make_idvec, idvec_insert, idvec_add, idvec_contains):
+ All renamed from the corresponding `ivec' routine, and types,
+ variable names, etc, changed accordingly.
+ * Makefile (SRCS): Remove options.c. Rename ivec.c to idvec.c.
+ (LCLHDRS): Remove options.h. Rename ivec.h to idvec.h.
+
+Wed Dec 20 13:05:00 1995 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argz.c (argz_insert): Instead of an integer position N, take a
+ pointer BEFORE into ARGZ to insert before.
+ * argz.h (argz_insert): Instead of an integer position N, take a
+ pointer BEFORE into ARGZ to insert before.
+ (argz_next): New inline function.
+
+Tue Dec 19 13:52:52 1995 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp.h (struct argp_option): Add the GROUP field. Twiddle doc.
+ (_option_is_end): Be more pessimistic about what constitutes `the end'.
+ * argp-help.c (make_hol): Use the new GROUP field in struct
+ argp_option to initialize sort_classes.
+ (HEADER_COL): New macro.
+ (hol_entry_help): Deal with group headers.
+ * argp-parse.c (argp_default_options): Put --help in group -1.
+
+Sun Dec 17 00:18:58 1995 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * ivec.c: New file.
+ * ivec.h: New file.
+ * Makefile (LCLHDRS): Add ivec.h.
+ (SRCS): Add ivec.c.
+
+Sat Dec 16 17:42:27 1995 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * termsize.c (deduce_term_size): New function, new file.
+ * Makefile (SRCS): Add termsize.c.
+
+ * argz.c (argz_insert): New function.
+ (argz_remove, argz_append, argz_add): New functions, were in envz.c.
+ * argz.h (argz_insert): New declaration.
+
+Thu Dec 14 18:04:48 1995 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argz.h (argz_append, argz_add, argz_remove): New functions.
+
+Wed Dec 13 14:28:12 1995 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * envz.c: New file.
+ * envz.h: New file.
+ * Makefile (SRCS): Add envz.c.
+ (LCLHDRS): Add envz.h
+
+Wed Dec 6 15:05:43 1995 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp.h (struct argp_state): Rename the INDEX field to be NEXT.
+ * argp-parse.c (argp_parse): Change uses of that field.
+
+ * argz.c (argz_stringify): Add the SEP argument.
+ * argz.h (argz_stringify): Ditto.
+
+Tue Dec 5 18:38:40 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
+
+ * Makefile (SRCS, LCLHDRS): Removed error.c and error.h.
+ (CPPFLAGS-error.c): Variable removed.
+ * error.c, error.h: Files removed.
+
+Thu Oct 19 18:39:59 1995 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp.h (argp_usage, argp_error): New declarations.
+ (argp_usage): New inline function.
+ * argp-help.c (argp_error): New function.
+
+Fri Oct 13 19:28:28 1995 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp.h (ARGP_HELP_STD_ERR): Doesn't print a usage message.
+ (ARGP_HELP_STD_USAGE): ... whereas this does.
+
+Thu Oct 12 15:57:18 1995 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-parse.c (argp_parse): Correctly mark short options as optional.
+ (argp_parse): If an option alias doesn't have a key, use the real key.
+
+Wed Oct 11 13:54:18 1995 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp-help.c (hol_find_entry): Don't increment ENTRY prematurely.
+
+ * argp-parse.c (argp_parse): Update STATE.argp when adding a
+ wrapper to implement the --help option.
+ In general, use the version of variables that are in STATE.
+ Update STATE.index in the case where getopt returns EOF.
+ (argp_parse): Correctly translate options.
+
+ * line.c (line_write): New function.
+ (line_puts): Function deleted.
+ (line_fill): Use line_write instead of line_printf.
+ * line.h (line_write): New declaration.
+ (line_puts): Rewrite in terms of line_write.
+
+ * argp-help.c (hol_entry_help): Print the right documentation
+ string for each entry.
+
+ * argp-parse.c (argp_default_parser, argp_parse): Rename uses of
+ argp_usage* to argp_help*.
+
+ * argp-help.c (argp_help): Renamed from argp_usage.
+ * argp.h (ARGP_HELP_*, argp_help): Renamed from ARGP_USAGE_* &c.
+
+ * argp.h (ARGP_USAGE_STD_HELP): Use ARGP_USAGE_SHORT_USAGE instead
+ of ARGP_USAGE_USAGE.
+
+ * argp-help.c (make_hol): Deal with a null value of OPT. If there
+ are no entries, don't define the ENTRIES or SHORT_OPTIONS fields.
+ (hol_free): Don't free ENTRIES or SHORT_OPTIONS unless there are any.
+ (hol_sort): Don't sort unless there are some entries.
+ (hol_usage): Don't do anything unless there are some entries.
+ (hol_sort): Sort int he correct order.
+ (argp_usage): Add the ARGP_USAGE_SHORT_USAGE case.
+
+ * argp-parse.c (argp_parse): Deal with null parser or option fields.
+ If an argp has neither a parser or any options, don't put it in GROUPS.
+ Use comparison with EGROUP, rather than testing the parser field,
+ the end test for iteration over GROUPS.
+
+ * argp-help.c (hol_append): Implement.
+
+ * argp-parse.c (argp_parse): Pass in the right value for GROUPS to
+ convert_options.
+
+ * Makefile (SRCS): Add argp-parse.c, argp-help.c, and line.c
+ (LCLHDRS): Add line.h and argp.h.
+
+Tue Oct 10 17:58:14 1995 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * argp.h: Doc fixes.
+
+ * argp.h: (ARGP_KEY_NO_ARGS): New macro.
+ * argp-parse.c (argp_parse): Add support for ARGP_KEY_NO_ARGS.
+ Put all the group attributes into structures which get stored in
+ the GROUPS array, rather than having a separate array for each.
+
+Sat Oct 7 03:32:51 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
+
+ * rwlock.h: Protect against multiple inclusion.
+ Include cthreads.h and assert.h.
+
+Wed Sep 27 17:37:08 1995 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * options.c (options_parse): Use 0 as the tag for non-option args.
+ * options.h: Ditto.
+
+Sat Sep 23 14:15:01 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
+
+ * rwlock.h (RWLOCK_INITIALIZER): New macro.
+
+Sat Sep 16 13:40:22 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
+
+ * Makefile (lndist, $(srcdir)/hurd-snap/$(dir)/error.[ch]):
+ Targets removed.
+
+Thu Aug 24 11:49:13 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
+
+ * options.c: Include "options.h" instead of <options.h>.
diff --git a/libshouldbeinlibc/Makefile b/libshouldbeinlibc/Makefile
new file mode 100644
index 00000000..562ebd82
--- /dev/null
+++ b/libshouldbeinlibc/Makefile
@@ -0,0 +1,40 @@
+# Makefile for libshouldbeinlibc
+#
+# Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
+#
+# 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.
+
+dir := libshouldbeinlibc
+makemode := library
+
+libname = libshouldbeinlibc
+SRCS = termsize.c timefmt.c exec-reauth.c maptime-funcs.c \
+ canon-host.c maptime.c shared-dom.c localhost.c wire.c portinfo.c \
+ xportinfo.c portxlate.c lcm.c cacheq.c fsysops.c \
+ idvec.c idvec-auth.c idvec-funcs.c \
+ idvec-impgids.c idvec-verify.c idvec-rep.c \
+ ugids.c ugids-argp.c ugids-rep.c ugids-verify.c ugids-subtract.c \
+ ugids-auth.c ugids-xinl.c ugids-merge.c ugids-imply.c ugids-posix.c \
+ ugids-verify-auth.c
+installhdrs = idvec.h timefmt.h maptime.h \
+ wire.h portinfo.h portxlate.h cacheq.h ugids.h
+LCLHDRS = $(installhdrs)
+installhdrsubdir = .
+
+CFLAGS += -DHAVE_LINEWRAP_H -DHAVE_CTHREADS_H
+
+OBJS = $(SRCS:.c=.o)
+
+include ../Makeconf
diff --git a/libshouldbeinlibc/cacheq.c b/libshouldbeinlibc/cacheq.c
new file mode 100644
index 00000000..eb41c6e9
--- /dev/null
+++ b/libshouldbeinlibc/cacheq.c
@@ -0,0 +1,143 @@
+/* Helper functions for maintaining a fixed-size lru-ordered queue
+
+ Copyright (C) 1996, 1998 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 <string.h>
+#include <malloc.h>
+
+#include "cacheq.h"
+
+/* Move ENTRY to the most-recently-used end of CACHEQ. */
+void
+cacheq_make_mru (struct cacheq *cq, void *entry)
+{
+ struct cacheq_hdr *h = entry;
+
+ if (h != cq->mru)
+ {
+ /* First remove it. We known H->prev isn't 0 because H wasn't
+ previously == MRU. */
+ ((struct cacheq_hdr *)h->prev)->next = h->next;
+ if (h->next)
+ ((struct cacheq_hdr *)h->next)->prev = h->prev;
+ else
+ cq->lru = h->prev;
+
+ /* Now make it MRU. */
+ h->next = cq->mru;
+ h->prev = 0;
+ ((struct cacheq_hdr *)cq->mru)->prev = h;
+ cq->mru = h;
+ }
+}
+
+/* Move ENTRY to the least-recently-used end of CACHEQ. */
+void
+cacheq_make_lru (struct cacheq *cq, void *entry)
+{
+ struct cacheq_hdr *h = entry;
+
+ if (h != cq->lru)
+ {
+ /* First remove it. We known H->next isn't 0 because H wasn't
+ previously == LRU. */
+ ((struct cacheq_hdr *)h->next)->prev = h->prev;
+ if (h->prev)
+ ((struct cacheq_hdr *)h->prev)->next = h->next;
+ else
+ cq->mru = h->next;
+
+ /* Now make it LRU. */
+ h->prev = cq->lru;
+ h->next = 0;
+ ((struct cacheq_hdr *)cq->lru)->next = h;
+ cq->lru = h;
+ }
+}
+
+/* Change CQ's size to be LENGTH entries. */
+error_t
+cacheq_set_length (struct cacheq *cq, int length)
+{
+ if (length != cq->length)
+ {
+ size_t esz = cq->entry_size;
+ void *new_entries = malloc (esz * length);
+ /* Source entries. */
+ struct cacheq_hdr *fh = cq->mru;
+ /* Destination entries (and limit). */
+ struct cacheq_hdr *th = new_entries;
+ struct cacheq_hdr *end = new_entries + esz * (length - 1);
+ struct cacheq_hdr *prev_th = 0;
+
+ if (! new_entries)
+ return ENOMEM;
+
+ while (fh || th)
+ {
+ struct cacheq_hdr *next_th =
+ (!th || th >= end) ? 0 : (void *)th + esz;
+
+ if (fh && th)
+ bcopy (fh, th, esz); /* Copy the bits in a moved entry. */
+ else if (th)
+ bzero (th, esz); /* Zero the bits in a new entry. */
+
+ if (th)
+ /* Fixup headers. */
+ {
+ th->prev = prev_th;
+ th->next = next_th;
+ }
+
+ /* Call user hooks as appropiate. */
+ if (fh && th)
+ {
+ if (cq->move_entry)
+ (*cq->move_entry) (fh, th);
+ }
+ else if (th)
+ {
+ if (cq->init_entry)
+ (*cq->init_entry) (th);
+ }
+ else
+ {
+ if (cq->finalize_entry)
+ (*cq->finalize_entry) (fh);
+ }
+
+ if (fh)
+ fh = fh->next;
+ if (th)
+ {
+ prev_th = th;
+ th = next_th;
+ }
+ }
+
+ free (cq->entries);
+ cq->entries = new_entries;
+ cq->mru = new_entries;
+ cq->lru = prev_th;
+ cq->length = length;
+ }
+
+ return 0;
+}
diff --git a/libshouldbeinlibc/cacheq.h b/libshouldbeinlibc/cacheq.h
new file mode 100644
index 00000000..a221a7a7
--- /dev/null
+++ b/libshouldbeinlibc/cacheq.h
@@ -0,0 +1,87 @@
+/* Helper functions for maintaining a fixed-size lru-ordered queue
+
+ Copyright (C) 1996 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 __CACHEQ_H__
+#define __CACHEQ_H__
+
+#include <stddef.h>
+#include <errno.h>
+
+/* This header occurs at the start of every cacheq entry. */
+struct cacheq_hdr
+{
+ /* Next and prev entries in the cache, linked in LRU order. These are of
+ type `void *' so that it's conveient to iterate through the list using a
+ variable pointing to a structure that contains the header, by using
+ something like `VAR = VAR->hdr.next'. */
+ void *next, *prev;
+};
+
+/* A cacheq. Note that this structure is laid out to allow convenient use as
+ static initialized data. */
+struct cacheq
+{
+ /* The size of each entry, including its cacheq_hdr. */
+ size_t entry_size;
+
+ /* If non-0, then when making new entries (for instance, when the cacheq is
+ initialized, or when its size is increased), this function is called on
+ each new entry (with it's header already initialized). If this function
+ isn't defined, then each entry is simply zeroed. */
+ void (*init_entry) (void *entry);
+
+ /* When an entry is moved from one place in memory to another (for
+ instance, changing the size of the cache, new storage is used), this is
+ called for each entry, with FROM and TO the old and new locations of the
+ entry (and TO contains a bitwise copy of FROM). This is often useful
+ when the entry points to something that contains a backpointer to it. */
+ void (*move_entry) (void *from, void *to);
+
+ /* When entries are removed for some reason (for instance, when reducing
+ the size of the cacheq), this function is called on each. */
+ void (*finalize_entry) (void *entry);
+
+ /* The number of entries in the cache. This number is fixed. */
+ int length;
+
+ /* A buffer holding malloc'd memory for all the entries -- NUM_ENTRIES
+ entries of size ENTRY_SIZE. */
+ void *entries;
+
+ /* The least, and most, recently used entries in the cache. These point to
+ either end of a linked list composed of all the elements of the cache.
+ This list will always be the same length -- if an element is `removed',
+ its entry is simply marked inactive, and moved to the LRU end of the list
+ so it will be reused first. These pointers are of type `void *' so they
+ can be conveniently used by client code (see comment in struct
+ cacheq_hdr). */
+ void *lru, *mru;
+};
+
+/* Move ENTRY to the most-recently-used end of CACHEQ. */
+void cacheq_make_mru (struct cacheq *cq, void *entry);
+
+/* Move ENTRY to the least-recently-used end of CACHEQ. */
+void cacheq_make_lru (struct cacheq *cq, void *entry);
+
+/* Change CQ's size to be LENGTH entries. */
+error_t cacheq_set_length (struct cacheq *cq, int length);
+
+#endif /* __CACHEQ_H__ */
diff --git a/libshouldbeinlibc/canon-host.c b/libshouldbeinlibc/canon-host.c
new file mode 100644
index 00000000..ea6c7195
--- /dev/null
+++ b/libshouldbeinlibc/canon-host.c
@@ -0,0 +1,58 @@
+/* Host name canonicalization
+
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ [This file is from sh-utils/lib; maybe something can be done to share them.]
+
+ 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 <unistd.h>
+#include <string.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+/* Returns the canonical hostname associated with HOST (allocated in a static
+ buffer), or 0 if it can't be determined. */
+char *
+canon_host (char *host)
+{
+ struct hostent *he = gethostbyname (host);
+
+ if (he)
+ {
+ char *addr = 0;
+
+ /* Try and get an ascii version of the numeric host address. */
+ switch (he->h_addrtype)
+ {
+ case AF_INET:
+ addr = inet_ntoa (*(struct in_addr *)he->h_addr);
+ break;
+ }
+
+ if (addr && strcmp (he->h_name, addr) == 0)
+ /* gethostbyname() cheated! Lookup the host name via the address
+ this time to get the actual host name. */
+ he = gethostbyaddr (he->h_addr, he->h_length, he->h_addrtype);
+
+ if (he)
+ return he->h_name;
+ }
+
+ return 0;
+}
diff --git a/libshouldbeinlibc/exec-reauth.c b/libshouldbeinlibc/exec-reauth.c
new file mode 100644
index 00000000..1ddfcefa
--- /dev/null
+++ b/libshouldbeinlibc/exec-reauth.c
@@ -0,0 +1,106 @@
+/* Re-authentication in preparation for an exec
+
+ Copyright (C) 1995, 96, 98 Free Software Foundation, Inc.
+
+ Stolen by Miles Bader <miles@gnu.ai.mit.edu>, but really
+ written by Michael I. Bushnell p/BSG <mib@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 <mach.h>
+#include <hurd/auth.h>
+#include <hurd/io.h>
+#include <hurd/process.h>
+
+/* Re-authenticates the ports in PORTS and FDS appropriately (replacing
+ PORTS[INIT_PORT_AUTH] with AUTH) for a following exec using the auth port
+ AUTH. Each replaced port has a reference consumed; if an error is
+ returned, then PORTS and FDS may contain a mixture of old and new ports,
+ however AUTH will only be placed in PORTS upon success. If SECURE is
+ true, then it is assumed the exec will use EXEC_SECURE, and certain ports
+ may be replaced by MACH_PORT_NULL, with the expectation that exec will
+ fill these in itself; if all ports should be re-authenticated, use 0 for
+ this argument, regardless of whether EXEC_SECURE will be used. If
+ MUST_REAUTH is true, then any failure to re-authenticate a port will
+ result in the function return the error, otherwise, such failures are
+ silently ignored. */
+error_t
+exec_reauth (auth_t auth, int secure, int must_reauth,
+ mach_port_t *ports, unsigned num_ports,
+ mach_port_t *fds, unsigned num_fds)
+{
+ int i;
+ error_t err = 0;
+
+ error_t reauth (mach_port_t *port, int isproc)
+ {
+ if (*port != MACH_PORT_NULL)
+ {
+ mach_port_t newport;
+ mach_port_t ref = mach_reply_port ();
+ error_t err =
+ (isproc ? proc_reauthenticate : io_reauthenticate)
+ (*port, ref, MACH_MSG_TYPE_MAKE_SEND);
+
+ if (!err)
+ err = auth_user_authenticate (auth, ref, MACH_MSG_TYPE_MAKE_SEND,
+ &newport);
+ if (err)
+ {
+ if (must_reauth)
+ return err;
+ /* Nothing Happens. */
+ }
+ else
+ {
+ if (isproc)
+ mach_port_deallocate (mach_task_self (), newport);
+ else
+ {
+ mach_port_deallocate (mach_task_self (), *port);
+ *port = newport;
+ }
+ }
+ mach_port_destroy (mach_task_self (), ref);
+ }
+ return 0;
+ }
+
+ /* Re-authenticate all the ports we are handing to the user
+ with this new port, and install the new auth port in ports. */
+ for (i = 0; i < num_fds && !err; ++i)
+ err = reauth (&fds[i], 0);
+
+ if (!err)
+ {
+ if (secure)
+ /* Not worth doing; the exec server will just do it again. */
+ ports[INIT_PORT_CRDIR] = MACH_PORT_NULL;
+ else
+ err = reauth (&ports[INIT_PORT_CRDIR], 0);
+ }
+ if (!err)
+ err = reauth (&ports[INIT_PORT_PROC], 1);
+ if (!err)
+ err = reauth (&ports[INIT_PORT_CWDIR], 0);
+
+ if (!err)
+ {
+ mach_port_deallocate (mach_task_self (), ports[INIT_PORT_AUTH]);
+ ports[INIT_PORT_AUTH] = auth;
+ }
+
+ return 0;
+}
diff --git a/libshouldbeinlibc/fsysops.c b/libshouldbeinlibc/fsysops.c
new file mode 100644
index 00000000..f26069df
--- /dev/null
+++ b/libshouldbeinlibc/fsysops.c
@@ -0,0 +1,95 @@
+/* Some handy utility routines for fsys control ports
+
+ Copyright (C) 1996, 1999 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This file 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 <errno.h>
+#include <argz.h>
+#include <mach.h>
+#include <sys/mman.h>
+#include <hurd/fsys.h>
+
+/* Make FSYS readonly or writable. */
+error_t
+fsys_set_readonly (fsys_t fsys, int readonly)
+{
+ error_t err;
+ char *opts = readonly ? "--readonly" : "--writable";
+ size_t opts_len = strlen (opts) + 1;
+ err = fsys_set_options (fsys, opts, opts_len, 0);
+ if (err == EINVAL)
+ err = EOPNOTSUPP;
+ return err;
+}
+
+/* Ask FSYS whether it's readonly, returning the result in READONLY; we don't
+ really have a good method for this, other than asking for it's options and
+ looking for `--readonly' or `--writable'. If we see neither, return
+ EOPNOTSUPP. */
+error_t
+fsys_get_readonly (fsys_t fsys, int *readonly)
+{
+ error_t err;
+ char _opts[200], *opts = _opts;
+ size_t opts_len = sizeof opts;
+
+ err = fsys_get_options (fsys, &opts, &opts_len);
+ if (! err)
+ {
+ char *opt;
+ int ok = 0;
+
+ for (opt = opts
+ ; !ok && opt && opt < opts + opts_len
+ ; opt = argz_next (opts, opts_len, opt))
+ if (strcasecmp (opt, "--readonly") == 0)
+ {
+ *readonly = 1;
+ ok = 1;
+ }
+ else if (strcasecmp (opt, "--writable") == 0)
+ {
+ *readonly = 0;
+ ok = 1;
+ }
+
+ if (! ok)
+ err = EOPNOTSUPP; /* So far as we know... */
+
+ if (opts != _opts)
+ /* Free out-of-line memory returned by fsys_get_options. */
+ munmap (opts, opts_len);
+ }
+
+ return err;
+}
+
+/* Tell FSYS to remount itself. */
+error_t
+fsys_update (fsys_t fsys, int readonly)
+{
+ error_t err;
+ char *opts = "--update";
+ size_t opts_len = strlen (opts) + 1;
+ err = fsys_set_options (fsys, opts, opts_len, 0);
+ if (err == EINVAL)
+ err = EOPNOTSUPP;
+ return err;
+}
diff --git a/libshouldbeinlibc/idvec-auth.c b/libshouldbeinlibc/idvec-auth.c
new file mode 100644
index 00000000..22f2d559
--- /dev/null
+++ b/libshouldbeinlibc/idvec-auth.c
@@ -0,0 +1,79 @@
+/* Idvec functions that interact with an auth server
+
+ Copyright (C) 1995, 1998, 1999 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 <mach.h>
+#include <sys/mman.h>
+#include <hurd/auth.h>
+
+#include "idvec.h"
+
+/* Add to all of EFF_UIDS, AVAIL_UIDS, EFF_GIDS, AVAIL_GIDS (as if with
+ idvec_merge_ids()) the ids associated with the auth port AUTH. Any of
+ these parameters may be NULL if that information isn't desired. */
+error_t
+idvec_merge_auth (struct idvec *eff_uids, struct idvec *avail_uids,
+ struct idvec *eff_gids, struct idvec *avail_gids,
+ auth_t auth)
+{
+ error_t err;
+ uid_t eff_uid_buf[10], avail_uid_buf[20];
+ uid_t *_eff_uids = eff_uid_buf, *_avail_uids = avail_uid_buf;
+ int num_eff_uids = 10, num_avail_uids = 20;
+ uid_t eff_gid_buf[10], avail_gid_buf[20];
+ uid_t *_eff_gids = eff_gid_buf, *_avail_gids = avail_gid_buf;
+ int num_eff_gids = 10, num_avail_gids = 20;
+
+ err = auth_getids (auth,
+ &_eff_uids, &num_eff_uids, &_avail_uids, &num_avail_uids,
+ &_eff_gids, &num_eff_gids, &_avail_gids, &num_avail_gids);
+ if (err)
+ return err;
+
+ if (eff_uids)
+ err = idvec_grow (eff_uids, num_eff_uids);
+ if (avail_uids && !err)
+ err = idvec_grow (avail_uids, num_avail_uids);
+ if (eff_gids && !err)
+ err = idvec_grow (eff_gids, num_eff_gids);
+ if (avail_gids && !err)
+ err = idvec_grow (avail_gids, num_avail_gids);
+
+ if (!err)
+ /* Now that we've ensured there's enough space, none of these should
+ return an error. */
+ {
+ idvec_merge_ids (eff_uids, _eff_uids, num_eff_uids);
+ idvec_merge_ids (avail_uids, _avail_uids, num_avail_uids);
+ idvec_merge_ids (eff_gids, _eff_gids, num_eff_gids);
+ idvec_merge_ids (avail_gids, _avail_gids, num_avail_gids);
+ }
+
+ /* Deallocate any out-of-line memory we got back. */
+ if (_eff_uids != eff_uid_buf)
+ munmap ((caddr_t) _eff_uids, num_eff_uids);
+ if (_avail_uids != avail_uid_buf)
+ munmap ((caddr_t) _avail_uids, num_avail_uids);
+ if (_eff_gids != eff_gid_buf)
+ munmap ((caddr_t) _eff_gids, num_eff_gids);
+ if (_avail_gids != avail_gid_buf)
+ munmap ((caddr_t) _avail_gids, num_avail_gids);
+
+ return err;
+}
diff --git a/libshouldbeinlibc/idvec-funcs.c b/libshouldbeinlibc/idvec-funcs.c
new file mode 100644
index 00000000..1bc6d85f
--- /dev/null
+++ b/libshouldbeinlibc/idvec-funcs.c
@@ -0,0 +1,2 @@
+#define IDVEC_EI
+#include "idvec.h"
diff --git a/libshouldbeinlibc/idvec-impgids.c b/libshouldbeinlibc/idvec-impgids.c
new file mode 100644
index 00000000..62417e12
--- /dev/null
+++ b/libshouldbeinlibc/idvec-impgids.c
@@ -0,0 +1,123 @@
+/* Add gids implied by a user
+
+ Copyright (C) 1997 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 <errno.h>
+#include <idvec.h>
+#include <pwd.h>
+#include <grp.h>
+
+#define NUM_STATIC_GIDS 100 /* Initial size of static gid array. */
+
+/* The set of gids implied by a uid. */
+struct uid_implies
+{
+ uid_t uid; /* this uid... */
+ struct idvec *implies; /* implies these gids. */
+ struct uid_implies *next;
+};
+
+/* Cache of previously calculated results for add_implied_gids. */
+static struct uid_implies *uid_implies_cache = 0;
+
+/* Add to IMPLIED_GIDS those group ids implied by the user UID. */
+static error_t
+_merge_implied_gids (struct idvec *implied_gids, uid_t uid)
+{
+ struct uid_implies *ui;
+
+ for (ui = uid_implies_cache; ui; ui = ui->next)
+ if (ui->uid == uid)
+ return idvec_merge (implied_gids, ui->implies);
+
+ {
+ error_t err = 0;
+ struct passwd *pw = getpwuid (uid);
+
+ if (! pw)
+ err = EINVAL;
+ else
+ {
+ struct idvec *cache = make_idvec ();
+#if 0 /* Glibc doesn't have getgrouplist yet. */
+ gid_t _gids[NUM_STATIC_GIDS], *gids = _gids;
+ size_t maxgids = NUM_STATIC_GIDS;
+ size_t ngids =
+ getgrouplist (pw->pw_name, pw->pw_gid, gids, &maxgids);
+
+ if (ngids == -1)
+ {
+ gids = malloc (maxgids * sizeof (gid_t));
+ if (! gids)
+ err = ENOMEM;
+ else
+ ngids = getgrouplist (pw->pw_name, pw->pw_gid, gids, &maxgids);
+ }
+
+ if (! cache)
+ err = ENOMEM;
+
+ if (! err)
+ {
+ err = idvec_merge_ids (cache, gids, ngids);
+ if (gids != _gids)
+ free (gids);
+ }
+#else
+ if (! cache)
+ err = ENOMEM;
+ else
+ err = idvec_add_new (cache, pw->pw_gid);
+#endif
+
+ if (! err)
+ {
+ idvec_merge (implied_gids, cache);
+ ui = malloc (sizeof (struct uid_implies));
+ if (ui)
+ {
+ ui->uid = uid;
+ ui->implies = cache;
+ ui->next = uid_implies_cache;
+ uid_implies_cache = ui;
+ }
+ else
+ idvec_free (cache);
+ }
+ }
+
+ return err;
+ }
+}
+
+/* Add to GIDS those group ids implied by the users in UIDS. */
+error_t
+idvec_merge_implied_gids (struct idvec *gids, const struct idvec *uids)
+{
+ int i;
+ error_t err = 0;
+ for (i = 0; i < uids->num; i++)
+ {
+ error_t this_err = _merge_implied_gids (gids, uids->ids[i]);
+ if (this_err && !err)
+ err = this_err;
+ }
+ return err;
+}
diff --git a/libshouldbeinlibc/idvec-rep.c b/libshouldbeinlibc/idvec-rep.c
new file mode 100644
index 00000000..b20e58ca
--- /dev/null
+++ b/libshouldbeinlibc/idvec-rep.c
@@ -0,0 +1,164 @@
+/* idvec string representation
+
+ Copyright (C) 1996, 1997, 1998 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 <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <idvec.h>
+#include <grp.h>
+#include <pwd.h>
+
+/* Return a string representation of the ids in IDVEC, each id separated by
+ the string SEP (default ","). SHOW_VALUES and SHOW_NAMES reflect how each
+ id is printed (if SHOW_NAMES is true values are used where names aren't
+ available); if both are true, the `VALUE(NAME)' format is used.
+ ID_NAME_FN is used to map each id to a name; it should return a malloced
+ string, which will be freed here. The empty string is returned for an
+ empty list, and 0 for an allocation error. */
+char *
+idvec_rep (const struct idvec *idvec, int show_values, int show_names,
+ char *(*id_name_fn) (uid_t id), const char *sep)
+{
+ size_t sep_len;
+ char *rep = 0;
+ size_t rep_len = 0, rep_sz = 0;
+
+ int ensure_room (size_t amount)
+ {
+ size_t end = rep_len + amount;
+ if (end > rep_sz)
+ {
+ size_t new_sz = rep_sz + end;
+ char *new_rep = realloc (rep, new_sz);
+ if (new_rep)
+ {
+ rep = new_rep;
+ rep_sz = new_sz;
+ }
+ else
+ return 0;
+ }
+ return 1;
+ }
+ int add_id (uid_t val, char *name)
+ {
+ if (!name || show_values)
+ {
+ if (! ensure_room (10))
+ return 0;
+ rep_len += snprintf (rep + rep_len, 10, "%d", val);
+ }
+ if (name)
+ {
+ size_t nlen = strlen (name) + 3;
+ if (! ensure_room (nlen))
+ {
+ free (name);
+ return 0;
+ }
+ rep_len +=
+ snprintf (rep + rep_len, nlen, show_values ? "(%s)" : "%s", name);
+ free (name);
+ }
+ return 1;
+ }
+
+ if (! sep)
+ sep = ",";
+ sep_len = strlen (sep);
+
+ if (idvec->num > 0)
+ {
+ int i;
+
+ for (i = 0; i < idvec->num; i++)
+ {
+ char *name = 0;
+ uid_t val = idvec->ids[i];
+
+ if (i > 0)
+ {
+ if (ensure_room (sep_len))
+ {
+ strcpy (rep + rep_len, sep);
+ rep_len += sep_len;
+ }
+ else
+ break;
+ }
+
+ if (show_names || !show_values)
+ name = (*id_name_fn) (val);
+ if (! add_id (val, name))
+ break;
+ }
+
+ if (i < idvec->num)
+ {
+ free (rep);
+ return 0;
+ }
+
+ return rep;
+ }
+
+ return strdup ("");
+}
+
+/* Return a malloced string with the name of the user UID. */
+static char *
+lookup_uid (uid_t uid)
+{
+ char buf[1024];
+ struct passwd _pw, *pw;
+ if (getpwuid_r (uid, &_pw, buf, sizeof buf, &pw) == 0)
+ return strdup (pw->pw_name);
+ else
+ return 0;
+}
+
+/* Return a malloced string with the name of the group GID. */
+static char *
+lookup_gid (gid_t gid)
+{
+ char buf[1024];
+ struct group _gr, *gr;
+ if (getgrgid_r (gid, &_gr, buf, sizeof buf, &gr) == 0)
+ return strdup (gr->gr_name);
+ else
+ return 0;
+}
+
+/* Like idvec_rep, mapping ids to user names. */
+char *
+idvec_uids_rep (const struct idvec *idvec, int show_values, int show_names,
+ const char *sep)
+{
+ return idvec_rep (idvec, show_values, show_names, lookup_uid, sep);
+}
+
+/* Like idvec_rep, mapping ids to group names. */
+char *
+idvec_gids_rep (const struct idvec *idvec, int show_values, int show_names,
+ const char *sep)
+{
+ return idvec_rep (idvec, show_values, show_names, lookup_gid, sep);
+}
diff --git a/libshouldbeinlibc/idvec-verify.c b/libshouldbeinlibc/idvec-verify.c
new file mode 100644
index 00000000..4014c2b5
--- /dev/null
+++ b/libshouldbeinlibc/idvec-verify.c
@@ -0,0 +1,362 @@
+/* Verify user passwords
+
+ Copyright (C) 1996,97,98,99 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 <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <idvec.h>
+#include <grp.h>
+#include <pwd.h>
+#include <shadow.h>
+
+#define SHADOW_PASSWORD_STRING "x" /* pw_passwd contents for shadow passwd */
+
+extern char *crypt (const char *string, const char salt[2]);
+#pragma weak crypt
+
+static error_t verify_id (); /* FWD */
+
+/* Get a password from the user, returning it in malloced storage. */
+static char *
+get_passwd (const char *prompt,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook)
+{
+ char *st = getpass (prompt);
+ if (st)
+ st = strdup (st);
+ return st;
+}
+
+/* Verify PASSWORD using /etc/passwd (and maybe /etc/shadow). */
+static error_t
+verify_passwd (const char *password,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook)
+{
+ const char *encrypted;
+ int wheel_uid = (int)hook;
+ const char *sys_encrypted;
+
+ if (! pwd_or_grp)
+ /* No password db entry for ID; if ID is root, the system is probably
+ really fucked up, so grant it (heh). */
+ return (id == 0 ? 0 : EACCES);
+
+ /* The encrypted password in the passwd db. */
+ sys_encrypted =
+ (is_group
+ ? ((struct passwd *)pwd_or_grp)->pw_passwd
+ : ((struct group *)pwd_or_grp)->gr_passwd);
+
+ if (sys_encrypted[0] == '\0')
+ return 0; /* No password. */
+
+ if (crypt)
+ /* Encrypt the password entered by the user (SYS_ENCRYPTED is the salt). */
+ encrypted = crypt (password, sys_encrypted);
+ else
+ /* No crypt on this system! Use plain-text passwords. */
+ encrypted = password;
+
+ if (! encrypted)
+ /* Crypt failed. */
+ return errno;
+
+ /* See whether the user's password matches the system one. */
+ if (strcmp (encrypted, sys_encrypted) == 0)
+ /* Password check succeeded. */
+ return 0;
+ else if (id == 0 && !is_group && wheel_uid)
+ /* Special hack: a user attempting to gain root access can use
+ their own password (instead of root's) if they're in group 0. */
+ {
+ struct passwd _pw, *pw;
+ char lookup_buf[1024];
+ char sp_lookup_buf[1024];
+
+ const char *check_shadow (struct passwd *pw)
+ {
+ if (strcmp (pw->pw_passwd, SHADOW_PASSWORD_STRING) == 0)
+ {
+ /* When encrypted password is "x", try shadow passwords. */
+ struct spwd _sp, *sp;
+ if (getspnam_r (pw->pw_name, &_sp, sp_lookup_buf,
+ sizeof sp_lookup_buf, &sp) == 0)
+ return sp->sp_pwdp;
+ }
+ return pw->pw_passwd;
+ }
+
+ if (getpwuid_r (wheel_uid, &_pw, lookup_buf, sizeof lookup_buf, &pw))
+ return errno ?: EINVAL;
+
+ sys_encrypted = check_shadow (pw);
+
+ encrypted = crypt (password, sys_encrypted);
+ if (! encrypted)
+ /* Crypt failed. */
+ return errno;
+
+ if (strcmp (encrypted, sys_encrypted) == 0)
+ /* *this* password is correct! */
+ return 0;
+ }
+
+ return EACCES;
+}
+
+/* Make sure the user has the right to the ids in UIDS and GIDS, given that
+ we know he already has HAVE_UIDS and HAVE_GIDS, asking for passwords (with
+ GETPASS_FN) where necessary; any of the arguments may be 0, which is
+ treated the same as if they were empty. 0 is returned if access should be
+ allowed, otherwise EINVAL if an incorrect password was entered, or an
+ error relating to resource failure. Any uid/gid < 0 will be guaranteed to
+ fail regardless of what the user types. GETPASS_FN should ask for a
+ password from the user, and return it in malloced storage; it defaults to
+ using the standard libc function getpass. If VERIFY_FN is 0, then the
+ users password will be encrypted with crypt and compared with the
+ password/group entry's encrypted password, otherwise, VERIFY_FN will be
+ called to check the entered password's validity; it should return 0 if the
+ given password is correct, or an error code. The common arguments to
+ GETPASS_FN and VERIFY_FN are: ID, the user/group id; IS_GROUP, true if its
+ a group, or false if a user; PWD_OR_GRP, a pointer to either the passwd or
+ group entry for ID, and HOOK, containing the appropriate hook passed into
+ idvec_verify. */
+error_t
+idvec_verify (const struct idvec *uids, const struct idvec *gids,
+ const struct idvec *have_uids, const struct idvec *have_gids,
+ char *(*getpass_fn) (const char *prompt,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook),
+ void *getpass_hook,
+ error_t (*verify_fn) (const char *password,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook),
+ void *verify_hook)
+{
+ if (have_uids && idvec_contains (have_uids, 0))
+ /* Root can do anything. */
+ return 0;
+ else
+ {
+ int i;
+ int multiple = 0; /* Asking for multiple ids? */
+ error_t err = 0; /* Our return status. */
+ struct idvec implied_gids = IDVEC_INIT; /* Gids implied by uids. */
+ /* If we already are in group 0 (`wheel'), this user's password can be
+ used to get root privileges instead of root's. */
+ int wheel_uid =
+ ((have_uids && have_gids
+ && (idvec_contains (have_gids, 0) && have_uids->num > 0))
+ ? have_uids->ids[0]
+ : 0);
+
+ if (! verify_fn)
+ {
+ verify_fn = verify_passwd;
+ verify_hook = (void *)wheel_uid;
+ }
+
+ /* See if there are multiple ids in contention, in which case we should
+ name each user/group as we ask for its password. */
+ if (uids && gids)
+ {
+ int num_non_implied_gids = 0;
+
+ /* Calculate which groups we need not ask about because they are
+ implied by the uids which we (will) have verified. Note that we
+ ignore any errors; at most, it means we will ask for too many
+ passwords. */
+ idvec_merge_implied_gids (&implied_gids, uids);
+
+ for (i = 0; i < gids->num; i++)
+ if (! idvec_contains (&implied_gids, gids->ids[i]))
+ num_non_implied_gids++;
+
+ multiple = (uids->num + num_non_implied_gids) > 1;
+ }
+ else if (uids)
+ multiple = uids->num > 1;
+ else if (gids)
+ multiple = gids->num > 1;
+
+ if (uids && idvec_contains (uids, 0))
+ /* root is being asked for, which, once granted will provide access for
+ all the others. */
+ err = verify_id (0, 0, multiple,
+ getpass_fn, getpass_hook, verify_fn, verify_hook);
+ else
+ {
+ if (uids)
+ /* Check uids */
+ for (i = 0; i < uids->num && !err; i++)
+ {
+ uid_t uid = uids->ids[i];
+ if (!have_uids || !idvec_contains (have_uids, uid))
+ err = verify_id (uid, 0, multiple,
+ getpass_fn, getpass_hook, verify_fn, verify_hook);
+ }
+
+ if (gids)
+ /* Check gids */
+ for (i = 0; i < gids->num && !err; i++)
+ {
+ gid_t gid = gids->ids[i];
+ if ((!have_gids || !idvec_contains (have_gids, gid))
+ && !idvec_contains (&implied_gids, gid))
+ err = verify_id (gid, 1, multiple,
+ getpass_fn, getpass_hook, verify_fn, verify_hook);
+ }
+ }
+
+ idvec_fini (&implied_gids);
+
+ return err;
+ }
+}
+
+/* Verify that the user should be allowed to assume the indentity of the
+ user/group ID (depending on whether IS_GROUP is false/true). If MULTIPLE
+ is true, then this is one of multiple ids being verified, so */
+static error_t
+verify_id (uid_t id, int is_group, int multiple,
+ char *(*getpass_fn) (const char *prompt,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook),
+ void *getpass_hook,
+ error_t (*verify_fn) (const char *password,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook),
+ void *verify_hook)
+{
+ int err;
+ void *pwd_or_grp = 0;
+ char *name = 0;
+ char *prompt = 0, *password;
+ char id_lookup_buf[1024];
+ char sp_lookup_buf[1024];
+
+ /* VERIFY_FN should have been defaulted in idvec_verify if necessary. */
+ assert (verify_fn);
+
+ if (id >= 0)
+ do
+ {
+ if (is_group)
+ {
+ struct group _gr, *gr;
+ if (getgrgid_r (id, &_gr, id_lookup_buf, sizeof id_lookup_buf, &gr)
+ == 0)
+ {
+ if (!gr->gr_passwd || !*gr->gr_passwd)
+ return (*verify_fn) ("", id, 1, gr, verify_hook);
+ name = gr->gr_name;
+ pwd_or_grp = gr;
+ }
+ }
+ else
+ {
+ struct passwd _pw, *pw;
+ if (getpwuid_r (id, &_pw, id_lookup_buf, sizeof id_lookup_buf, &pw)
+ == 0)
+ {
+ if (strcmp (pw->pw_passwd, SHADOW_PASSWORD_STRING) == 0)
+ {
+ /* When encrypted password is "x", check shadow
+ passwords to see if there is an empty password. */
+ struct spwd _sp, *sp;
+ if (getspnam_r (pw->pw_name, &_sp, sp_lookup_buf,
+ sizeof sp_lookup_buf, &sp) == 0)
+ /* The storage for the password string is in
+ SP_LOOKUP_BUF, a local variable in this function.
+ We Know that the only use of PW->pw_passwd will be
+ in the VERIFY_FN call in this function, and that
+ the pointer will not be stored past the call. */
+ pw->pw_passwd = sp->sp_pwdp;
+ }
+
+ if (pw->pw_passwd[0] == '\0')
+ return (*verify_fn) ("", id, 0, pw, verify_hook);
+ name = pw->pw_name;
+ pwd_or_grp = pw;
+ }
+ }
+ if (! name)
+ {
+ /* [ug]id lookup failed! */
+ if (id != 0 || is_group)
+ /* If ID != 0, then it's probably just an unknown id, so ask for
+ the root password instead -- root should be able to do
+ anything. */
+ {
+ id = 0; /* Root */
+ is_group = 0; /* uid */
+ multiple = 1; /* Explicitly ask for root's password. */
+ }
+ else
+ /* No password entry for root. */
+ name = "root";
+ }
+ }
+ while (! name);
+
+ if (! getpass_fn)
+ /* Default GETPASS_FN to using getpass. */
+ getpass_fn = get_passwd;
+
+ if (multiple)
+ {
+ if (name)
+ asprintf (&prompt, "Password for %s%s:",
+ is_group ? "group " : "", name);
+ else
+ asprintf (&prompt, "Password for %s %d:",
+ is_group ? "group" : "user", id);
+ }
+
+ /* Prompt the user for the password. */
+ if (prompt)
+ {
+ password =
+ (*getpass_fn) (prompt, id, is_group, pwd_or_grp, getpass_hook);
+ free (prompt);
+ }
+ else
+ password =
+ (*getpass_fn) ("Password:", id, is_group, pwd_or_grp, getpass_hook);
+
+ /* Check the user's answer. */
+ if (password)
+ {
+ err = (*verify_fn) (password, id, is_group, pwd_or_grp, verify_hook);
+
+ /* Paranoia may destroya. */
+ memset (password, 0, strlen (password));
+
+ free (password);
+ }
+ else
+ err = EACCES;
+
+ return err;
+}
diff --git a/libshouldbeinlibc/idvec.c b/libshouldbeinlibc/idvec.c
new file mode 100644
index 00000000..692c4788
--- /dev/null
+++ b/libshouldbeinlibc/idvec.c
@@ -0,0 +1,338 @@
+/* Routines for vectors of uids/gids
+
+ Copyright (C) 1995, 1996, 1997, 1998, 1999 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 <malloc.h>
+#include <string.h>
+#include <idvec.h>
+
+/* Return a new, empty, idvec, or NULL if there wasn't enough memory. */
+struct idvec *
+make_idvec ()
+{
+ struct idvec *idvec = malloc (sizeof (struct idvec));
+ if (idvec)
+ {
+ idvec->alloced = idvec->num = 0;
+ idvec->ids = 0;
+ }
+ return idvec;
+}
+
+/* Free's IDVEC, but not the storage pointed to by the IDS field. */
+void
+idvec_free_wrapper (struct idvec *idvec)
+{
+ free (idvec);
+}
+
+void
+idvec_free_contents (struct idvec *idvec)
+{
+ if (idvec->alloced)
+ free (idvec->ids);
+}
+
+void
+idvec_free (struct idvec *idvec)
+{
+ idvec_free_contents (idvec);
+ idvec_free_wrapper (idvec);
+}
+
+/* Ensure that IDVEC has enough spaced allocated to hold NUM ids, thus
+ ensuring that any subsequent ids added won't return a memory allocation
+ error unless it would result in more ids that NUM. ENOMEM is returned if
+ a memory allocation error occurs. */
+error_t
+idvec_ensure (struct idvec *idvec, unsigned num)
+{
+ if (num > idvec->alloced)
+ {
+ uid_t *_ids = realloc (idvec->ids, num * sizeof (uid_t));
+ if (! _ids)
+ return ENOMEM;
+ idvec->ids = _ids;
+ idvec->alloced = num;
+ }
+ return 0;
+}
+
+/* Like idvec_ensure(), but takes INC, the increment of the number of ids
+ already in IDVEC as an argument. */
+error_t
+idvec_grow (struct idvec *idvec, unsigned inc)
+{
+ return idvec_ensure (idvec, idvec->num + inc);
+}
+
+/* Returns true if IDVEC contains ID, at or after position POS. */
+int
+idvec_tail_contains (const struct idvec *idvec, unsigned pos, uid_t id)
+{
+ uid_t *ids = idvec->ids, *end = ids + idvec->num, *p = ids + pos;
+ while (p < end)
+ if (*p++ == id)
+ return 1;
+ return 0;
+}
+
+/* Insert ID into IDVEC at position POS, returning ENOMEM if there wasn't
+ enough memory, or 0. */
+error_t
+idvec_insert (struct idvec *idvec, unsigned pos, uid_t id)
+{
+ error_t err = 0;
+ unsigned num = idvec->num;
+ unsigned new_num = (pos < num ? num + 1 : pos + 1);
+
+ if (idvec->alloced == num)
+ /* If we seem to be growing by just one, actually prealloc some more. */
+ err = idvec_ensure (idvec, new_num + num);
+ else
+ err = idvec_ensure (idvec, new_num);
+
+ if (! err)
+ {
+ uid_t *ids = idvec->ids;
+ if (pos < num)
+ bcopy (ids + pos, ids + pos + 1, (num - pos) * sizeof (uid_t));
+ else if (pos > num)
+ bzero (ids + num, (pos - num) * sizeof (uid_t));
+ ids[pos] = id;
+ idvec->num = new_num;
+ }
+
+ return err;
+}
+
+/* Add ID onto the end of IDVEC, returning ENOMEM if there's not enough memory,
+ or 0. */
+error_t
+idvec_add (struct idvec *idvec, uid_t id)
+{
+ return idvec_insert (idvec, idvec->num, id);
+}
+
+/* If IDVEC doesn't contain ID, add it onto the end, returning ENOMEM if
+ there's not enough memory; otherwise, do nothing. */
+error_t
+idvec_add_new (struct idvec *idvec, uid_t id)
+{
+ if (idvec_contains (idvec, id))
+ return 0;
+ else
+ return idvec_add (idvec, id);
+}
+
+/* If IDVEC doesn't contain ID at position POS or after, insert it at POS,
+ returning ENOMEM if there's not enough memory; otherwise, do nothing. */
+error_t
+idvec_insert_new (struct idvec *idvec, unsigned pos, uid_t id)
+{
+ if (idvec_tail_contains (idvec, pos, id))
+ return 0;
+ else
+ return idvec_insert (idvec, pos, id);
+}
+
+/* Set the ids in IDVEC to IDS (NUM elements long); delete whatever
+ the previous ids were. */
+error_t
+idvec_set_ids (struct idvec *idvec, const uid_t *ids, unsigned num)
+{
+ error_t err;
+
+ err = idvec_ensure (idvec, num);
+ if (!err)
+ {
+ bcopy (ids, idvec->ids, num * sizeof (uid_t));
+ idvec->num = num;
+ }
+ return err;
+}
+
+/* Like idvec_set_ids, but get the new ids from new. */
+error_t
+idvec_set (struct idvec *idvec, const struct idvec *new)
+{
+ return idvec_set_ids (idvec, new->ids, new->num);
+}
+
+/* Adds each id in the vector IDS (NUM elements long) to IDVEC, as long as it
+ wasn't previously in IDVEC. */
+error_t
+idvec_merge_ids (struct idvec *idvec, const uid_t *ids, unsigned num)
+{
+ error_t err = 0;
+ unsigned num_old = idvec->num;
+ while (num-- > 0 && !err)
+ {
+ int i;
+ for (i = 0; i < num_old; i++)
+ if (idvec->ids[i] == *ids)
+ break;
+ if (i == num_old)
+ err = idvec_add (idvec, *ids);
+ ids++;
+ }
+ return err;
+}
+
+/* Adds each id from NEW to IDVEC, as if with idvec_add_new(). */
+error_t
+idvec_merge (struct idvec *idvec, const struct idvec *new)
+{
+ return idvec_merge_ids (idvec, new->ids, new->num);
+}
+
+/* Remove any occurances of ID in IDVEC after position POS.
+ Returns true if anything was done. */
+int
+idvec_remove (struct idvec *idvec, unsigned pos, uid_t id)
+{
+ if (pos < idvec->num)
+ {
+ int left = idvec->num - pos;
+ uid_t *ids = idvec->ids + pos, *targ = ids;
+ while (left--)
+ {
+ if (*ids != id)
+ {
+ if (ids != targ)
+ *targ = *ids;
+ targ++;
+ }
+ ids++;
+ }
+ if (ids == targ)
+ return 0;
+ idvec->num = targ - idvec->ids;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+/* Remove all ids in SUB from IDVEC, returning true if anything was done. */
+int
+idvec_subtract (struct idvec *idvec, const struct idvec *sub)
+{
+ int i;
+ int done = 0;
+ for (i = 0; i < sub->num; i++)
+ done |= idvec_remove (idvec, 0, sub->ids[i]);
+ return done;
+}
+
+/* Remove all ids from IDVEC that are *not* in KEEP, returning true if
+ anything was changed. */
+int
+idvec_keep (struct idvec *idvec, const struct idvec *keep)
+{
+ uid_t *old = idvec->ids, *new = old, *end = old + idvec->num;
+
+ while (old < end)
+ {
+ uid_t id = *old++;
+ if (idvec_contains (keep, id))
+ {
+ if (old != new)
+ *new = id;
+ new++;
+ }
+ }
+
+ if (old != new)
+ {
+ idvec->num = new - idvec->ids;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+/* Deleted the id at position POS in IDVEC. */
+void
+idvec_delete (struct idvec *idvec, unsigned pos)
+{
+ unsigned num = idvec->num;
+ if (pos < num)
+ {
+ uid_t *ids = idvec->ids;
+ idvec->num = --num;
+ if (num > pos)
+ bcopy (ids + pos + 1, ids + pos, (num - pos) * sizeof (uid_t));
+ }
+}
+
+/* Insert ID at position POS in IDVEC, remove any instances of ID previously
+ present at POS or after. ENOMEM is returned if there's not enough memory,
+ otherwise 0. */
+error_t
+idvec_insert_only (struct idvec *idvec, unsigned pos, uid_t id)
+{
+ if (idvec->num > pos && idvec->ids[pos] == id)
+ return 0;
+ else
+ {
+ idvec_remove (idvec, pos, id);
+ return idvec_insert (idvec, pos, id);
+ }
+}
+
+/* EFF and AVAIL should be idvec's corresponding to a processes
+ effective and available ids. ID replaces the first id in EFF, and,
+ if there are any IDs in AVAIL, replaces the second ID in AVAIL;
+ what it replaces in any case is preserved by adding it to AVAIL if
+ not already present. In addition, the If SECURE is non-NULL, and
+ ID was not previously present in either EFF or AVAIL, then *SECURE
+ is set to true. ENOMEM is returned if a malloc fails, otherwise 0.
+ The return parameters are only touched if this call succeeds. */
+error_t
+idvec_setid (struct idvec *eff, struct idvec *avail, uid_t id, int *secure)
+{
+ error_t err;
+ /* True if ID was not previously present in either EFF or AVAIL. */
+ int _secure = !idvec_contains (eff, id) && !idvec_contains (avail, id);
+
+ if (eff->num > 0)
+ {
+ /* If there are any old effective ids, we replace eff[0] with
+ ID, and try to preserve the old eff[0] by putting it in AVAIL
+ list if necessary. */
+ err = idvec_add_new (avail, eff->ids[0]);
+ if (!err)
+ eff->ids[0] = id;
+ }
+ else
+ /* No previous effective ids, just make ID the first one. */
+ err = idvec_add (eff, id);
+
+ if (avail->num > 0 && !err)
+ err = idvec_insert_only (avail, 1, id);
+
+ if (err)
+ return err;
+
+ if (_secure && secure && !*secure)
+ *secure = 1;
+
+ return 0;
+}
diff --git a/libshouldbeinlibc/idvec.h b/libshouldbeinlibc/idvec.h
new file mode 100644
index 00000000..621dfba6
--- /dev/null
+++ b/libshouldbeinlibc/idvec.h
@@ -0,0 +1,218 @@
+/* Routines for vectors of uids/gids
+
+ Copyright (C) 1995, 1996, 1997, 1999 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 __IDVEC_H__
+#define __IDVEC_H__
+
+#include <sys/types.h>
+#include <errno.h>
+#include <hurd/hurd_types.h>
+
+#ifndef IDVEC_EI
+#define IDVEC_EI extern inline
+#endif
+
+struct idvec
+{
+ uid_t *ids;
+ unsigned num, alloced;
+};
+
+#define IDVEC_INIT { 0 }
+
+/* Return a new, empty, idvec, or NULL if there wasn't enough memory. */
+struct idvec *make_idvec (void);
+
+/* Free the storage pointed to by IDVEC->ids. */
+void idvec_free_contents (struct idvec *idvec);
+#define idvec_fini idvec_free_contents
+
+/* Free IDVEC, but not the storage pointed to by the IDS field. */
+void idvec_free_wrapper (struct idvec *idvec);
+
+/* Free IDVEC and any storage associated with it. */
+void idvec_free (struct idvec *idvec);
+
+/* Mark IDVEC as not containing any ids. */
+IDVEC_EI void
+idvec_clear (struct idvec *idvec)
+{
+ idvec->num = 0;
+}
+
+/* Returns true if IDVEC contains no ids. */
+IDVEC_EI int
+idvec_is_empty (const struct idvec *idvec)
+{
+ return idvec->num == 0;
+}
+
+/* Return true if IDVEC1 has contents identical to IDVEC2. */
+IDVEC_EI int
+idvec_equal (const struct idvec *idvec1, const struct idvec *idvec2)
+{
+ size_t num = idvec1->num;
+ return idvec2->num == num
+ && (num == 0
+ || memcmp (idvec1->ids, idvec2->ids, num * sizeof *idvec1->ids) == 0);
+}
+
+/* Ensure that IDVEC has enough spaced allocated to hold NUM ids, thus
+ ensuring that any subsequent ids added won't return a memory allocation
+ error unless it would result in more ids that NUM. ENOMEM is returned if
+ a memory allocation error occurs. */
+error_t idvec_ensure (struct idvec *idvec, unsigned num);
+
+/* Like idvec_ensure(), but takes INC, the increment of the number of ids
+ already in IDVEC as an argument. */
+error_t idvec_grow (struct idvec *idvec, unsigned inc);
+
+/* Returns true if IDVEC contains ID, at or after position POS. */
+int idvec_tail_contains (const struct idvec *idvec, unsigned pos, uid_t id);
+
+/* Returns true if IDVEC contains ID. */
+IDVEC_EI int
+idvec_contains (const struct idvec *idvec, uid_t id)
+{
+ return idvec_tail_contains (idvec, 0, id);
+}
+
+/* Insert ID into IDVEC at position POS, returning ENOMEM if there wasn't
+ enough memory, or 0. */
+error_t idvec_insert (struct idvec *idvec, unsigned pos, uid_t id);
+
+/* Add ID onto the end of IDVEC, returning ENOMEM if there's not enough memory,
+ or 0. */
+error_t idvec_add (struct idvec *idvec, uid_t id);
+
+/* If IDVEC doesn't contain ID, add it onto the end, returning ENOMEM if
+ there's not enough memory; otherwise, do nothing. */
+error_t idvec_add_new (struct idvec *idvec, uid_t id);
+
+/* If IDVEC doesn't contain ID at position POS or after, insert it at POS,
+ returning ENOMEM if there's not enough memory; otherwise, do nothing. */
+error_t idvec_insert_new (struct idvec *idvec, unsigned pos, uid_t id);
+
+/* Set the ids in IDVEC to IDS (NUM elements long); delete whatever
+ the previous ids were. */
+error_t idvec_set_ids (struct idvec *idvec, const uid_t *ids, unsigned num);
+
+/* Like idvec_set_ids, but get the new ids from new. */
+error_t idvec_set (struct idvec *idvec, const struct idvec *new);
+
+/* Adds each id in the vector IDS (NUM elements long) to IDVEC, as if with
+ idvec_add_new(). */
+error_t idvec_merge_ids (struct idvec *idvec, const uid_t *ids, unsigned num);
+
+/* Adds each id from NEW to IDVEC, as if with idvec_add_new(). */
+error_t idvec_merge (struct idvec *idvec, const struct idvec *new);
+
+/* Remove all ids in SUB from IDVEC, returning true if anything was done. */
+int idvec_subtract (struct idvec *idvec, const struct idvec *sub);
+
+/* Remove all ids from IDVEC that are *not* in KEEP, returning true if
+ anything was changed. */
+int idvec_keep (struct idvec *idvec, const struct idvec *keep);
+
+/* Remove any occurances of ID in IDVEC after position POS> Returns true if
+ anything was done. */
+int idvec_remove (struct idvec *idvec, unsigned pos, uid_t id);
+
+/* Deleted the id at position POS in IDVEC. */
+void idvec_delete (struct idvec *idvec, unsigned pos);
+
+/* Insert ID at position POS in IDVEC, remove any instances of ID previously
+ present at POS or after. ENOMEM is returned if there's not enough memory,
+ otherwise 0. */
+error_t idvec_insert_only (struct idvec *idvec, unsigned pos, uid_t id);
+
+/* EFF and AVAIL should be idvec's corresponding to a process's
+ effective and available ids. ID replaces the first id in EFF, and,
+ if there are any IDs in AVAIL, replaces the second ID in AVAIL;
+ what it replaces in any case is preserved by adding it to AVAIL if
+ not already present. In addition, the If SECURE is non-NULL, and
+ ID was not previously present in either EFF or AVAIL, then *SECURE
+ is set to true. ENOMEM is returned if a malloc fails, otherwise 0.
+ The return parameters are only touched if this call succeeds. */
+error_t idvec_setid (struct idvec *eff, struct idvec *avail, uid_t id,
+ int *secure);
+
+/* Add to all of EFF_UIDS, AVAIL_UIDS, EFF_GIDS, AVAIL_GIDS (as if with
+ idvec_merge) the ids associated with the auth port AUTH. Any of these
+ parameters may be NULL if that information isn't desired. */
+error_t idvec_merge_auth (struct idvec *eff_uids, struct idvec *avail_uids,
+ struct idvec *eff_gids, struct idvec *avail_gids,
+ auth_t auth);
+
+/* Add to GIDS those group ids implied by the users in UIDS. */
+error_t idvec_merge_implied_gids (struct idvec *gids, const struct idvec *uids);
+
+/* Make sure the user has the right to the ids in UIDS and GIDS, given that
+ we know he already has HAVE_UIDS and HAVE_GIDS, asking for passwords (with
+ GETPASS_FN) where necessary; any of the arguments may be 0, which is
+ treated the same as if they were empty. 0 is returned if access should be
+ allowed, otherwise EINVAL if an incorrect password was entered, or an
+ error relating to resource failure. Any uid/gid < 0 will be guaranteed to
+ fail regardless of what the user types. GETPASS_FN should ask for a
+ password from the user, and return it in malloced storage; it defaults to
+ using the standard libc function getpass. If VERIFY_FN is 0, then the
+ users password will be encrypted with crypt and compared with the
+ password/group entry's encrypted password, otherwise, VERIFY_FN will be
+ called to check the entered password's validity; it should return 0 if the
+ given password is correct, or an error code. The common arguments to
+ GETPASS_FN and VERIFY_FN are: ID, the user/group id; IS_GROUP, true if its
+ a group, or false if a user; PWD_OR_GRP, a pointer to either the passwd or
+ group entry for ID, and HOOK, containing the appropriate hook passed into
+ idvec_verify. */
+error_t idvec_verify (const struct idvec *uids, const struct idvec *gids,
+ const struct idvec *have_uids,
+ const struct idvec *have_gids,
+ char *(*getpass_fn) (const char *prompt,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook),
+ void *getpass_hook,
+ error_t (*verify_fn) (const char *password,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook),
+ void *verify_hook);
+
+/* Return a string representation of the ids in IDVEC, each id separated by
+ the string SEP (default ","). SHOW_VALUES and SHOW_NAMES reflect how each
+ id is printed (if SHOW_NAMES is true values are used where names aren't
+ available); if both are true, the `VALUE(NAME)' format is used.
+ ID_NAME_FN is used to map each id to a name; it should return a malloced
+ string, which will be freed here. The empty string is returned for an
+ empty list, and 0 for an allocation error. */
+char *idvec_rep (const struct idvec *idvec,
+ int show_values, int show_names,
+ char *(*id_name_fn) (uid_t id),
+ const char *sep);
+
+/* Like idvec_rep, mapping ids to user names. */
+char *idvec_uids_rep (const struct idvec *idvec,
+ int show_values, int show_names,
+ const char *sep);
+
+/* Like idvec_rep, mapping ids to group names. */
+char *idvec_gids_rep (const struct idvec *idvec,
+ int show_values, int show_names,
+ const char *sep);
+
+#endif /* __IDVEC_H__ */
diff --git a/libshouldbeinlibc/lcm.c b/libshouldbeinlibc/lcm.c
new file mode 100644
index 00000000..606f4eba
--- /dev/null
+++ b/libshouldbeinlibc/lcm.c
@@ -0,0 +1,46 @@
+/* Lcm (least common multiple), and gcd (greatest common divisor)
+
+ Copyright (C) 1996 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This file 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. */
+
+/* There are probably more efficient ways to do these... */
+
+/* Return the greatest common divisor of p & q. */
+inline long
+gcd (long p, long q)
+{
+ if (p == 0)
+ return q;
+ else if (q == 0)
+ return p;
+ else if (p == q)
+ return p;
+ else if (q > p)
+ return gcd (q, p);
+ else
+ return gcd (q, p % q);
+}
+
+/* Return the least common multiple of p & q. */
+long
+lcm (long p, long q)
+{
+ return (p / gcd (p, q)) * q;
+}
diff --git a/libshouldbeinlibc/localhost.c b/libshouldbeinlibc/localhost.c
new file mode 100644
index 00000000..f0c67541
--- /dev/null
+++ b/libshouldbeinlibc/localhost.c
@@ -0,0 +1,66 @@
+/* A slightly more convenient wrapper for gethostname
+
+ Copyright (C) 1996 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 <unistd.h>
+#include <malloc.h>
+#include <string.h>
+#include <errno.h>
+
+/* Return the name of the localhost. This is just a wrapper for gethostname,
+ which takes care of allocating a big enough buffer, and caches the result
+ after the first call (so the result should be copied before modification).
+ If something goes wrong, 0 is returned, and errno set. */
+char *
+localhost ()
+{
+ static char *buf = 0;
+ static size_t buf_len = 0;
+
+ if (! buf)
+ {
+ do {
+ errno = 0;
+
+ if (buf) {
+ buf_len += buf_len;
+ buf = realloc (buf, buf_len);
+ } else {
+ buf_len = 128; /* Initial guess */
+ buf = malloc (buf_len);
+ }
+
+ if (! buf)
+ {
+ errno = ENOMEM;
+ return 0;
+ }
+ } while ((gethostname(buf, buf_len) == 0 && !memchr (buf, '\0', buf_len))
+ || errno == ENAMETOOLONG);
+
+ if (errno)
+ /* gethostname failed, abort. */
+ {
+ free (buf);
+ buf = 0;
+ }
+ }
+
+ return buf;
+}
diff --git a/libshouldbeinlibc/maptime-funcs.c b/libshouldbeinlibc/maptime-funcs.c
new file mode 100644
index 00000000..eeac3b3e
--- /dev/null
+++ b/libshouldbeinlibc/maptime-funcs.c
@@ -0,0 +1,5 @@
+#define MAPTIME_EI
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include "maptime.h"
diff --git a/libshouldbeinlibc/maptime.c b/libshouldbeinlibc/maptime.c
new file mode 100644
index 00000000..bc750458
--- /dev/null
+++ b/libshouldbeinlibc/maptime.c
@@ -0,0 +1,79 @@
+/* Support for mach's mapped time
+
+ Copyright (C) 1996, 1997 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 <fcntl.h>
+#include <hurd.h>
+#include <mach.h>
+#include <device/device.h>
+
+#include "maptime.h"
+
+/* Return the mach mapped time page in MTIME. If USE_MACH_DEV is false, then
+ the hurd time device DEV_NAME, or "/dev/time" if DEV_NAME is 0, is
+ used. If USE_MACH_DEV is true, the mach device DEV_NAME, or "time" if
+ DEV_NAME is 0, is used; this is a privileged operation. The mapped time
+ may be converted to a struct timeval at any time using maptime_read. */
+error_t
+maptime_map (int use_mach_dev, char *dev_name,
+ volatile struct mapped_time_value **mtime)
+{
+ error_t err;
+ mach_port_t memobj;
+
+ if (use_mach_dev)
+ {
+ device_t device;
+ mach_port_t device_master;
+
+ err = get_privileged_ports (0, &device_master);
+ if (! err)
+ {
+ err = device_open (device_master, 0, dev_name ?: "time", &device);
+ mach_port_deallocate (mach_task_self (), device_master);
+ }
+
+ err = device_map (device, VM_PROT_READ, 0, sizeof *mtime, &memobj, 0);
+ }
+ else
+ {
+ mach_port_t wr_memobj;
+ file_t node = file_name_lookup (dev_name ?: "/dev/time", O_RDONLY, 0);
+
+ if (node == MACH_PORT_NULL)
+ return errno;
+
+ err = io_map (node, &memobj, &wr_memobj);
+ if (!err && wr_memobj != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), wr_memobj);
+
+ mach_port_deallocate (mach_task_self (), node);
+ }
+
+ if (! err)
+ {
+ *mtime = 0;
+ err =
+ vm_map (mach_task_self (), (vm_address_t *)mtime, sizeof *mtime, 0, 1,
+ memobj, 0, 0, VM_PROT_READ, VM_PROT_READ, VM_INHERIT_NONE);
+ mach_port_deallocate (mach_task_self (), memobj);
+ }
+
+ return err;
+}
diff --git a/libshouldbeinlibc/maptime.h b/libshouldbeinlibc/maptime.h
new file mode 100644
index 00000000..c7a246fc
--- /dev/null
+++ b/libshouldbeinlibc/maptime.h
@@ -0,0 +1,52 @@
+/* Support for mach's mapped time
+
+ Copyright (C) 1996, 1997, 2000 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.org>
+
+ 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 __MAPTIME_H__
+#define __MAPTIME_H__
+
+#ifndef MAPTIME_EI
+#define MAPTIME_EI extern inline
+#endif
+
+#include <mach/time_value.h>
+#include <sys/time.h>
+#include <errno.h>
+
+/* Return the mach mapped time page in MTIME. If USE_MACH_DEV is false, then
+ the hurd uptime device DEV_NAME, or "/dev/uptime" if DEV_NAME is 0, is
+ used. If USE_MACH_DEV is true, the mach device DEV_NAME, or "time" if
+ DEV_NAME is 0, is used; this is a privileged operation. The mapped uptime
+ may be converted to a struct timeval at any time using read_uptime. */
+error_t maptime_map (int use_mach_dev, char *dev_name,
+ volatile struct mapped_time_value **mtime);
+
+/* Read the current time from MTIME into TV. This should be very fast. */
+MAPTIME_EI void
+maptime_read (volatile struct mapped_time_value *mtime, struct timeval *tv)
+{
+ do
+ {
+ tv->tv_sec = mtime->seconds;
+ tv->tv_usec = mtime->microseconds;
+ }
+ while (tv->tv_sec != mtime->check_seconds);
+}
+
+#endif /* __MAPTIME_H__ */
diff --git a/libshouldbeinlibc/options.c b/libshouldbeinlibc/options.c
new file mode 100644
index 00000000..5f719616
--- /dev/null
+++ b/libshouldbeinlibc/options.c
@@ -0,0 +1,231 @@
+/* Hierarchial options parsing, layered over getopt
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This file 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 <stdlib.h>
+#include <string.h>
+#include <limits.h> /* for CHAR_BIT */
+#include <getopt.h>
+#include <cthreads.h>
+
+#include "options.h"
+
+#define EOF (-1)
+
+/* The number of bits we steal in a long-option value for our own use. */
+#define GROUP_BITS CHAR_BIT
+
+/* The number of bits available for the user value. */
+#define USER_BITS ((sizeof ((struct option *)0)->val * CHAR_BIT) - GROUP_BITS)
+#define USER_MASK ((1 << USER_BITS) - 1)
+
+/* ---------------------------------------------------------------- */
+
+/* Returns the offset into LONG_OPTIONS of a long option with called NAME, or
+ -1 if none is found. Passing NULL as NAME will return the number of
+ options. */
+static int
+find_long_option (struct option *long_options, const char *name)
+{
+ struct option *l = long_options;
+ while (l->name != NULL)
+ if (name != NULL && strcmp (l->name, name) == 0)
+ return l - long_options;
+ else
+ l++;
+ if (name == NULL)
+ return l - long_options;
+ else
+ return -1;
+}
+
+/* ---------------------------------------------------------------- */
+
+/* Used to regulate access to the getopt routines, which are non-reentrant. */
+static struct mutex getopt_lock = MUTEX_INITIALIZER;
+
+/* Parse the options strings in ARGC & ARGV according to the options in
+ OPTIONS. FLAGS is one of the OPTIONS_ flags above. If OPTIND is
+ non-NULL, the index in ARGV of the first unparsed option is returned in
+ it. If an unknown option is present, EINVAL is returned; if some parser
+ routine returned a non-zero value, it is returned; otherwise 0 is
+ returned. */
+error_t
+options_parse (struct options *options,
+ int argc, char **argv,
+ unsigned flags, int *arg_index)
+{
+ int opt;
+ struct options *o;
+ /* SHORT_OPTS is the getopt short options string for the union of all the
+ groups of options. */
+ char *short_opts;
+ /* GROUP_SHORT_STARTS is an array pointing to the part of SHORT_OPTS
+ corresponding to each different group of options. We use it to
+ determine from which groupa particular short options is from. */
+ char **group_short_starts;
+ /* LONG_OPTS is the array of getop long option structures for the union of
+ all the groups of options. */
+ struct option *long_opts;
+ error_t err = 0;
+
+ /* Find the merged set of short options. */
+ {
+ char *short_end;
+ int short_len = (flags & OPTIONS_PARSE_ARGS) ? 1 : 0;
+ int num_groups = 0, group;
+
+ /* Find the (maximum) amount of space necessary to store all combined
+ short options, plus the number of options groups in the chain. */
+ for (o = options; o != NULL; o = o->parent)
+ {
+ num_groups++;
+ short_len += strlen (o->short_options);
+ }
+
+ short_opts = short_end = alloca (short_len + 1);
+ if (flags & OPTIONS_PARSE_ARGS)
+ *short_end++ = '-'; /* Tell getopt we want to do this. */
+ *short_end = '\0';
+
+ group_short_starts = alloca (num_groups * sizeof (char *));
+
+ for (o = options, group = 0; o != NULL; o = o->parent, group++)
+ {
+ char *s;
+
+ group_short_starts[group] = short_end;
+
+ for (s = o->short_options; *s != '\0'; s++)
+ /* We add *S to our set of short options only if it hasn't already
+ been added by some previous group. */
+ if (*s != ':' && !index (short_opts, *s))
+ {
+ *short_end++ = *s;
+ /* Copy all the colon modifiers following the option. */
+ while (s[1] == ':')
+ *short_end++ = *++s;
+ *short_end = '\0';
+ }
+ }
+ }
+
+ /* Find the merged set of long options, with keys appropiately prefixed. */
+ {
+ struct option *long_end;
+ int group;
+ int long_len = 0;
+
+ for (o = options; o != NULL; o = o->parent)
+ long_len += find_long_option (o->long_options, NULL);
+
+ long_opts = long_end = alloca ((long_len + 1) * sizeof (struct option));
+ long_end->name = NULL;
+
+ /* Note that GROUP starts at 1 because 0 is for short options. */
+ for (o = options, group = 1; o != NULL; o = o->parent, group++)
+ {
+ struct option *l;
+ for (l = o->long_options; l->name != NULL; l++)
+ /* Only add the long option L if it hasn't been already. */
+ if (find_long_option (long_opts, l->name) < 0)
+ {
+ *long_end = *l;
+ if (long_end->flag == NULL)
+ /* In the case where a long option returns a key from getopt,
+ we add a disambiguating code to all the user's values
+ (which is removed before we actually call the function to
+ parse the value); this means that the user loses use of
+ the high 8 bits in all his values (the sign of the lower
+ bits is preserved however)... */
+ long_end->val = (l->val & USER_MASK) + (group << USER_BITS);
+ /* Keep the LONG_OPTS list terminated. */
+ (++long_end)->name = NULL;
+ }
+ }
+ }
+
+ /* Getopt is (currently) non-reentrant. */
+ mutex_lock (&getopt_lock);
+
+ /* Tell getopt to initialize. */
+ optind = 0;
+
+ if (flags & OPTIONS_PRINT_ERRS)
+ opterr = 1; /* Print error messages. */
+ else
+ {
+ opterr = 0;
+ if (!(flags & OPTIONS_SKIP_ARG0))
+ /* getopt always skips ARGV[0], so we have to fake it out. As long
+ as opterr is 0, then it shouldn't actually try to access it. */
+ argv--, argc++;
+ }
+
+ /* Now use getopt on our coalesced options lists. */
+ while ((opt = getopt_long (argc, argv, short_opts, long_opts, 0)) != EOF)
+ {
+ int group = opt >> USER_BITS;
+
+ err = EINVAL; /* until otherwise asserted */
+
+ if (opt == 1)
+ /* A non-option argument; try each parser in turn. */
+ for (o = options; o != NULL && err == EINVAL; o = o->parent)
+ err = (*o->parser)(0, optarg);
+ else if (group == 0)
+ /* A short option. */
+ {
+ /* By comparing OPT's position in SHORT_OPTS to the various
+ starting positions in GROUP_SHORT_STARTS, we can determine which
+ group OPT came from. */
+ char *short_index = index (short_opts, opt);
+ if (short_index)
+ for (o = options, group = 0; o != NULL; o = o->parent, group++)
+ if (o->parent == NULL
+ || group_short_starts[group + 1] > short_index)
+ {
+ err = (*o->parser)(opt, optarg);
+ break;
+ }
+ }
+ else
+ /* A long option. */
+ for (o = options; o != NULL; o = o->parent)
+ if (--group == 0)
+ {
+ /* We use shifts instead of masking for extracting the user value
+ in order to preserve the sign. */
+ err = (*o->parser)(((opt << GROUP_BITS) >> GROUP_BITS), optarg);
+ break;
+ }
+
+ if (err)
+ break;
+ }
+
+ if (arg_index != NULL)
+ *arg_index = optind;
+
+ mutex_unlock (&getopt_lock);
+
+ return err;
+}
diff --git a/libshouldbeinlibc/options.h b/libshouldbeinlibc/options.h
new file mode 100644
index 00000000..46651add
--- /dev/null
+++ b/libshouldbeinlibc/options.h
@@ -0,0 +1,79 @@
+/* Hierarchial options parsing, layered over getopt
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This file 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. */
+
+#ifndef __OPTIONS_H__
+#define __OPTIONS_H__
+
+#include <errno.h>
+#include <getopt.h>
+
+/* An options structure contains a set of getopt options declarations, a
+ function to deal with getting one, and an optional pointer to another
+ options structure. When actually parsing options, getopt is called with
+ the union of all the options structures chained together through their
+ PARENT pointers, with conflicts being resolved in favor of the first
+ occurance in the chain. */
+struct options
+{
+ /* The getopt-style short options string for this group of options. */
+ char *short_options;
+ /* An array of getopt-style long-options structures. */
+ struct option *long_options;
+
+ /* What to do with an option from this structure. KEY is either the short
+ option letter, or the final member of the long-option entry, as returned
+ by getopt, and ARG is the value of OPTARG. If a non-zero value is
+ returned, then parsing is stopped immediately, and that value is
+ returned from options_parse(). */
+ error_t (*parser)(int key, char *arg);
+
+ /* The next member in this options chain. */
+ struct options *parent;
+};
+
+/* Flags for options_parse: */
+
+/* Ignore the first element of ARGV. Useful for program command lines. */
+#define OPTIONS_SKIP_ARG0 0x1
+
+/* Print error messages for unknown options to stderr; if this flag is set,
+ OPTIONS_SKIP_ARG0 is ignored, as ARGV[0] is used as the program name in
+ the error messages. */
+#define OPTIONS_PRINT_ERRS 0x2
+
+/* Parse non-option args as well, similarly to getopt, by calling the parse
+ function with a key of 0, and the actual arg as the value. Since it's
+ impossible to know which parse function wants to handle it, each one is
+ called in turn, until one returns 0 or an error other than EINVAL. */
+#define OPTIONS_PARSE_ARGS 0x4
+
+
+/* Parse the options strings in ARGC & ARGV according to the options in
+ OPTIONS. FLAGS is one of the OPTIONS_ flags above. If ARG_INDEX is
+ non-NULL, the index in ARGV of the first unparsed option is returned in
+ it. If an unknown option is present, EINVAL is returned; if some parser
+ routine returned a non-zero value, it is returned; otherwise 0 is
+ returned. */
+error_t options_parse (struct options *options, int argc, char **argv,
+ unsigned flags, int *arg_index);
+
+#endif /* __OPTIONS_H__ */
diff --git a/libshouldbeinlibc/portinfo.c b/libshouldbeinlibc/portinfo.c
new file mode 100644
index 00000000..6cb3f375
--- /dev/null
+++ b/libshouldbeinlibc/portinfo.c
@@ -0,0 +1,158 @@
+/* Print information about a task's ports
+
+ Copyright (C) 1996, 1998, 1999 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 <sys/types.h>
+#include <sys/mman.h>
+
+#include "portinfo.h"
+
+/* Prints info about NAME in TASK to STREAM, in a way described by the flags
+ in SHOW. If TYPE is non-zero, it should be what mach_port_type returns
+ for NAME. */
+error_t
+print_port_info (mach_port_t name, mach_port_type_t type, task_t task,
+ unsigned show, FILE *stream)
+{
+ int hex_names = (show & PORTINFO_HEX_NAMES);
+ int first = 1;
+ void comma ()
+ {
+ if (first)
+ first = 0;
+ else
+ fprintf (stream, ", ");
+ }
+ void prefs (mach_port_right_t right)
+ {
+ mach_port_urefs_t refs;
+ error_t err = mach_port_get_refs (task, name, right, &refs);
+ if (! err)
+ fprintf (stream, " (refs: %u)", refs);
+ }
+
+ if (type == 0)
+ {
+ error_t err = mach_port_type (task, name, &type);
+ if (err)
+ return err;
+ }
+
+ fprintf (stream, hex_names ? "%#6x: " : "%6d: ", name);
+
+ if (type & MACH_PORT_TYPE_RECEIVE)
+ {
+ comma ();
+ fprintf (stream, "receive");
+ if (show & PORTINFO_DETAILS)
+ {
+ struct mach_port_status status;
+ error_t err = mach_port_get_receive_status (task, name, &status);
+ if (! err)
+ {
+ fprintf (stream, " (");
+ if (status.mps_pset != MACH_PORT_NULL)
+ fprintf (stream,
+ hex_names ? "port-set: %#x, " : "port-set: %d, ",
+ status.mps_pset);
+ fprintf (stream, "seqno: %u", status.mps_seqno);
+ if (status.mps_mscount)
+ fprintf (stream, ", ms-count: %u", status.mps_mscount);
+ if (status.mps_qlimit != MACH_PORT_QLIMIT_DEFAULT)
+ fprintf (stream, ", qlimit: %u", status.mps_qlimit);
+ if (status.mps_msgcount)
+ fprintf (stream, ", msgs: %u", status.mps_msgcount);
+ fprintf (stream, "%s%s%s)",
+ status.mps_srights ? ", send-rights" : "",
+ status.mps_pdrequest ? ", pd-req" : "",
+ status.mps_nsrequest ? ", ns-req" : "");
+ }
+ }
+ }
+ if (type & MACH_PORT_TYPE_SEND)
+ {
+ comma ();
+ fprintf (stream, "send");
+ if (show & PORTINFO_DETAILS)
+ prefs (MACH_PORT_RIGHT_SEND);
+ }
+ if (type & MACH_PORT_TYPE_SEND_ONCE)
+ {
+ comma ();
+ fprintf (stream, "send-once");
+ }
+ if (type & MACH_PORT_TYPE_DEAD_NAME)
+ {
+ comma ();
+ fprintf (stream, "dead-name");
+ if (show & PORTINFO_DETAILS)
+ prefs (MACH_PORT_RIGHT_DEAD_NAME);
+ }
+ if (type & MACH_PORT_TYPE_PORT_SET)
+ {
+ comma ();
+ fprintf (stream, "port-set");
+ if (show & PORTINFO_DETAILS)
+ {
+ mach_port_t *members = 0;
+ mach_msg_type_number_t members_len = 0, i;
+ error_t err =
+ mach_port_get_set_status (task, name, &members, &members_len);
+ if (! err)
+ {
+ if (members_len == 0)
+ fprintf (stream, " (empty)");
+ else
+ {
+ fprintf (stream, hex_names ? " (%#x" : " (%u", members[0]);
+ for (i = 1; i < members_len; i++)
+ fprintf (stream, hex_names ? ", %#x" : ", %u", members[i]);
+ fprintf (stream, ")");
+ munmap ((caddr_t) members, members_len * sizeof *members);
+ }
+ }
+ }
+ }
+ putc ('\n', stream);
+
+ return 0;
+}
+
+/* Prints info about every port in TASK that has a type in ONLY to STREAM. */
+error_t
+print_task_ports_info (task_t task, mach_port_type_t only,
+ unsigned show, FILE *stream)
+{
+ mach_port_t *names = 0;
+ mach_port_type_t *types = 0;
+ mach_msg_type_number_t names_len = 0, types_len = 0, i;
+ error_t err = mach_port_names (task, &names, &names_len, &types, &types_len);
+
+ if (err)
+ return err;
+
+ for (i = 0; i < names_len; i++)
+ if (types[i] & only)
+ print_port_info (names[i], types[i], task, show, stream);
+
+ munmap ((caddr_t) names, names_len * sizeof *names);
+ munmap ((caddr_t) types, types_len * sizeof *types);
+
+ return 0;
+}
diff --git a/libshouldbeinlibc/portinfo.h b/libshouldbeinlibc/portinfo.h
new file mode 100644
index 00000000..143c2898
--- /dev/null
+++ b/libshouldbeinlibc/portinfo.h
@@ -0,0 +1,58 @@
+/* Print information about a task's ports
+
+ Copyright (C) 1996, 1999 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 __PORTINFO_H__
+#define __PORTINFO_H__
+
+#include <stdio.h>
+#include <errno.h>
+#include <mach.h>
+
+#include <portxlate.h>
+
+/* Flags describing what to show. */
+#define PORTINFO_DETAILS 0x1
+#define PORTINFO_MEMBERS 0x4
+#define PORTINFO_HEX_NAMES 0x8
+
+/* Prints info about NAME in TASK to STREAM, in a way described by the flags
+ in SHOW. If TYPE is non-zero, it should be what mach_port_type returns
+ for NAME. */
+error_t print_port_info (mach_port_t name, mach_port_type_t type, task_t task,
+ unsigned show, FILE *stream);
+
+/* Prints info about every port in TASK that has a type in ONLY to STREAM. */
+error_t print_task_ports_info (task_t task, mach_port_type_t only,
+ unsigned show, FILE *stream);
+
+/* Prints info about NAME translated through X to STREAM, in a way described
+ by the flags in SHOW. If TYPE is non-zero, it should be what
+ mach_port_type returns for NAME in X->to_task. */
+error_t print_xlated_port_info (mach_port_t name, mach_port_type_t type,
+ struct port_name_xlator *x,
+ unsigned show, FILE *stream);
+
+/* Prints info about every port common to both tasks in X, but only if the
+ port in X->from_task has a type in ONLY, to STREAM. */
+error_t print_xlated_task_ports_info (struct port_name_xlator *x,
+ mach_port_type_t only,
+ unsigned show, FILE *stream);
+
+#endif /* __PORTINFO_H__ */
diff --git a/libshouldbeinlibc/portxlate.c b/libshouldbeinlibc/portxlate.c
new file mode 100644
index 00000000..d574cb2f
--- /dev/null
+++ b/libshouldbeinlibc/portxlate.c
@@ -0,0 +1,174 @@
+/* Translate mach port names between two tasks
+
+ Copyright (C) 1996, 1999 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 <malloc.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include "portxlate.h"
+
+/* Return a new port name translator translating names between FROM_TASK and
+ TO_TASK, in XLATOR, or an error. */
+error_t
+port_name_xlator_create (mach_port_t from_task, mach_port_t to_task,
+ struct port_name_xlator **xlator)
+{
+ error_t err;
+ struct port_name_xlator *x = malloc (sizeof (struct port_name_xlator));
+
+ if (! x)
+ return ENOMEM;
+
+ x->from_task = from_task;
+ x->to_task = to_task;
+ x->to_names = 0;
+ x->to_types = 0;
+ x->to_names_len = 0;
+ x->to_types_len = 0;
+
+ /* Cache a list of names in TO_TASK. */
+ err = mach_port_names (to_task,
+ &x->to_names, &x->to_names_len,
+ &x->to_types, &x->to_types_len);
+
+ if (! err)
+ /* Make an array to hold ports from TO_TASK which have been translated
+ into our namespace. */
+ {
+ x->ports = malloc (sizeof (mach_port_t) * x->to_names_len);
+ if (x->ports)
+ {
+ int i;
+ for (i = 0; i < x->to_names_len; i++)
+ x->ports[i] = MACH_PORT_NULL;
+ }
+ else
+ {
+ munmap ((caddr_t) x->to_names,
+ x->to_names_len * sizeof (mach_port_t));
+ munmap ((caddr_t) x->to_types,
+ x->to_types_len * sizeof (mach_port_type_t));
+ err = ENOMEM;
+ }
+ }
+
+ if (err)
+ free (x);
+ else
+ *xlator = x;
+
+ return err;
+}
+
+/* Free the port name translator X and any resources it holds. */
+void
+port_name_xlator_free (struct port_name_xlator *x)
+{
+ int i;
+
+ for (i = 0; i < x->to_names_len; i++)
+ if (x->ports[i] != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), x->ports[i]);
+ free (x->ports);
+
+ munmap ((caddr_t) x->to_names, x->to_names_len * sizeof (mach_port_t));
+ munmap ((caddr_t) x->to_types, x->to_types_len * sizeof (mach_port_type_t));
+
+ mach_port_deallocate (mach_task_self (), x->to_task);
+ mach_port_deallocate (mach_task_self (), x->from_task);
+
+ free (x);
+}
+
+/* Translate the port FROM between the tasks in X, returning the translated
+ name in TO, and the types of TO in TO_TYPE, or an error. If TYPE is
+ non-zero, it should be what mach_port_type returns for FROM. */
+error_t
+port_name_xlator_xlate (struct port_name_xlator *x,
+ mach_port_t from, mach_port_type_t from_type,
+ mach_port_t *to, mach_port_type_t *to_type)
+{
+ error_t err;
+ mach_port_t port;
+ mach_msg_type_number_t i;
+ mach_port_type_t aquired_type;
+ mach_port_type_t valid_to_types;
+
+ if (from_type == 0)
+ {
+ error_t err = mach_port_type (x->from_task, from, &from_type);
+ if (err)
+ return err;
+ }
+
+ if (from_type & MACH_PORT_TYPE_RECEIVE)
+ valid_to_types = MACH_PORT_TYPE_SEND;
+ else if (from_type & MACH_PORT_TYPE_SEND)
+ valid_to_types = MACH_PORT_TYPE_SEND | MACH_PORT_TYPE_RECEIVE;
+ else
+ return EKERN_INVALID_RIGHT;
+
+ /* Translate the name FROM, in FROM_TASK's namespace into our namespace. */
+ err =
+ mach_port_extract_right (x->from_task, from,
+ ((from_type & MACH_PORT_TYPE_RECEIVE)
+ ? MACH_MSG_TYPE_MAKE_SEND
+ : MACH_MSG_TYPE_COPY_SEND),
+ &port,
+ &aquired_type);
+
+ if (err)
+ return err;
+
+ /* Look for likely candidates in TO_TASK's namespace to test against PORT. */
+ for (i = 0; i < x->to_names_len; i++)
+ {
+ if (x->ports[i] == MACH_PORT_NULL && (x->to_types[i] & valid_to_types))
+ /* Port I shows possibilities... */
+ {
+ err =
+ mach_port_extract_right (x->to_task,
+ x->to_names[i],
+ ((x->to_types[i] & MACH_PORT_TYPE_RECEIVE)
+ ? MACH_MSG_TYPE_MAKE_SEND
+ : MACH_MSG_TYPE_COPY_SEND),
+ &x->ports[i],
+ &aquired_type);
+ if (err)
+ x->to_types[i] = 0; /* Don't try to fetch this port again. */
+ }
+
+ if (x->ports[i] == port)
+ /* We win! Port I in TO_TASK is the same as PORT. */
+ break;
+ }
+
+ mach_port_deallocate (mach_task_self (), port);
+
+ if (i < x->to_names_len)
+ /* Port I is the right translation; return its name in TO_TASK. */
+ {
+ *to = x->to_names[i];
+ *to_type = x->to_types[i];
+ return 0;
+ }
+ else
+ return EKERN_INVALID_NAME;
+}
diff --git a/libshouldbeinlibc/portxlate.h b/libshouldbeinlibc/portxlate.h
new file mode 100644
index 00000000..13ddb148
--- /dev/null
+++ b/libshouldbeinlibc/portxlate.h
@@ -0,0 +1,67 @@
+/* Translate mach port names between two tasks
+
+ Copyright (C) 1996 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 __PORTXLATE_H__
+#define __PORTXLATE_H__
+
+#include <errno.h>
+#include <mach.h>
+
+/* A data structure specifying two tasks, and info used to translate port
+ names between them. */
+struct port_name_xlator
+{
+ /* The tasks between which we are translating port names. */
+ mach_port_t from_task;
+ mach_port_t to_task;
+
+ /* True if we're translating receive rights in FROM_TASK; otherwise, we're
+ translating send rights. */
+ int from_is_receive;
+
+ /* Arrays of port names and type masks from TO_TASK, fetched by
+ mach_port_names. These are vm_allocated. */
+ mach_port_t *to_names;
+ mach_msg_type_number_t to_names_len;
+ mach_port_type_t *to_types;
+ mach_msg_type_number_t to_types_len;
+
+ /* An array of rights in the current task to the ports in TO_NAMES/TO_TASK,
+ or MACH_PORT_NULL, indicating that none has been fetched yet.
+ This vector is malloced. */
+ mach_port_t *ports;
+};
+
+/* Return a new port name translator translating names between FROM_TASK and
+ TO_TASK, in XLATOR, or an error. */
+error_t port_name_xlator_create (mach_port_t from_task, mach_port_t to_task,
+ struct port_name_xlator **xlator);
+
+/* Free the port name translator X and any resources it holds. */
+void port_name_xlator_free (struct port_name_xlator *x);
+
+/* Translate the port FROM between the tasks in X, returning the translated
+ name in TO, and the types of TO in TO_TYPE, or an error. If TYPE is
+ non-zero, it should be what mach_port_type returns for FROM. */
+error_t port_name_xlator_xlate (struct port_name_xlator *x,
+ mach_port_t from, mach_port_type_t from_type,
+ mach_port_t *to, mach_port_type_t *to_type);
+
+#endif /* __PORTXLATE_H__ */
diff --git a/libshouldbeinlibc/shared-dom.c b/libshouldbeinlibc/shared-dom.c
new file mode 100644
index 00000000..0f8efdf8
--- /dev/null
+++ b/libshouldbeinlibc/shared-dom.c
@@ -0,0 +1,57 @@
+/* Deduce the shared portion of two hostnames
+
+ Copyright (C) 1996 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 <unistd.h>
+#include <malloc.h>
+#include <string.h>
+#include <errno.h>
+
+/* Returns a pointer into HOST1 that is the part of the domain shared with
+ HOST2. If the two do not share anything, the return value will point to
+ the end of HOST1. If either host is NULL, NULL is returned. */
+char *
+shared_domain (char *host1, char *host2)
+{
+ char *shared, *e1, *e2;
+
+ if (!host1 || !host2)
+ return 0;
+
+ /* Now compare HOST1 and HOST2 from the end. */
+ e2 = host2 + strlen (host2);
+ e1 = host1 + strlen (host1);
+ shared = e1;
+
+ /* Ignore `absolute' syntax. */
+ if (*e1 == '.')
+ e1--;
+ if (*e2 == '.')
+ e2--;
+
+ while (e1 > host1 && e2 > host2 && *e2 == *e1)
+ {
+ if (*e1 == '.')
+ shared = e1; /* A common domain level has been passed. */
+ e1--;
+ e2--;
+ }
+
+ return shared;
+}
diff --git a/libshouldbeinlibc/termsize.c b/libshouldbeinlibc/termsize.c
new file mode 100644
index 00000000..46666975
--- /dev/null
+++ b/libshouldbeinlibc/termsize.c
@@ -0,0 +1,54 @@
+/* Function to try and deduce what size the terminal is
+
+ 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 <sys/ioctl.h>
+
+/* Returns what we think is the size of the terminal attached to
+ file descriptor FD, of type TYPE, in WIDTH and/or HEIGHT. If FD is
+ negative, the terminal isn't queried, and if TYPE is NULL, it isn't used.
+ Both WIDTH and HEIGHT may be NULL if only partial information is needed.
+ True is returned upon success. Even if false is returned, both output
+ values are still written, with 0 for unknown, in case partial information
+ is useful. */
+int
+deduce_term_size (int fd, char *type, int *width, int *height)
+{
+ int w = 0, h = 0;
+ struct winsize ws;
+
+ if (fd >= 0 && ioctl (fd, TIOCGWINSZ, &ws) == 0)
+ /* Look at the actual terminal. */
+ {
+ w = ws.ws_col;
+ h = ws.ws_row;
+ }
+ if (((width && !w) || (height && !h)) && type)
+ /* Try the terminal type. */
+ {
+ /* XXX */
+ }
+
+ if (width)
+ *width = w;
+ if (height)
+ *height = h;
+
+ return (!width || w) && (!height && h);
+}
diff --git a/libshouldbeinlibc/timefmt.c b/libshouldbeinlibc/timefmt.c
new file mode 100644
index 00000000..da4ccde0
--- /dev/null
+++ b/libshouldbeinlibc/timefmt.c
@@ -0,0 +1,358 @@
+/* Routines for formatting time
+
+ Copyright (C) 1995, 1996 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 <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include "timefmt.h"
+
+#define SECOND 1
+#define MINUTE 60
+#define HOUR (60*MINUTE)
+#define DAY (24*HOUR)
+#define WEEK (7*DAY)
+#define MONTH (31*DAY) /* Not strictly accurate, but oh well. */
+#define YEAR (365*DAY) /* ditto */
+
+/* Returns the number of digits in the integer N. */
+static unsigned
+int_len (unsigned n)
+{
+ unsigned len = 1;
+ while (n >= 10)
+ {
+ n /= 10;
+ len++;
+ }
+ return len;
+}
+
+/* Returns TV1 divided by TV2. */
+static unsigned
+tv_div (struct timeval *tv1, struct timeval *tv2)
+{
+ return
+ tv2->tv_sec
+ ? tv1->tv_sec / tv2->tv_sec
+ : (tv1->tv_usec / tv2->tv_usec
+ + (tv1->tv_sec ? tv1->tv_sec * 1000000 / tv2->tv_usec : 0));
+}
+
+/* Returns true if TV is zero. */
+static inline int
+tv_is_zero (struct timeval *tv)
+{
+ return tv->tv_sec == 0 && tv->tv_usec == 0;
+}
+
+/* Returns true if TV1 >= TV2. */
+static inline int
+tv_is_ge (struct timeval *tv1, struct timeval *tv2)
+{
+ return
+ tv1->tv_sec > tv2->tv_sec
+ || (tv1->tv_sec == tv2->tv_sec && tv1->tv_usec >= tv2->tv_usec);
+}
+
+/* Format into BUF & BUF_LEN the time interval represented by TV, trying to
+ make the result less than WIDTH characters wide. The number of characters
+ used is returned. */
+size_t
+fmt_named_interval (struct timeval *tv, size_t width,
+ char *buf, size_t buf_len)
+{
+ struct tscale
+ {
+ struct timeval thresh; /* Minimum time to use this scale. */
+ struct timeval unit; /* Unit this scale is based on. */
+ struct timeval frac_thresh; /* If a emitting a single digit of precision
+ will cause at least this much error, also
+ emit a single fraction digit. */
+ char *sfxs[5]; /* Names to use, in descending length. */
+ }
+ time_scales[] =
+ {
+ {{2*YEAR, 0}, {YEAR, 0}, {MONTH, 0},{" years", "years", "yrs", "y", 0 }},
+ {{3*MONTH, 0}, {MONTH, 0}, {WEEK, 0}, {" months","months","mo", 0 }},
+ {{2*WEEK, 0}, {WEEK, 0}, {DAY, 0}, {" weeks", "weeks", "wks", "w", 0 }},
+ {{2*DAY, 0}, {DAY, 0}, {HOUR, 0}, {" days", "days", "dys", "d", 0 }},
+ {{2*HOUR, 0}, {HOUR, 0}, {MINUTE, 0},{" hours","hours", "hrs", "h", 0 }},
+ {{2*MINUTE, 0},{MINUTE, 0},{1, 0}, {" minutes","min", "mi", "m", 0 }},
+ {{1, 100000}, {1, 0}, {0, 100000},{" seconds", "sec", "s", 0 }},
+ {{1, 0}, {1, 0}, {0, 0}, {" second", "sec", "s", 0 }},
+ {{0, 1100}, {0, 1000}, {0, 100}, {" milliseconds", "ms", 0 }},
+ {{0, 1000}, {0, 1000}, {0, 0}, {" millisecond", "ms", 0 }},
+ {{0, 2}, {0, 1}, {0, 0}, {" microseconds", "us", 0 }},
+ {{0, 1}, {0, 1}, {0, 0}, {" microsecond", "us", 0 }},
+ {{0, 0} }
+ };
+ struct tscale *ts = time_scales;
+
+ if (width <= 0 || width >= buf_len)
+ width = buf_len - 1;
+
+ for (ts = time_scales; !tv_is_zero (&ts->thresh); ts++)
+ if (tv_is_ge (tv, &ts->thresh))
+ {
+ char **sfx;
+ struct timeval *u = &ts->unit;
+ unsigned num = tv_div (tv, u);
+ unsigned frac = 0;
+ unsigned num_len = int_len (num);
+
+ if (num < 10
+ && !tv_is_zero (&ts->frac_thresh)
+ && tv_is_ge (tv, &ts->frac_thresh))
+ /* Calculate another place of prec, but only for low numbers. */
+ {
+ /* TV times 10. */
+ struct timeval tv10 =
+ { tv->tv_sec * 10 + tv->tv_usec / 100000,
+ (tv->tv_usec % 100000) * 10 };
+ frac = tv_div (&tv10, u) - num * 10;
+ if (frac)
+ num_len += 2; /* Account for the extra `.' + DIGIT. */
+ }
+
+ /* While we have a choice, find a suffix that fits in WIDTH. */
+ for (sfx = ts->sfxs; sfx[1]; sfx++)
+ if (num_len + strlen (*sfx) <= width)
+ break;
+
+ if (!sfx[1] && frac)
+ /* We couldn't find a suffix that fits, and we're printing a
+ fraction digit. Sacrifice the fraction to make it fit. */
+ {
+ num_len -= 2;
+ frac = 0;
+ for (sfx = ts->sfxs; sfx[1]; sfx++)
+ if (num_len + strlen (*sfx) <= width)
+ break;
+ }
+
+ if (!sfx[1])
+ /* Still couldn't find a suffix that fits. Oh well, use the best. */
+ sfx--;
+
+ if (frac)
+ return snprintf (buf, buf_len, "%d.%d%s", num, frac, *sfx);
+ else
+ return snprintf (buf, buf_len, "%d%s", num, *sfx);
+ }
+
+ return sprintf (buf, "0"); /* Whatever */
+}
+
+/* Prints the number of units of size UNIT in *SECS, subtracting them from
+ *SECS, to BUF (the result *must* fit!), followed by SUFFIX; if the number
+ of units is zero, however, and *LEADING_ZEROS is false, print nothing (and
+ if something *is* printed, set *LEADING_ZEROS to true). MIN_WIDTH is the
+ minimum *total width* (including other fields) needed to print these
+ units. WIDTH is the amount of (total) space available. The number of
+ characters printed is returned. */
+static size_t
+add_field (int *secs, int unit, int *leading_zeros,
+ size_t min_width, char *suffix,
+ size_t width, char *buf)
+{
+ int units = *secs / unit;
+ if (units || (width >= min_width && *leading_zeros))
+ {
+ *secs -= units * unit;
+ *leading_zeros = 1;
+ return
+ sprintf (buf,
+ (width == min_width ? "%d%s"
+ : width == min_width + 1 ? "%2d%s"
+ : "%02d%s"),
+ units, suffix);
+ }
+ else
+ return 0;
+}
+
+/* Format into BUF & BUF_LEN the time interval represented by TV, using
+ HH:MM:SS notation where possible, with FRAC_PLACES digits after the
+ decimal point, and trying to make the result less than WIDTH characters
+ wide. If LEADING_ZEROS is true, then any fields that are zero-valued, but
+ would fit in the given width are printed. If FRAC_PLACES is negative,
+ then any space remaining after printing the time, up to WIDTH, is used for
+ the fraction. The number of characters used is returned. */
+size_t
+fmt_seconds (struct timeval *tv, int leading_zeros, int frac_places,
+ size_t width, char *buf, size_t buf_len)
+{
+ char *p = buf;
+ int secs = tv->tv_sec;
+
+ if (width <= 0 || width >= buf_len)
+ width = buf_len - 1;
+
+ if (tv->tv_sec > DAY)
+ return fmt_named_interval (tv, width, buf, buf_len);
+
+ if (frac_places > 0)
+ width -= frac_places + 1;
+
+ /* See if this time won't fit at all in fixed format. */
+ if ((secs > 10*HOUR && width < 8)
+ || (secs > HOUR && width < 7)
+ || (secs > 10*MINUTE && width < 5)
+ || (secs > MINUTE && width < 4)
+ || (secs > 10 && width < 2)
+ || width < 1)
+ return fmt_named_interval (tv, width, buf, buf_len);
+
+ p += add_field (&secs, HOUR, &leading_zeros, 7, ":", width, p);
+ p += add_field (&secs, MINUTE, &leading_zeros, 4, ":", width, p);
+ p += add_field (&secs, SECOND, &leading_zeros, 1, "", width, p);
+
+ if (frac_places < 0 && (p - buf) < width - 2)
+ /* If FRAC_PLACES is < 0, then use any space remaining before WIDTH. */
+ frac_places = width - (p - buf) - 1;
+
+ if (frac_places > 0)
+ /* Print fractions of a second. */
+ {
+ int frac = tv->tv_usec, i;
+ for (i = 6; i > frac_places; i--)
+ frac /= 10;
+ return (p - buf) + sprintf (p, ".%0*d", frac_places, frac);
+ }
+ else
+ return (p - buf);
+}
+
+/* Format into BUF & BUF_LEN the time interval represented by TV, using HH:MM
+ notation where possible, and trying to make the result less than WIDTH
+ characters wide. If LEADING_ZEROS is true, then any fields that are
+ zero-valued, but would fit in the given width are printed. The number of
+ characters used is returned. */
+size_t
+fmt_minutes (struct timeval *tv, int leading_zeros,
+ size_t width, char *buf, size_t buf_len)
+{
+ char *p = buf;
+ int secs = tv->tv_sec;
+
+ if (width <= 0 || width >= buf_len)
+ width = buf_len - 1;
+
+ if (secs > DAY)
+ return fmt_named_interval (tv, width, buf, buf_len);
+
+ /* See if this time won't fit at all in fixed format. */
+ if ((secs > 10*HOUR && width < 5)
+ || (secs > HOUR && width < 4)
+ || (secs > 10*MINUTE && width < 2)
+ || width < 1)
+ return fmt_named_interval (tv, width, buf, buf_len);
+
+ p += add_field (&secs, HOUR, &leading_zeros, 4, ":", width, p);
+ p += add_field (&secs, MINUTE, &leading_zeros, 1, "", width, p);
+
+ return p - buf;
+}
+
+/* Format into BUF & BUF_LEN the absolute time represented by TV. An attempt
+ is made to fit the result in less than WIDTH characters, by omitting
+ fields implied by the current time, NOW (if NOW is 0, then no assumption
+ is made, so the resulting times will be somewhat long). The number of
+ characters used is returned. */
+size_t
+fmt_past_time (struct timeval *tv, struct timeval *now,
+ size_t width, char *buf, size_t buf_len)
+{
+ static char *time_fmts[] = { "%-r", "%-l:%M%p", "%-l%p", 0 };
+ static char *week_fmts[] = { "%A", "%a", 0 };
+ static char *month_fmts[] = { "%A %-d", "%a %-d", "%a%-d", 0 };
+ static char *date_fmts[] =
+ { "%A, %-d %B", "%a, %-d %b", "%-d %B", "%-d %b", "%-d%b", 0 };
+ static char *year_fmts[] =
+ { "%A, %-d %B %Y", "%a, %-d %b %Y", "%a, %-d %b %y", "%-d %b %y", "%-d%b%y", 0 };
+ struct tm tm;
+ int used = 0; /* Number of characters generated. */
+ long diff = now ? (now->tv_sec - tv->tv_sec) : tv->tv_sec;
+
+ if (diff < 0)
+ diff = -diff; /* XXX */
+
+ bcopy (localtime ((time_t *) &tv->tv_sec), &tm, sizeof tm);
+
+ if (width <= 0 || width >= buf_len)
+ width = buf_len - 1;
+
+ if (diff < DAY)
+ {
+ char **fmt;
+ for (fmt = time_fmts; *fmt && !used; fmt++)
+ used = strftime (buf, width + 1, *fmt, &tm);
+ if (! used)
+ /* Nothing worked, perhaps WIDTH is too small, but BUF_LEN will work.
+ We know FMT is one past the end the array, so FMT[-1] should be
+ the shortest possible option. */
+ used = strftime (buf, buf_len, fmt[-1], &tm);
+ }
+ else
+ {
+ static char *seps[] = { ", ", " ", "", 0 };
+ char **fmt, **dfmt, **dfmts, **sep;
+
+ if (diff < WEEK)
+ dfmts = week_fmts;
+ else if (diff < MONTH)
+ dfmts = month_fmts;
+ else if (diff < YEAR)
+ dfmts = date_fmts;
+ else
+ dfmts = year_fmts;
+
+ /* This ordering (date varying most quickly, then the separator, then
+ the time) preserves time detail as long as possible, and seems to
+ produce a graceful degradation of the result with decreasing widths. */
+ for (fmt = time_fmts; *fmt && !used; fmt++)
+ for (sep = seps; *sep && !used; sep++)
+ for (dfmt = dfmts; *dfmt && !used; dfmt++)
+ {
+ char whole_fmt[strlen (*dfmt) + strlen (*sep) + strlen (*fmt) + 1];
+ char *end = whole_fmt;
+
+ end = stpcpy (end, *dfmt);
+ end = stpcpy (end, *sep);
+ end = stpcpy (end, *fmt);
+
+ used = strftime (buf, width + 1, whole_fmt, &tm);
+ }
+
+ if (! used)
+ /* No concatenated formats worked, try just date formats. */
+ for (dfmt = dfmts; *dfmt && !used; dfmt++)
+ used = strftime (buf, width + 1, *dfmt, &tm);
+
+ if (! used)
+ /* Absolutely nothing has worked, perhaps WIDTH is too small, but
+ BUF_LEN will work. We know DFMT is one past the end the array, so
+ DFMT[-1] should be the shortest possible option. */
+ used = strftime (buf, buf_len, dfmt[-1], &tm);
+ }
+
+ return used;
+}
diff --git a/libshouldbeinlibc/timefmt.h b/libshouldbeinlibc/timefmt.h
new file mode 100644
index 00000000..134cf56a
--- /dev/null
+++ b/libshouldbeinlibc/timefmt.h
@@ -0,0 +1,58 @@
+/* Routines for formatting time
+
+ Copyright (C) 1995, 1996 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 __TIMEFMT_H__
+#define __TIMEFMT_H__
+
+struct timeval;
+
+/* Format into BUF & BUF_LEN the time interval represented by TV, trying to
+ make the result less than WIDTH characters wide. The number of characters
+ used is returned. */
+size_t fmt_named_interval (struct timeval *tv, size_t width,
+ char *buf, size_t buf_len);
+
+/* Format into BUF & BUF_LEN the time interval represented by TV, using
+ HH:MM:SS notation where possible, with FRAC_PLACES digits after the
+ decimal point, and trying to make the result less than WIDTH characters
+ wide. If LEADING_ZEROS is true, then any fields that are zero-valued, but
+ would fit in the given width are printed. If FRAC_PLACES is negative,
+ then any space remaining after printing the time, up to WIDTH, is used for
+ the fraction. The number of characters used is returned. */
+size_t fmt_seconds (struct timeval *tv, int leading_zeros, int frac_places,
+ size_t width, char *buf, size_t buf_len);
+
+/* Format into BUF & BUF_LEN the time interval represented by TV, using HH:MM
+ notation where possible, and trying to make the result less than WIDTH
+ characters wide. If LEADING_ZEROS is true, then any fields that are
+ zero-valued, but would fit in the given width are printed. The number of
+ characters used is returned. */
+size_t fmt_minutes (struct timeval *tv, int leading_zeros,
+ size_t width, char *buf, size_t buf_len);
+
+/* Format into BUF & BUF_LEN the absolute time represented by TV. An attempt
+ is made to fit the result in less than WIDTH characters, by omitting
+ fields implied by the current time, NOW (if NOW is 0, then no assumptions
+ are made, so the resulting times will be somewhat long). The number of
+ characters used is returned. */
+size_t fmt_past_time (struct timeval *tv, struct timeval *now,
+ size_t width, char *buf, size_t buf_len);
+
+#endif /* __TIMEFMT_H__ */
diff --git a/libshouldbeinlibc/ugids-argp.c b/libshouldbeinlibc/ugids-argp.c
new file mode 100644
index 00000000..809da784
--- /dev/null
+++ b/libshouldbeinlibc/ugids-argp.c
@@ -0,0 +1,154 @@
+/* Parse user and group ids
+
+ Copyright (C) 1997, 1999 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 <hurd.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <argp.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include "ugids.h"
+
+#define OA OPTION_ARG_OPTIONAL
+
+static const struct argp_option options[] =
+{
+ {"user", 'u', "USER", 0, "Add USER to the effective uids"},
+ {"avail-user",'U', "USER", 0, "Add USER to the available uids"},
+ {"group", 'g', "GROUP", 0, "Add GROUP to the effective groups"},
+ {"avail-group",'G',"GROUP", 0, "Add GROUP to the available groups"},
+ { 0 }
+};
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ char id_lookup_buf[1024];
+ struct ugids_argp_params *params = state->input;
+ struct ugids *ugids = params->ugids;
+
+ switch (key)
+ {
+ uid_t uid;
+
+ case 'u':
+ case 'U':
+ case ARGP_KEY_ARG:
+ case ARGP_KEY_END:
+ if (key == ARGP_KEY_ARG && !params->parse_user_args)
+ /* Let someone else parse this argument. */
+ return ARGP_ERR_UNKNOWN;
+
+ if (key == ARGP_KEY_END)
+ {
+ if (ugids_is_empty (ugids))
+ {
+ if (params->default_user >= 0)
+ uid = params->default_user;
+ else if (params->require_ids)
+ {
+ argp_error (state, "No ids specified");
+ return EINVAL;
+ }
+ else
+ break;
+ }
+ else
+ break;
+ }
+ else if (isdigit (*arg))
+ uid = atoi (arg);
+ else if (strcmp (arg, "-") == 0)
+ break;
+ else
+ {
+ struct passwd _pw, *pw;
+ if (getpwnam_r (arg, &_pw, id_lookup_buf, sizeof id_lookup_buf, &pw)
+ == 0)
+ uid = pw->pw_uid;
+ else
+ {
+ argp_failure (state, 10, 0, "%s: Unknown user", arg);
+ return EINVAL;
+ }
+ }
+
+ if (key == ARGP_KEY_ARG || key == ARGP_KEY_END)
+ {
+ /* A user arg, which means add the user, and any appropriate
+ groups. */
+ if (!params->user_args_are_effective
+ && !params->user_args_are_available)
+ return ugids_set_posix_user (ugids, uid);
+ else
+ {
+ error_t err = 0;
+ if (params->user_args_are_effective)
+ err = ugids_add_user (ugids, uid, 0);
+ if (!err && params->user_args_are_available)
+ err = ugids_add_user (ugids, uid, 1);
+ return err;
+ }
+ }
+ else
+ /* Add an individual specific effective/auxiliary uid. */
+ return ugids_add_uid (ugids, uid, key == 'U');
+
+ case 'g':
+ case 'G':
+ if (isdigit (*arg))
+ return ugids_add_gid (ugids, atoi (arg), key == 'G');
+ else
+ {
+ struct group _gr, *gr;
+ if (getgrnam_r (arg, &_gr, id_lookup_buf, sizeof id_lookup_buf, &gr)
+ == 0)
+ return ugids_add_gid (ugids, gr->gr_gid, key == 'G');
+ else
+ {
+ argp_failure (state, 11, 0, "%s: Unknown group", arg);
+ return EINVAL;
+ }
+ }
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+/* Filtering of help output strings for UGIDS_ARGP. */
+static char *
+help_filter (int key, const char *text, void *input)
+{
+ struct ugids_argp_params *params = input;
+
+ /* Describe the optional behavior of parsing normal args as ugids. */
+ if (key == ARGP_KEY_HELP_ARGS_DOC && params->parse_user_args)
+ return strdup ("[USER...]");
+
+ return (char *)text;
+}
+
+/* A parser for selecting a set of ugids. */
+struct argp ugids_argp = { options, parse_opt, 0, 0, 0, help_filter };
diff --git a/libshouldbeinlibc/ugids-auth.c b/libshouldbeinlibc/ugids-auth.c
new file mode 100644
index 00000000..d7ec9daa
--- /dev/null
+++ b/libshouldbeinlibc/ugids-auth.c
@@ -0,0 +1,53 @@
+/* Translate user and group ids to/from auth ports
+
+ Copyright (C) 1997 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 <hurd.h>
+
+#include "ugids.h"
+
+/* Make an auth port from UGIDS and return it in AUTH, using authority in
+ both the auth port FROM and the current auth port. */
+error_t
+ugids_make_auth (const struct ugids *ugids,
+ const auth_t *from, size_t num_from,
+ auth_t *auth)
+{
+ auth_t cur_auth = getauth ();
+ error_t err =
+ auth_makeauth (cur_auth, (auth_t *)from, MACH_MSG_TYPE_COPY_SEND, num_from,
+ ugids->eff_uids.ids, ugids->eff_uids.num,
+ ugids->avail_uids.ids, ugids->avail_uids.num,
+ ugids->eff_gids.ids, ugids->eff_gids.num,
+ ugids->avail_gids.ids, ugids->avail_gids.num,
+ auth);
+ mach_port_deallocate (mach_task_self (), cur_auth);
+ return err;
+}
+
+/* Merge the ids from the auth port AUTH into UGIDS. */
+error_t
+ugids_merge_auth (struct ugids *ugids, auth_t auth)
+{
+ return
+ idvec_merge_auth (&ugids->eff_uids, &ugids->avail_uids,
+ &ugids->eff_gids, &ugids->avail_gids,
+ auth);
+}
diff --git a/libshouldbeinlibc/ugids-imply.c b/libshouldbeinlibc/ugids-imply.c
new file mode 100644
index 00000000..9c2a8a2c
--- /dev/null
+++ b/libshouldbeinlibc/ugids-imply.c
@@ -0,0 +1,35 @@
+/* Calculate implied group ids from user ids
+
+ Copyright (C) 1997 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 "ugids.h"
+
+/* Mark as implied all gids in UGIDS that can be implied from its uids. */
+error_t
+ugids_imply_all (struct ugids *ugids)
+{
+ error_t err;
+ err = idvec_merge_implied_gids (&ugids->imp_eff_gids, &ugids->eff_uids);
+ if (! err)
+ err =
+ idvec_merge_implied_gids (&ugids->imp_avail_gids, &ugids->avail_uids);
+ return err;
+}
diff --git a/libshouldbeinlibc/ugids-merge.c b/libshouldbeinlibc/ugids-merge.c
new file mode 100644
index 00000000..924e1ed9
--- /dev/null
+++ b/libshouldbeinlibc/ugids-merge.c
@@ -0,0 +1,109 @@
+/* Merging of ugids
+
+ Copyright (C) 1997 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 "ugids.h"
+
+static error_t
+_merge_gids (struct idvec *gids, struct idvec *gids_imp,
+ const struct idvec *new, const struct idvec *new_imp)
+{
+ error_t err;
+ /* Gids that exist in both GIDS and NEW can only be implied in the result
+ if they are implied in both; here GIDS_STRONG and NEW_STRONG contain
+ those gids which shouldn't be implied in the result because they are not
+ in either of the sources. */
+ struct idvec gids_strong = IDVEC_INIT;
+ struct idvec new_strong = IDVEC_INIT;
+
+ err = idvec_set (&gids_strong, gids);
+ if (! err)
+ err = idvec_set (&new_strong, new);
+ if (! err)
+ {
+ idvec_subtract (&gids_strong, gids_imp);
+ idvec_subtract (&new_strong, new_imp);
+
+ err = idvec_merge (gids, new);
+ if (! err)
+ {
+ err = idvec_merge (gids_imp, new_imp);
+ if (! err)
+ {
+ idvec_subtract (gids_imp, &gids_strong);
+ idvec_subtract (gids_imp, &new_strong);
+ }
+ }
+ }
+
+ idvec_fini (&gids_strong);
+ idvec_fini (&new_strong);
+
+ return err;
+}
+
+/* Add all ids in NEW to UGIDS. */
+error_t
+ugids_merge (struct ugids *ugids, const struct ugids *new)
+{
+ error_t err;
+ err = idvec_merge (&ugids->eff_uids, &new->eff_uids);
+ if (! err)
+ err = idvec_merge (&ugids->avail_uids, &new->avail_uids);
+ if (! err)
+ err = _merge_gids (&ugids->eff_gids, &ugids->imp_eff_gids,
+ &new->eff_gids, &new->imp_eff_gids);
+ if (! err)
+ err = _merge_gids (&ugids->avail_gids, &ugids->imp_avail_gids,
+ &new->avail_gids, &new->imp_avail_gids);
+ return err;
+}
+
+/* Set the ids in UGIDS to those in NEW. */
+error_t
+ugids_set (struct ugids *ugids, const struct ugids *new)
+{
+ idvec_clear (&ugids->eff_uids);
+ idvec_clear (&ugids->eff_gids);
+ idvec_clear (&ugids->avail_uids);
+ idvec_clear (&ugids->avail_gids);
+ idvec_clear (&ugids->imp_eff_gids);
+ idvec_clear (&ugids->imp_avail_gids);
+ return ugids_merge (ugids, new);
+}
+
+/* Save any effective ids in UGIDS by merging them into the available ids,
+ and removing them from the effective ones. */
+error_t
+ugids_save (struct ugids *ugids)
+{
+ error_t err = idvec_merge (&ugids->avail_uids, &ugids->eff_uids);
+ if (! err)
+ err = _merge_gids (&ugids->avail_gids, &ugids->imp_avail_gids,
+ &ugids->eff_gids, &ugids->imp_eff_gids);
+ if (! err)
+ {
+ idvec_clear (&ugids->eff_uids);
+ idvec_clear (&ugids->eff_gids);
+ idvec_clear (&ugids->imp_eff_gids);
+ }
+ return err;
+}
diff --git a/libshouldbeinlibc/ugids-posix.c b/libshouldbeinlibc/ugids-posix.c
new file mode 100644
index 00000000..35d73e32
--- /dev/null
+++ b/libshouldbeinlibc/ugids-posix.c
@@ -0,0 +1,95 @@
+/* Set posix-compatible ugids
+
+ Copyright (C) 1997 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 "ugids.h"
+
+/* Install UID into UGIDS as the main user, making sure that the posix
+ `real' and `saved' uid slots are filled in, and similarly add all
+ groups to which UID belongs. */
+error_t
+ugids_set_posix_user (struct ugids *ugids, uid_t uid)
+{
+ error_t err;
+ struct idvec imp_gids = IDVEC_INIT;
+ uid_t uids_ids[] = { uid };
+ struct idvec uids = { uids_ids, 1 };
+
+ error_t update_real (struct idvec *avail_ids, uid_t id)
+ {
+ if (avail_ids->num == 0
+ || !idvec_tail_contains (avail_ids, 1, avail_ids->ids[0]))
+ return idvec_insert (avail_ids, 0, id);
+ else
+ avail_ids->ids[0] = id;
+ return 0;
+ }
+
+ idvec_merge_implied_gids (&imp_gids, &uids);
+
+ /* Try to add UID. */
+ err = idvec_insert_only (&ugids->eff_uids, 0, uid); /* Effective */
+ if (! err)
+ err = update_real (&ugids->avail_uids, uid); /* Real */
+ if (! err)
+ err = idvec_insert_only (&ugids->avail_uids, 1, uid); /* Saved */
+
+ if (!err && imp_gids.num > 0)
+ /* Now do the gids. */
+ {
+ /* The main gid associated with UID (usually from /etc/passwd). */
+ gid_t gid = imp_gids.ids[0];
+ /* True if GID was already an available gid. */
+ int gid_was_avail = idvec_contains (&ugids->avail_gids, gid);
+
+ /* Update the implied sets for the gids: they're implied unless
+ they were present as non-implied gids before. Here we
+ remove existing effective gids from the IMP_GIDS before we
+ added it to the implied sets -- if some of those gids were
+ actually implied, they'll already be present in the implied
+ set. */
+ idvec_subtract (&imp_gids, &ugids->eff_gids);
+
+ /* Now add GID, as effective, real, and saved gids. */
+ if (! err) /* Effective */
+ err = idvec_insert_only (&ugids->eff_gids, 0, gid);
+ if (! err) /* Real */
+ err = update_real (&ugids->avail_gids, gid);
+ if (! err) /* Saved */
+ err = idvec_insert_only (&ugids->avail_gids, 1, gid);
+
+ /* Mark GID as implied in the available gids unless it was already
+ present (in which case its implied status is already settled). */
+ if (!err && !gid_was_avail)
+ err = idvec_add (&ugids->imp_avail_gids, gid);
+
+ /* Add the other implied gids to the end of the effective gids. */
+ if (! err)
+ err = idvec_merge (&ugids->eff_gids, &imp_gids);
+ /* And make them implied. */
+ if (! err)
+ err = idvec_merge (&ugids->imp_eff_gids, &imp_gids);
+ }
+
+ idvec_fini (&imp_gids);
+
+ return err;
+}
diff --git a/libshouldbeinlibc/ugids-rep.c b/libshouldbeinlibc/ugids-rep.c
new file mode 100644
index 00000000..3e6e59d5
--- /dev/null
+++ b/libshouldbeinlibc/ugids-rep.c
@@ -0,0 +1,118 @@
+/* String representation of ugids
+
+ Copyright (C) 1997 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 "ugids.h"
+
+/* Return a string representation of the ids in UGIDS. SHOW_VALUES and
+ SHOW_NAMES reflect how each id is printed (if SHOW_NAMES is true values
+ are used where names aren't available); if both are true, the
+ `VALUE(NAME)' format is used. ID_SEP, TYPE_SEP, and HDR_SEP contain the
+ strings that separate, respectively, multiple ids of a particular type
+ (default ","), the various types of ids (default ", "), and the name of
+ each type from its ids (default ": "). The empty string is returned for
+ an empty list, and 0 for an allocation error. */
+char *
+ugids_rep (const struct ugids *ugids, int show_values, int show_names,
+ const char *id_sep, const char *type_sep, const char *hdr_sep)
+{
+ size_t type_sep_len, hdr_sep_len;
+ int first = 1;
+ char *rep = 0; /* Result */
+ size_t len = 0; /* Total length of result. */
+ char *euid_rep = 0, *egid_rep = 0, *auid_rep = 0, *agid_rep = 0;
+
+ /* Calculate the rep for NAME, with ids IDS, returning the rep for the ids
+ in REP, and updates LEN to include everything needed by this type (the
+ length of *REP *plus* the length of NAME and any separators). True is
+ returned unless an allocation error occurs. */
+ int type_rep (const char *name, const struct idvec *ids, int is_group,
+ char **rep)
+ {
+ if (ids->num > 0)
+ {
+ if (first)
+ first = 0;
+ else
+ len += type_sep_len;
+ len += strlen (name);
+ len += hdr_sep_len;
+ *rep =
+ (is_group ? idvec_gids_rep : idvec_uids_rep)
+ (ids, show_values, show_names, id_sep);
+ if (*rep)
+ len += strlen (*rep);
+ else
+ return 0;
+ }
+ return 1;
+ }
+ void add_type_rep (char **to, const char *name, const char *rep)
+ {
+ if (rep)
+ {
+ if (first)
+ first = 0;
+ else
+ *to = stpcpy (*to, type_sep);
+ *to = stpcpy (*to, name);
+ *to = stpcpy (*to, hdr_sep);
+ *to = stpcpy (*to, rep);
+ }
+ }
+
+ if (! type_sep)
+ type_sep = ", ";
+ if (! hdr_sep)
+ hdr_sep = ": ";
+
+ type_sep_len = strlen (type_sep);
+ hdr_sep_len = strlen (hdr_sep);
+
+ if (type_rep ("euids", &ugids->eff_uids, 0, &euid_rep)
+ && type_rep ("egids", &ugids->eff_gids, 1, &egid_rep)
+ && type_rep ("auids", &ugids->avail_uids, 0, &auid_rep)
+ && type_rep ("agids", &ugids->avail_gids, 1, &agid_rep))
+ {
+ char *p = malloc (len + 1);
+ if (p)
+ {
+ rep = p;
+ first = 1;
+ add_type_rep (&p, "euids", euid_rep);
+ add_type_rep (&p, "egids", egid_rep);
+ add_type_rep (&p, "auids", auid_rep);
+ add_type_rep (&p, "agids", agid_rep);
+ }
+ }
+
+ if (euid_rep)
+ free (euid_rep);
+ if (egid_rep)
+ free (egid_rep);
+ if (auid_rep)
+ free (auid_rep);
+ if (agid_rep)
+ free (agid_rep);
+
+ return rep;
+}
diff --git a/libshouldbeinlibc/ugids-subtract.c b/libshouldbeinlibc/ugids-subtract.c
new file mode 100644
index 00000000..eecba20e
--- /dev/null
+++ b/libshouldbeinlibc/ugids-subtract.c
@@ -0,0 +1,130 @@
+/* Subtract one set of user and group ids from another
+
+ Copyright (C) 1997 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 <stdio.h>
+
+#include "ugids.h"
+
+/* Remove the gids in SUB from those in GIDS, except where they are implied
+ in SUB (as represented by SUB_IMP), but not in GIDS (as represented by
+ GIDS_IMP). */
+static
+error_t _sub_gids (struct idvec *gids, struct idvec *gids_imp,
+ const struct idvec *sub, const struct idvec *sub_imp)
+{
+ error_t err;
+ /* What we'll remove from GIDS. */
+ struct idvec delta = IDVEC_INIT;
+ /* Those implied ids in SUB that we *won't* remove, because they're not
+ also implied in GIDS. */
+ struct idvec delta_suppress = IDVEC_INIT;
+
+ err = idvec_set (&delta, sub);
+ if (! err)
+ err = idvec_set (&delta_suppress, sub_imp);
+ if (! err)
+ {
+ /* Don't suppress those implied ids that are implied in both. */
+ idvec_subtract (&delta_suppress, gids_imp);
+ idvec_subtract (&delta, &delta_suppress);
+
+ /* Actually remove the gids. */
+ idvec_subtract (gids, &delta);
+ }
+
+ idvec_fini (&delta);
+ idvec_fini (&delta_suppress);
+
+ return err;
+}
+
+/* Remove the in SUB from those in GIDS, except where they are implied
+ in SUB (as represented by SUB_IMP), but not in GIDS (as represented by
+ GIDS_IMP). */
+static
+error_t _sub (struct idvec *uids, struct idvec *gids, struct idvec *gids_imp,
+ const struct idvec *sub_uids,
+ const struct idvec *sub_gids, const struct idvec *sub_gids_imp)
+{
+ error_t err;
+ struct idvec new_uids = IDVEC_INIT; /* The set of uids after subtraction. */
+ struct idvec no_sub_gids = IDVEC_INIT; /* Gids we *don't* want to remove
+ from GIDS, despite what's in
+ SUB_GIDS. */
+ struct idvec new_sub_gids = IDVEC_INIT;
+ struct idvec new_sub_gids_imp = IDVEC_INIT;
+
+ err = idvec_set (&new_uids, uids);
+ if (! err)
+ err = idvec_set (&new_sub_gids, sub_gids);
+ if (! err)
+ err = idvec_set (&new_sub_gids_imp, sub_gids_imp);
+ if (! err)
+ {
+ idvec_subtract (&new_uids, sub_uids);
+
+ err = idvec_merge_implied_gids (&no_sub_gids, &new_uids);
+ if (! err)
+ {
+ /* NO_SUB_GIDS is the intersection of implied gids in GIDS,
+ implied gids in SUB_GIDS, and implied gids after the subtraction
+ of uids -- we don't want to remove those implied gids because we
+ can't be sure which uids implied them (as there will be
+ appropriately implicative uids left after the subtraction). */
+ idvec_keep (&no_sub_gids, gids_imp);
+ idvec_keep (&no_sub_gids, sub_gids_imp);
+
+ /* Remove those gids we don't want to subtract. */
+ idvec_subtract (&new_sub_gids, &no_sub_gids);
+ idvec_subtract (&new_sub_gids_imp, &no_sub_gids);
+
+ /* Do the group subtraction. */
+ err = _sub_gids (gids, gids_imp, &new_sub_gids, &new_sub_gids_imp);
+ if (! err)
+ /* Finally, if no problems, do the uid subtraction. */
+ err = idvec_set (uids, &new_uids);
+ }
+ }
+
+ idvec_fini (&new_uids);
+ idvec_fini (&no_sub_gids);
+ idvec_fini (&new_sub_gids);
+ idvec_fini (&new_sub_gids_imp);
+
+ return err;
+}
+
+/* Remove the ids in SUB from those in UGIDS. */
+error_t
+ugids_subtract (struct ugids *ugids, const struct ugids *sub)
+{
+ error_t err =
+ _sub (&ugids->eff_uids, &ugids->eff_gids, &ugids->imp_eff_gids,
+ &sub->eff_uids, &sub->eff_gids, &sub->imp_eff_gids);
+
+ if (! err)
+ /* If this second call to _sub fails, ugids will be in an inconsistent
+ state, but oh well. */
+ err = _sub (&ugids->avail_uids, &ugids->avail_gids, &ugids->imp_avail_gids,
+ &sub->avail_uids, &sub->avail_gids, &sub->imp_avail_gids);
+
+ return err;
+}
diff --git a/libshouldbeinlibc/ugids-verify-auth.c b/libshouldbeinlibc/ugids-verify-auth.c
new file mode 100644
index 00000000..91fa06e9
--- /dev/null
+++ b/libshouldbeinlibc/ugids-verify-auth.c
@@ -0,0 +1,190 @@
+/* Verify user/group passwords and authenticate accordingly
+
+ Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+ This file 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <hurd.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <argp.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include <hurd/paths.h>
+#include <hurd/password.h>
+
+#include "ugids.h"
+
+/* Accumulated information from authentication various passwords. */
+struct svma_state
+{
+ /* The password server. */
+ file_t server;
+
+ /* An auth port for each password that was verify by the server. */
+ auth_t *auths;
+ size_t num_auths;
+};
+
+/* Append the auth ports in AUTHS, of length NUM_AUTHS, to the auth port
+ vector in SS, returning 0 if successful, or an error. */
+static error_t
+svma_state_add_auths (struct svma_state *ss,
+ const auth_t *auths, size_t num_auths)
+{
+ auth_t *new = realloc (ss->auths,
+ (ss->num_auths + num_auths) * sizeof (auth_t));
+ if (new)
+ {
+ ss->auths = new;
+ while (num_auths--)
+ ss->auths[ss->num_auths++] = *auths++;
+ return 0;
+ }
+ else
+ return ENOMEM;
+}
+
+/* Get authentication from PASSWORD using the hurd password server. */
+static error_t
+server_verify_make_auth (const char *password,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook)
+{
+ auth_t auth;
+ struct svma_state *svma_state = hook;
+ error_t (*check) (io_t server, uid_t id, const char *passwd, auth_t *auth) =
+ is_group ? password_check_group : password_check_user;
+ error_t err = (*check) (svma_state->server, id, password, &auth);
+
+ if (! err)
+ /* PASSWORD checked out ok; the corresponding authentication is in AUTH. */
+ {
+ err = svma_state_add_auths (svma_state, &auth, 1);
+ if (err)
+ mach_port_deallocate (mach_task_self (), auth);
+ }
+
+ return err;
+}
+
+/* Verify that we have the right to the ids in UGIDS, given that we already
+ possess those in HAVE_UIDS and HAVE_GIDS (asking for passwords where
+ necessary), and return corresponding authentication in AUTH; the auth
+ ports in FROM, of length NUM_FROM, are used to supplement the auth port of
+ the current process if necessary. 0 is returned if access should be
+ allowed, otherwise EINVAL if an incorrect password was entered, or an
+ error relating to resource failure. GETPASS_FN and GETPASS_HOOK are as
+ for the idvec_verify function in <idvec.h>. */
+error_t
+ugids_verify_make_auth (const struct ugids *ugids,
+ const struct idvec *have_uids,
+ const struct idvec *have_gids,
+ char *(*getpass_fn) (const char *prompt,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook),
+ void *getpass_hook,
+ const auth_t *from, size_t num_from,
+ auth_t *auth)
+{
+ error_t err;
+ /* By default, get authentication from the password server. */
+ struct svma_state svma_state;
+ error_t (*verify_fn) (const char *password,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook)
+ = server_verify_make_auth;
+ void *verify_hook = &svma_state;
+
+ /* Try to open the hurd password server. */
+ svma_state.server = file_name_lookup (_SERVERS_PASSWORD, 0, 0);
+
+ if (svma_state.server == MACH_PORT_NULL)
+ /* Can't open the password server, try to use our own authority in
+ the traditional unix manner. */
+ {
+ verify_fn = 0;
+ verify_hook = 0;
+ }
+ else
+ {
+ /* Must initialize list to empty so svma_state_add_auths works. */
+ svma_state.auths = NULL;
+ svma_state.num_auths = 0;
+ }
+
+ /* Check passwords. */
+ err = ugids_verify (ugids, have_uids, have_gids,
+ getpass_fn, getpass_hook, verify_fn, verify_hook);
+
+ if (! err)
+ {
+ /* The user apparently has access to all the ids, try to grant the
+ corresponding authentication. */
+ if (verify_fn)
+ /* Merge the authentication we got from the password server into our
+ result. */
+ {
+ if (num_from > 0)
+ /* Use FROM as well as the passwords to get authentication. */
+ err = svma_state_add_auths (&svma_state, from, num_from);
+
+ if (! err)
+ {
+ auth_t cur_auth = getauth ();
+
+ err =
+ auth_makeauth (cur_auth,
+ svma_state.auths, MACH_MSG_TYPE_COPY_SEND,
+ svma_state.num_auths,
+ ugids->eff_uids.ids, ugids->eff_uids.num,
+ ugids->avail_uids.ids, ugids->avail_uids.num,
+ ugids->eff_gids.ids, ugids->eff_gids.num,
+ ugids->avail_gids.ids, ugids->avail_gids.num,
+ auth);
+ mach_port_deallocate (mach_task_self (), cur_auth);
+
+ /* Avoid deallocating FROM when we clean up SVMA_STATE. */
+ svma_state.num_auths -= num_from;
+ }
+ }
+ else
+ /* Try to authenticate the old fashioned way... */
+ err = ugids_make_auth (ugids, from, num_from, auth);
+ }
+
+ if (verify_fn)
+ /* Clean up any left over state. */
+ {
+ int i;
+
+ /* Get rid of auth ports. */
+ for (i = 0; i < svma_state.num_auths; i++)
+ mach_port_deallocate (mach_task_self (), svma_state.auths[i]);
+
+ /* Close password server. */
+ mach_port_deallocate (mach_task_self (), svma_state.server);
+
+ if (svma_state.num_auths > 0)
+ free (svma_state.auths);
+ }
+
+ return err;
+}
diff --git a/libshouldbeinlibc/ugids-verify.c b/libshouldbeinlibc/ugids-verify.c
new file mode 100644
index 00000000..f9d45c63
--- /dev/null
+++ b/libshouldbeinlibc/ugids-verify.c
@@ -0,0 +1,70 @@
+/* Verify user/group passwords
+
+ Copyright (C) 1997 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 <hurd.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <argp.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include "ugids.h"
+
+/* Verify that we have the right to the ids in UGIDS, given that we already
+ possess those in HAVE_UIDS and HAVE_GIDS, asking for passwords where
+ necessary. 0 is returned if access should be allowed, otherwise
+ EINVAL if an incorrect password was entered, or an error relating to
+ resource failure. The GETPASS_FN, GETPASS_HOOK, VERIFY_FN, and
+ VERIFY_HOOK arguments are as for the idvec_verify function (in <idvec.h>). */
+error_t
+ugids_verify (const struct ugids *ugids,
+ const struct idvec *have_uids, const struct idvec *have_gids,
+ char *(*getpass_fn) (const char *prompt,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook),
+ void *getpass_hook,
+ error_t (*verify_fn) (const char *password,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook),
+ void *verify_hook)
+{
+ error_t err;
+ struct idvec check_uids = IDVEC_INIT; /* User-ids to verify. */
+ struct idvec check_gids = IDVEC_INIT; /* group-ids to verify. */
+
+ err = idvec_merge (&check_uids, &ugids->eff_uids);
+ if (! err)
+ err = idvec_merge (&check_uids, &ugids->avail_uids);
+ if (! err)
+ err = idvec_merge (&check_gids, &ugids->eff_gids);
+ if (! err)
+ err = idvec_merge (&check_gids, &ugids->avail_gids);
+
+ if (! err)
+ err = idvec_verify (&check_uids, &check_gids, have_uids, have_gids,
+ getpass_fn, getpass_hook, verify_fn, verify_hook);
+
+ idvec_fini (&check_uids);
+ idvec_fini (&check_gids);
+
+ return err;
+}
diff --git a/libshouldbeinlibc/ugids-xinl.c b/libshouldbeinlibc/ugids-xinl.c
new file mode 100644
index 00000000..f472e1ec
--- /dev/null
+++ b/libshouldbeinlibc/ugids-xinl.c
@@ -0,0 +1,25 @@
+/* Real definitions for extern inline functions in ugids.h
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#define UGIDS_EI
+#undef __OPTIMIZE__
+#define __OPTIMIZE__
+#include "ugids.h"
diff --git a/libshouldbeinlibc/ugids.c b/libshouldbeinlibc/ugids.c
new file mode 100644
index 00000000..057dcf81
--- /dev/null
+++ b/libshouldbeinlibc/ugids.c
@@ -0,0 +1,97 @@
+/* Frob user and group ids
+
+ Copyright (C) 1997 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 "ugids.h"
+
+/* Return a new ugids structure, or 0 if an allocation error occurs. */
+struct ugids *
+make_ugids ()
+{
+ struct ugids *u = malloc (sizeof (struct ugids));
+ if (u)
+ bzero (u, sizeof *u);
+ return u;
+}
+
+/* Add a new uid to UGIDS. If AVAIL is true, it's added to the avail uids
+ instead of the effective ones. */
+error_t
+ugids_add_uid (struct ugids *ugids, uid_t uid, int avail)
+{
+ return idvec_add_new (avail ? &ugids->avail_uids : &ugids->eff_uids, uid);
+}
+
+/* Add a new gid to UGIDS. If AVAIL is true, it's added to the avail gids
+ instead of the effective ones. */
+error_t
+ugids_add_gid (struct ugids *ugids, gid_t gid, int avail)
+{
+ error_t err =
+ idvec_add_new (avail ? &ugids->avail_gids : &ugids->eff_gids, gid);
+ if (! err)
+ /* Since this gid is now explicit, remove it from the appropiate implied
+ set. */
+ idvec_remove (avail ? &ugids->imp_avail_gids : &ugids->imp_eff_gids,
+ 0, gid);
+ return err;
+}
+
+/* Add UID to UGIDS, plus any gids to which that user belongs. If AVAIL is
+ true, the are added to the avail gids instead of the effective ones. */
+error_t
+ugids_add_user (struct ugids *ugids, uid_t uid, int avail)
+{
+ error_t err;
+ struct idvec imp_gids = IDVEC_INIT;
+ uid_t uids_ids[] = { uid };
+ struct idvec uids = { uids_ids, 1 };
+ struct idvec *gids = avail ? &ugids->avail_gids : &ugids->eff_gids;
+
+ idvec_merge_implied_gids (&imp_gids, &uids);
+
+ /* Now remove any gids we already know about from IMP_GIDS. For gids
+ that weren't in the appropiate implied set before, this will
+ ensure that they remain out after we merge IMP_GIDS into it, and
+ ones that *were*, they will remain so. */
+ idvec_subtract (&imp_gids, gids);
+
+ /* Try to add UID. */
+ err = idvec_add_new (avail ? &ugids->avail_uids : &ugids->eff_uids, uid);
+
+ if (! err)
+ /* Now that we've added UID, we can add appropriate implied gids.
+ [If this fails, UGIDS will be an inconsistent state, but things
+ are probably fucked anyhow] */
+ err =
+ idvec_merge (avail ? &ugids->avail_gids : &ugids->eff_gids,
+ &imp_gids);
+ if (! err)
+ err = idvec_merge ((avail
+ ? &ugids->imp_avail_gids
+ : &ugids->imp_eff_gids),
+ &imp_gids);
+
+ idvec_fini (&imp_gids);
+
+ return err;
+}
diff --git a/libshouldbeinlibc/ugids.h b/libshouldbeinlibc/ugids.h
new file mode 100644
index 00000000..8992724b
--- /dev/null
+++ b/libshouldbeinlibc/ugids.h
@@ -0,0 +1,214 @@
+/* Uid/gid parsing/frobbing
+
+ Copyright (C) 1997 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 __UGIDS_H__
+#define __UGIDS_H__
+
+#include <stdlib.h> /* For inline function stuff. */
+#include <idvec.h>
+
+#ifndef UGIDS_EI
+#define UGIDS_EI extern inline
+#endif
+
+/* A structure holding a set of the common various types of ids. */
+struct ugids
+{
+ struct idvec eff_uids; /* Effective UIDs */
+ struct idvec eff_gids; /* Effective GIDs */
+ struct idvec avail_uids; /* Available UIDs */
+ struct idvec avail_gids; /* Available GIDs */
+
+ /* These should be a subset of EFF/AVAIL_GIDS, containing those gids which
+ are present only by implication from uids in EFF/AVAIL_UIDS. */
+ struct idvec imp_eff_gids;
+ struct idvec imp_avail_gids;
+};
+
+#define UGIDS_INIT { IDVEC_INIT, IDVEC_INIT, IDVEC_INIT, IDVEC_INIT, IDVEC_INIT, IDVEC_INIT }
+
+/* Return a new ugids structure, or 0 if an allocation error occurs. */
+struct ugids *make_ugids ();
+
+/* Free all resources used by UGIDS except UGIDS itself. */
+UGIDS_EI void
+ugids_fini (struct ugids *ugids)
+{
+ idvec_fini (&ugids->eff_uids);
+ idvec_fini (&ugids->eff_gids);
+ idvec_fini (&ugids->avail_uids);
+ idvec_fini (&ugids->avail_gids);
+ idvec_fini (&ugids->imp_eff_gids);
+ idvec_fini (&ugids->imp_avail_gids);
+}
+
+/* Free all resources used by UGIDS. */
+UGIDS_EI void
+ugids_free (struct ugids *ugids)
+{
+ ugids_fini (ugids);
+ free (ugids);
+}
+
+/* Return true if UGIDS contains no ids. */
+UGIDS_EI int
+ugids_is_empty (const struct ugids *ugids)
+{
+ /* We needn't test the imp_*_gids vectors because they are subsets of the
+ corresponding *_gids vectors. */
+ return
+ idvec_is_empty (&ugids->eff_uids)
+ && idvec_is_empty (&ugids->eff_gids)
+ && idvec_is_empty (&ugids->avail_uids)
+ && idvec_is_empty (&ugids->avail_gids);
+}
+
+/* Free all resources used by UGIDS except UGIDS itself. */
+UGIDS_EI int
+ugids_equal (const struct ugids *ugids1, const struct ugids *ugids2)
+{
+ return
+ idvec_equal (&ugids1->eff_uids, &ugids2->eff_uids)
+ && idvec_equal (&ugids1->eff_gids, &ugids2->eff_gids)
+ && idvec_equal (&ugids1->avail_uids, &ugids2->avail_uids)
+ && idvec_equal (&ugids1->avail_gids, &ugids2->avail_gids)
+ && idvec_equal (&ugids1->imp_eff_gids, &ugids2->imp_eff_gids)
+ && idvec_equal (&ugids1->imp_avail_gids, &ugids2->imp_avail_gids);
+}
+
+/* Add all ids in NEW to UGIDS. */
+error_t ugids_merge (struct ugids *ugids, const struct ugids *new);
+
+/* Set the ids in UGIDS to those in NEW. */
+error_t ugids_set (struct ugids *ugids, const struct ugids *new);
+
+/* Remove the ids in SUB from those in UGIDS. */
+error_t ugids_subtract (struct ugids *ugids, const struct ugids *sub);
+
+/* Mark as implied all gids in UGIDS that can be implied from its uids. */
+error_t ugids_imply_all (struct ugids *ugids);
+
+/* Save any effective ids in UGIDS by merging them into the available ids,
+ and removing them from the effective ones. */
+error_t ugids_save (struct ugids *ugids);
+
+/* Verify that we have the right to the ids in UGIDS, given that we already
+ possess those in HAVE_UIDS and HAVE_GIDS, asking for passwords where
+ necessary. 0 is returned if access should be allowed, otherwise
+ EINVAL if an incorrect password was entered, or an error relating to
+ resource failure. The GETPASS_FN, GETPASS_HOOK, VERIFY_FN, and
+ VERIFY_HOOK arguments are as for the idvec_verify function (in <idvec.h>). */
+error_t ugids_verify (const struct ugids *ugids,
+ const struct idvec *have_uids,
+ const struct idvec *have_gids,
+ char *(*getpass_fn) (const char *prompt,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook),
+ void *getpass_hook,
+ error_t (*verify_fn) (const char *password,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook),
+ void *verify_hook);
+
+/* Make an auth port from UGIDS and return it in AUTH, using authority in
+ both the auth port FROM and the current auth port. */
+error_t ugids_make_auth (const struct ugids *ugids,
+ const auth_t *from, size_t num_from,
+ auth_t *auth);
+
+/* Verify that we have the right to the ids in UGIDS, given that we already
+ possess those in HAVE_UIDS and HAVE_GIDS (asking for passwords where
+ necessary), and return corresponding authentication in AUTH; the auth
+ ports in FROM, of length NUM_FROM, are used to supplement the auth port of
+ the current process if necessary. 0 is returned if access should be
+ allowed, otherwise EINVAL if an incorrect password was entered, or an
+ error relating to resource failure. GETPASS_FN and GETPASS_HOOK are as
+ for the idvec_verify function in <idvec.h>. */
+error_t ugids_verify_make_auth (const struct ugids *ugids,
+ const struct idvec *have_uids,
+ const struct idvec *have_gids,
+ char *(*getpass_fn) (const char *prompt,
+ uid_t id, int is_group,
+ void *pwd_or_grp,
+ void *hook),
+ void *getpass_hook,
+ const auth_t *from, size_t num_from,
+ auth_t *auth);
+
+/* Merge the ids from the auth port AUTH into UGIDS. */
+error_t ugids_merge_auth (struct ugids *ugids, auth_t auth);
+
+/* Return a string representation of the ids in UGIDS. SHOW_VALUES and
+ SHOW_NAMES reflect how each id is printed (if SHOW_NAMES is true values
+ are used where names aren't available); if both are true, the
+ `VALUE(NAME)' format is used. ID_SEP, TYPE_SEP, and HDR_SEP contain the
+ strings that separate, respectively, multiple ids of a particular type
+ (default ","), the various types of ids (default ", "), and the name of
+ each type from its ids (default ": "). The empty string is returned for
+ an empty list, and 0 for an allocation error. */
+char *ugids_rep (const struct ugids *ugids, int show_values, int show_names,
+ const char *id_sep, const char *type_sep,
+ const char *hdr_sep);
+
+/* Add a new uid to UGIDS. If AVAIL is true, it's added to the avail uids
+ instead of the effective ones. */
+error_t ugids_add_uid (struct ugids *ugids, uid_t uid, int avail);
+
+/* Add a new gid to UGIDS. If AVAIL is true, it's added to the avail gids
+ instead of the effective ones. */
+error_t ugids_add_gid (struct ugids *ugids, gid_t gid, int avail);
+
+/* Add UID to UGIDS, plus any gids to which that user belongs. If AVAIL is
+ true, the are added to the avail gids instead of the effective ones. */
+error_t ugids_add_user (struct ugids *ugids, uid_t uid, int avail);
+
+/* Install UID into UGIDS as the main user, making sure that the posix
+ `real' and `saved' uid slots are filled in, and similarly add all
+ groups to which UID belongs. */
+error_t ugids_set_posix_user (struct ugids *ugids, uid_t uid);
+
+/* Params to be passed as the input when parsing UGIDS_ARGP. */
+struct ugids_argp_params
+{
+ /* Parsed ids should be added here. */
+ struct ugids *ugids;
+
+ /* If true, parse multiple args as user otherwise, parse none. */
+ int parse_user_args;
+
+ /* If true, and PARSE_USER_ARGS is true, add user args to the available
+ ids, not the effective ones. If both are true, add them to both.
+ If both are false, use the special ugids_set_posix_user instead (which
+ sets both, in a particular way). */
+ int user_args_are_effective;
+ int user_args_are_available;
+
+ /* If >= 0, a user that should be added if none are specified on the
+ command line (following the same rules). */
+ int default_user;
+
+ /* If true, at least one id has to be specified. */
+ int require_ids;
+};
+
+/* A parser for selecting a set of ugids. */
+extern struct argp ugids_argp;
+
+#endif __UGIDS_H__
diff --git a/libshouldbeinlibc/wire.c b/libshouldbeinlibc/wire.c
new file mode 100644
index 00000000..8273ed0d
--- /dev/null
+++ b/libshouldbeinlibc/wire.c
@@ -0,0 +1,163 @@
+/* Function to wire down text and data (including from shared libraries)
+ Copyright (C) 1996, 1999 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG.
+
+ This file 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+
+#include <link.h>
+#include <mach.h>
+#include <hurd.h>
+
+#pragma weak _DYNAMIC
+
+/* Find the list of shared objects */
+static struct link_map *
+loaded (void)
+{
+ Elf32_Dyn *d;
+
+ if (&_DYNAMIC == 0) /* statically linked */
+ return 0;
+
+ for (d = _DYNAMIC; d->d_tag != DT_NULL; ++d)
+ if (d->d_tag == DT_DEBUG)
+ {
+ struct r_debug *r = (void *) d->d_un.d_ptr;
+ return r->r_map;
+ }
+
+ return 0; /* ld broken */
+}
+
+/* Compute the extent of a particular shared object. */
+static Elf32_Addr
+map_extent (struct link_map *map)
+{
+ /* Find the last load cmd; they are in ascending p_vaddr order. */
+ Elf32_Word n = map->l_phnum;
+ while (n-- > 0 && map->l_phdr[n].p_type != PT_LOAD);
+ return map->l_phdr[n].p_vaddr + map->l_phdr[n].p_memsz;
+}
+
+/* Wire down all memory currently allocated at START for LEN bytes;
+ host_priv is the privileged host port. */
+static void
+wire_segment_internal (vm_address_t start,
+ vm_size_t len,
+ host_priv_t host_priv)
+{
+ vm_address_t addr;
+ vm_size_t size;
+ vm_prot_t protection;
+ vm_prot_t max_protection;
+ vm_inherit_t inheritance;
+ boolean_t shared;
+ mach_port_t object_name;
+ vm_offset_t offset;
+ error_t err;
+ volatile char *poke;
+
+ do
+ {
+ addr = start;
+ err = vm_region (mach_task_self (), &addr, &size, &protection,
+ &max_protection, &inheritance, &shared, &object_name,
+ &offset);
+ if (err)
+ return;
+
+ /* The current region begins at ADDR and is SIZE long. If it
+ extends beyond the LEN, prune it. */
+ if (addr + size > start + len)
+ size = len - (addr - start);
+
+ /* Set protection to allow all access possible */
+ vm_protect (mach_task_self (), addr, size, 0, max_protection);
+
+ /* Generate write faults */
+ for (poke = (char *) addr;
+ (vm_address_t) poke < addr + size;
+ poke += vm_page_size)
+ *poke = *poke;
+
+ /* Wire pages */
+ vm_wire (host_priv, mach_task_self (), addr, size, max_protection);
+
+ /* Set protection back to what it was */
+ vm_protect (mach_task_self (), addr, size, 0, protection);
+
+
+ mach_port_deallocate (mach_task_self (), object_name);
+
+ len -= (addr - start) + size;
+ start = addr + size;
+ }
+ while (len);
+}
+
+/* Wire down all memory currently allocated at START for LEN bytes. */
+void
+wire_segment (vm_address_t start,
+ vm_size_t len)
+{
+ mach_port_t host, device;
+ error_t error;
+
+ error = get_privileged_ports (&host, &device);
+ if (!error)
+ {
+ wire_segment_internal (start, len, host);
+ mach_port_deallocate (mach_task_self (), host);
+ mach_port_deallocate (mach_task_self (), device);
+ }
+}
+
+
+/* Wire down all the text and data (including from shared libraries)
+ for the current program. */
+void
+wire_task_self ()
+{
+ struct link_map *map;
+ mach_port_t host, device;
+ error_t error;
+ extern char _edata, _etext, __data_start;
+
+ error = get_privileged_ports (&host, &device);
+ if (error)
+ return;
+
+ map = loaded ();
+ if (!map)
+ {
+ extern void _start ();
+ vm_address_t text_start = (vm_address_t) &_start;
+ wire_segment_internal (text_start,
+ (vm_size_t) (&_etext - text_start),
+ host);
+ wire_segment_internal ((vm_address_t) &__data_start,
+ (vm_size_t) (&_edata - &__data_start),
+ host);
+ }
+ else
+ while (map)
+ wire_segment ((vm_address_t) map->l_addr, map_extent (map));
+
+ mach_port_deallocate (mach_task_self (), host);
+ mach_port_deallocate (mach_task_self (), device);
+}
diff --git a/libshouldbeinlibc/wire.h b/libshouldbeinlibc/wire.h
new file mode 100644
index 00000000..a7f6e899
--- /dev/null
+++ b/libshouldbeinlibc/wire.h
@@ -0,0 +1,27 @@
+/* Function to wire down text and data (including from shared libraries)
+ Copyright (C) 1996 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG.
+
+ This file 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+/* Wire down all the text and data (including from shared libraries)
+ for the current program. */
+void wire_task_self (void);
+
+/* Wire down all memory currently allocated at START for LEN bytes. */
+void wire_segment (vm_address_t start, vm_size_t len);
+
diff --git a/libshouldbeinlibc/xportinfo.c b/libshouldbeinlibc/xportinfo.c
new file mode 100644
index 00000000..bba84a12
--- /dev/null
+++ b/libshouldbeinlibc/xportinfo.c
@@ -0,0 +1,69 @@
+/* Print information about a port, with the name translated between tasks
+
+ Copyright (C) 1996, 1999 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 <sys/types.h>
+#include <sys/mman.h>
+
+#include "portinfo.h"
+
+/* Prints info about NAME translated through X to STREAM, in a way described
+ by the flags in SHOW. If TYPE is non-zero, it should be what
+ mach_port_type returns for NAME in X->to_task. */
+error_t
+print_xlated_port_info (mach_port_t name, mach_port_type_t type,
+ struct port_name_xlator *x,
+ unsigned show, FILE *stream)
+{
+ mach_port_t old_name = name;
+ error_t err = port_name_xlator_xlate (x, name, type, &name, &type);
+ if (! err)
+ {
+ fprintf (stream, (show & PORTINFO_HEX_NAMES) ? "%#6x => " : "%6d => ",
+ old_name);
+ err = print_port_info (name, type, x->to_task, show, stream);
+ }
+ return err;
+}
+
+/* Prints info about every port common to both tasks in X, but only if the
+ port in X->from_task has a type in ONLY, to STREAM. */
+error_t
+print_xlated_task_ports_info (struct port_name_xlator *x,
+ mach_port_type_t only,
+ unsigned show, FILE *stream)
+{
+ mach_port_t *names = 0;
+ mach_port_type_t *types = 0;
+ mach_msg_type_number_t names_len = 0, types_len = 0, i;
+ error_t err =
+ mach_port_names (x->from_task, &names, &names_len, &types, &types_len);
+
+ if (err)
+ return err;
+
+ for (i = 0; i < names_len; i++)
+ if (types[i] & only)
+ print_xlated_port_info (names[i], types[i], x, show, stream);
+
+ munmap ((caddr_t) names, names_len * sizeof *names);
+ munmap ((caddr_t) types, types_len * sizeof *types);
+
+ return 0;
+}