diff options
Diffstat (limited to 'libshouldbeinlibc')
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; +} |