diff options
Diffstat (limited to 'libshouldbeinlibc')
47 files changed, 2429 insertions, 4053 deletions
diff --git a/libshouldbeinlibc/=argz.c b/libshouldbeinlibc/=argz.c deleted file mode 100644 index fd90a1e2..00000000 --- a/libshouldbeinlibc/=argz.c +++ /dev/null @@ -1,190 +0,0 @@ -/* 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 deleted file mode 100644 index 1de0cd64..00000000 --- a/libshouldbeinlibc/=argz.h +++ /dev/null @@ -1,89 +0,0 @@ -/* 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 deleted file mode 100644 index 4d0816e4..00000000 --- a/libshouldbeinlibc/=envz.c +++ /dev/null @@ -1,171 +0,0 @@ -/* 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 deleted file mode 100644 index 55224c72..00000000 --- a/libshouldbeinlibc/=envz.h +++ /dev/null @@ -1,55 +0,0 @@ -/* 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 deleted file mode 100644 index 1c8eab8e..00000000 --- a/libshouldbeinlibc/=line.c +++ /dev/null @@ -1,147 +0,0 @@ -/* 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 deleted file mode 100644 index 54ab15de..00000000 --- a/libshouldbeinlibc/=line.h +++ /dev/null @@ -1,128 +0,0 @@ -/* 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 deleted file mode 100644 index b89f8d4d..00000000 --- a/libshouldbeinlibc/=path-lookup.c +++ /dev/null @@ -1,120 +0,0 @@ -/* 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 deleted file mode 100644 index ab2b938f..00000000 --- a/libshouldbeinlibc/ChangeLog +++ /dev/null @@ -1,614 +0,0 @@ -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 index 1a00dac1..0787d2d6 100644 --- a/libshouldbeinlibc/Makefile +++ b/libshouldbeinlibc/Makefile @@ -1,6 +1,6 @@ # Makefile for libshouldbeinlibc # -# Copyright (C) 1995, 1996 Free Software Foundation, Inc. +# Copyright (C) 1995,96,97,98,99,2002 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 @@ -20,13 +20,17 @@ dir := libshouldbeinlibc makemode := library libname = libshouldbeinlibc -SRCS = argp-parse.c argp-help.c argp-pv.c argp-pvh.c \ - termsize.c idvec.c idvec-auth.c timefmt.c exec-reauth.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 -LCLHDRS = argp.h idvec.h timefmt.h maptime.h \ - wire.h portinfo.h portxlate.h cacheq.h -installhdrs = $(LCLHDRS) +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 = . OBJS = $(SRCS:.c=.o) diff --git a/libshouldbeinlibc/argp-help.c b/libshouldbeinlibc/argp-help.c deleted file mode 100644 index b8b519e2..00000000 --- a/libshouldbeinlibc/argp-help.c +++ /dev/null @@ -1,908 +0,0 @@ -/* Hierarchial argument parsing help output - - 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 <stdlib.h> -#include <string.h> -#include <assert.h> -#include <stdarg.h> -#include <malloc.h> -#include <ctype.h> -#include <linewrap.h> - -#include "argp.h" - -#define SHORT_OPT_COL 2 /* column in which short options start */ -#define LONG_OPT_COL 6 /* column in which long options start */ -#define OPT_DOC_COL 29 /* column in which option text starts */ -#define HEADER_COL 1 /* column in which group headers are printed */ -#define USAGE_INDENT 12 /* indentation of wrapped usage lines */ -#define RMARGIN 79 /* right margin used for wrapping */ - -/* Returns true if OPT hasn't been marked invisible. Visibility only affects - whether OPT is displayed or used in sorting, not option shadowing. */ -#define ovisible(opt) (! ((opt)->flags & OPTION_HIDDEN)) - -/* Returns true if OPT is an alias for an earlier option. */ -#define oalias(opt) ((opt)->flags & OPTION_ALIAS) - -/* Returns true if OPT is the end-of-list marker for a list of options. */ -#define oend(opt) _option_is_end (opt) - -/* Returns true if OPT has a short option. */ -#define oshort(opt) _option_is_short (opt) - -/* - The help format for a particular option is like: - - -xARG, -yARG, --long1=ARG, --long2=ARG Documentation... - - Where ARG will be omitted if there's no argument, for this option, or - will be surrounded by "[" and "]" appropiately if the argument is - optional. The documentation string is word-wrapped appropiately, and if - the list of options is long enough, it will be started on a separate line. - If there are no short options for a given option, the first long option is - indented slighly in a way that's supposed to make most long options appear - to be in a separate column. - - For example (from ps): - - -p PID, --pid=PID List the process PID - --pgrp=PGRP List processes in the process group PGRP - -P, -x, --no-parent Include processes without parents - -Q, --all-fields Don't elide unusable fields (normally if there's - some reason ps can't print a field for any - process, it's removed from the output entirely) - -r, --reverse, --gratuitously-long-reverse-option - Reverse the order of any sort - --session[=SID] Add the processes from the session SID (which - defaults to the sid of the current process) - - The struct argp_option array for the above could look like: - - { - {"pid", 'p', "PID", 0, - "List the process PID"}, - {"pgrp", OPT_PGRP, "PGRP", 0, - "List processes in the process group PGRP"}, - {"no-parent", 'P', 0, 0, - "Include processes without parents"}, - {0, 'x', 0, OPTION_ALIAS}, - {"all-fields",'Q', 0, 0, - "Don't elide unusable fields (normally if there's some reason ps \ -can't print a field for any process, it's removed from the output entirely)"}, - {"reverse", 'r', 0, 0, - "Reverse the order of any sort"}, - {"gratuitously-long-reverse-option", 0, 0, OPTION_ALIAS}, - {"session", OPT_SESS, "SID", OPTION_ARG_OPTIONAL, - "Add the processes from the session SID (which defaults to the sid of \ -the current process)"}, - } - -*/ - -/* Returns true if CH occurs between BEG and END. */ -static int -find_char (char ch, char *beg, char *end) -{ - while (beg < end) - if (*beg == ch) - return 1; - else - beg++; - return 0; -} - -struct hol_entry -{ - /* First option. */ - const struct argp_option *opt; - /* Number of options (including aliases). */ - unsigned num; - - /* A pointers into the HOL's short_options field, to the first short option - letter for this entry. The order of the characters following this point - corresponds to the order of options pointed to by OPT, and there are at - most NUM. A short option recorded in a option following OPT is only - valid if it occurs in the right place in SHORT_OPTIONS (otherwise it's - probably been shadowed by some other entry). */ - char *short_options; - - /* Entries are sorted by their group first, in the order: - 1, 2, ..., n, 0, -m, ..., -2, -1 - and then alphabetically within each group. The default is 0. */ - int group; -}; - -/* A list of options for help. */ -struct hol -{ - /* The number of entries in this hol. If this field is zero, the others - are undefined. */ - unsigned num_entries; - /* An array of hol_entry's. */ - struct hol_entry *entries; - /* A string containing all short options in this HOL. Each entry contains - pointers into this string, so the order can't be messed with blindly. */ - char *short_options; -}; - -/* Create a struct hol from an array of struct argp_option. */ -struct hol *make_hol (const struct argp_option *opt) -{ - char *so; - const struct argp_option *o; - struct hol_entry *entry; - unsigned num_short_options = 0; - struct hol *hol = malloc (sizeof (struct hol)); - - assert (hol); - - hol->num_entries = 0; - - if (opt) - { - int cur_group = 0; - - /* The first option must not be an alias. */ - assert (! oalias (opt)); - - /* Calculate the space needed. */ - for (o = opt; ! oend (o); o++) - { - if (! oalias (o)) - hol->num_entries++; - if (oshort (o)) - num_short_options++; /* This is an upper bound. */ - } - - hol->entries = malloc (sizeof (struct hol_entry) * hol->num_entries); - hol->short_options = malloc (num_short_options + 1); - - assert (hol->entries && hol->short_options); - - /* Fill in the entries. */ - so = hol->short_options; - for (o = opt, entry = hol->entries; ! oend (o); entry++) - { - entry->opt = o; - entry->num = 0; - entry->short_options = so; - entry->group = cur_group = o->group ?: cur_group; - - do - { - entry->num++; - if (oshort (o) && ! find_char (o->key, hol->short_options, so)) - /* O has a valid short option which hasn't already been used.*/ - *so++ = o->key; - o++; - } - while (! oend (o) && oalias (o)); - } - *so = '\0'; /* null terminated so we can find the length */ - } - - return hol; -} - -/* Free HOL and any resources it uses. */ -static void -hol_free (struct hol *hol) -{ - if (hol->num_entries > 0) - { - free (hol->entries); - free (hol->short_options); - } - free (hol); -} - -static inline int -hol_entry_short_iterate (const struct hol_entry *entry, - int (*func)(const struct argp_option *opt, - const struct argp_option *real)) -{ - unsigned nopts; - int val = 0; - const struct argp_option *opt, *real = entry->opt; - char *so = entry->short_options; - - for (opt = real, nopts = entry->num; nopts > 0 && !val; opt++, nopts--) - if (oshort (opt) && *so == opt->key) - { - if (!oalias (opt)) - real = opt; - if (ovisible (opt)) - val = (*func)(opt, real); - so++; - } - - return val; -} - -static inline int -hol_entry_long_iterate (const struct hol_entry *entry, - int (*func)(const struct argp_option *opt, - const struct argp_option *real)) -{ - unsigned nopts; - int val = 0; - const struct argp_option *opt, *real = entry->opt; - - for (opt = real, nopts = entry->num; nopts > 0 && !val; opt++, nopts--) - if (opt->name) - { - if (!oalias (opt)) - real = opt; - if (ovisible (opt)) - val = (*func)(opt, real); - } - - return val; -} - -/* Returns the first valid short option in ENTRY, or 0 if there is none. */ -static char -hol_entry_first_short (const struct hol_entry *entry) -{ - inline int func1 (const struct argp_option *opt, - const struct argp_option *real) - { - return opt->key; - } - return hol_entry_short_iterate (entry, func1); -} - -/* Returns the first valid long option in ENTRY, or 0 if there is none. */ -static const char * -hol_entry_first_long (const struct hol_entry *entry) -{ - const struct argp_option *opt; - unsigned num; - for (opt = entry->opt, num = entry->num; num > 0; opt++, num--) - if (opt->name && ovisible (opt)) - return opt->name; - return 0; -} - -/* Returns the entry in HOL with the long option name NAME, or 0 if there is - none. */ -static struct hol_entry *hol_find_entry (struct hol *hol, char *name) -{ - struct hol_entry *entry = hol->entries; - unsigned num_entries = hol->num_entries; - - while (num_entries-- > 0) - { - const struct argp_option *opt = entry->opt; - unsigned num_opts = entry->num; - - while (num_opts-- > 0) - if (opt->name && ovisible (opt) && strcmp (opt->name, name) == 0) - return entry; - else - opt++; - - entry++; - } - - return 0; -} - -/* If an entry with the long option NAME occurs in HOL, set it's special - sort position to GROUP. */ -static void -hol_set_group (struct hol *hol, char *name, int group) -{ - struct hol_entry *entry = hol_find_entry (hol, name); - if (entry) - entry->group = group; -} - -/* Sort HOL by group and alphabetically by option name (with short options - taking precedence over long). Since the sorting is for display purposes - only, the shadowing of options isn't effected. */ -static void -hol_sort (struct hol *hol) -{ - int entry_cmp (const void *entry1_v, const void *entry2_v) - { - const struct hol_entry *entry1 = entry1_v, *entry2 = entry2_v; - int group1 = entry1->group, group2 = entry2->group; - - if (group1 == group2) - /* Normal comparison. */ - { - int short1 = hol_entry_first_short (entry1); - int short2 = hol_entry_first_short (entry2); - const char *long1 = hol_entry_first_long (entry1); - const char *long2 = hol_entry_first_long (entry2); - - if (!short1 && !short2 && long1 && long2) - /* Only long options. */ - return strcasecmp (long1, long2); - else - /* Compare short/short, long/short, short/long, using the first - character of long options. Entries without *any* valid - options (such as options with OPTION_HIDDEN set) will be put - first, but as they're not displayed, it doesn't matter where - they are. */ - { - char first1 = short1 ?: long1 ? *long1 : 0; - char first2 = short2 ?: long2 ? *long2 : 0; - /* Compare ignoring case, except when the options are both the - same letter, in which case lower-case always comes first. */ - return (tolower (first1) - tolower (first2)) ?: first2 - first1; - } - } - else - /* Order by group: 1, 2, ..., n, 0, -m, ..., -2, -1 */ - if ((group1 < 0 && group2 < 0) || (group1 > 0 && group2 > 0)) - return group1 - group2; - else - return group2 - group1; - } - - if (hol->num_entries > 0) - qsort (hol->entries, hol->num_entries, sizeof (struct hol_entry), - entry_cmp); -} - -/* Append MORE to HOL, destroying MORE in the process. Options in HOL shadow - any in MORE with the same name. */ -static void -hol_append (struct hol *hol, struct hol *more) -{ - if (more->num_entries == 0) - hol_free (more); - else if (hol->num_entries == 0) - { - hol->num_entries = more->num_entries; - hol->entries = more->entries; - hol->short_options = more->short_options; - /* We've stolen everything MORE from more. Destroy the empty shell. */ - free (more); - } - else - /* append the entries in MORE to those in HOL, taking care to only add - non-shadowed SHORT_OPTIONS values. */ - { - unsigned left; - char *so, *more_so; - struct hol_entry *e; - unsigned num_entries = hol->num_entries + more->num_entries; - struct hol_entry *entries = - malloc (num_entries * sizeof (struct hol_entry)); - unsigned hol_so_len = strlen (hol->short_options); - char *short_options = - malloc (hol_so_len + strlen (more->short_options) + 1); - - bcopy (hol->entries, entries, - hol->num_entries * sizeof (struct hol_entry)); - bcopy (more->entries, entries + hol->num_entries, - more->num_entries * sizeof (struct hol_entry)); - - bcopy (hol->short_options, short_options, hol_so_len); - - /* Fix up the short options pointers from HOL. */ - for (e = entries, left = hol->num_entries; left > 0; e++, left--) - e->short_options += (short_options - hol->short_options); - - /* Now add the short options from MORE, fixing up its entries too. */ - so = short_options + hol_so_len; - more_so = more->short_options; - for (left = more->num_entries; left > 0; e++, left--) - { - int opts_left; - const struct argp_option *opt; - - e->short_options = so; - - for (opts_left = e->num, opt = e->opt; opts_left; opt++, opts_left--) - { - int ch = *more_so; - if (oshort (opt) && ch == opt->key) - /* The next short option in MORE_SO, CH, is from OPT. */ - { - if (! find_char (ch, - short_options, short_options + hol_so_len)) - /* The short option CH isn't shadowed by HOL's options, - so add it to the sum. */ - *so++ = ch; - more_so++; - } - } - } - - *so = '\0'; - - free (hol->entries); - free (hol->short_options); - - hol->entries = entries; - hol->num_entries = num_entries; - hol->short_options = short_options; - - hol_free (more); - } -} - -/* Inserts enough spaces to make sure STREAM is at column COL. */ -static void -indent_to (FILE *stream, unsigned col) -{ - int needed = col - line_wrap_point (stream); - while (needed-- > 0) - putc (' ', stream); -} - -/* Print help for ENTRY to STREAM. *LAST_ENTRY should contain the last entry - printed before this, or null if it's the first, and if ENTRY is in a - different group, and *SEP_GROUPS is true, then a blank line will be - printed before any output. *SEP_GROUPS is also set to true if a - user-specified group header is printed. */ -static void -hol_entry_help (struct hol_entry *entry, FILE *stream, - struct hol_entry **prev_entry, int *sep_groups) -{ - unsigned num; - int first = 1; /* True if nothing's been printed so far. */ - const struct argp_option *real = entry->opt, *opt; - char *so = entry->short_options; - int old_lm = line_wrap_set_lmargin (stream, 0); - int old_wm = line_wrap_set_wmargin (stream, 0); - - /* Inserts a comma if this isn't the first item on the line, and then makes - sure we're at least to column COL. Also clears FIRST. */ - void comma (unsigned col) - { - if (first) - { - if (sep_groups && *sep_groups - && prev_entry && *prev_entry - && entry->group != (*prev_entry)->group) - putc ('\n', stream); - first = 0; - } - else - fputs (", ", stream); - indent_to (stream, col); - } - - /* If the option REAL has an argument, we print it in using the printf - format REQ_FMT or OPT_FMT depending on whether it's a required or - optional argument. */ - void arg (char *req_fmt, char *opt_fmt) - { - if (real->arg) - if (real->flags & OPTION_ARG_OPTIONAL) - fprintf (stream, opt_fmt, real->arg); - else - fprintf (stream, req_fmt, real->arg); - } - - /* First emit short options. */ - line_wrap_set_wmargin (stream, SHORT_OPT_COL); /* For truly bizarre cases. */ - for (opt = real, num = entry->num; num > 0; opt++, num--) - if (oshort (opt) && opt->key == *so) - /* OPT has a valid (non shadowed) short option. */ - { - if (ovisible (opt)) - { - comma (SHORT_OPT_COL); - putc ('-', stream); - putc (*so, stream); - arg (" %s", "[%s]"); - } - so++; - } - - /* Now, long options. */ - line_wrap_set_wmargin (stream, LONG_OPT_COL); - for (opt = real, num = entry->num; num > 0; opt++, num--) - if (opt->name && ovisible (opt)) - { - comma (LONG_OPT_COL); - fprintf (stream, "--%s", opt->name); - arg ("=%s", "[=%s]"); - } - - line_wrap_set_lmargin (stream, 0); - if (first) - /* Didn't print any switches, what's up? */ - if (!oshort (real) && !real->name && real->doc) - /* This is a group header, print it nicely. */ - { - if (*real->doc) - { - if (prev_entry && *prev_entry) - putc ('\n', stream); /* Precede with a blank line. */ - indent_to (stream, HEADER_COL); - line_wrap_set_lmargin (stream, HEADER_COL); - line_wrap_set_wmargin (stream, HEADER_COL); - fputs (real->doc, stream); - } - if (sep_groups) - *sep_groups = 1; /* Separate subsequent groups. */ - } - else - /* Just a totally shadowed option or null header; print nothing. */ - goto cleanup; /* Just return, after cleaning up. */ - else if (real->doc) - /* Now the option documentation. */ - { - unsigned col = line_wrap_point (stream); - const char *doc = real->doc; - - line_wrap_set_lmargin (stream, OPT_DOC_COL); - line_wrap_set_wmargin (stream, OPT_DOC_COL); - - if (col > OPT_DOC_COL + 3) - putc ('\n', stream); - else if (col >= OPT_DOC_COL) - fprintf (stream, " "); - else - indent_to (stream, OPT_DOC_COL); - - fputs (doc, stream); - } - - line_wrap_set_lmargin (stream, 0); /* Don't follow the nl with spaces. */ - putc ('\n', stream); - - if (prev_entry) - *prev_entry = entry; - -cleanup: - line_wrap_set_lmargin (stream, old_lm); - line_wrap_set_wmargin (stream, old_wm); -} - -/* Output a long help message about the options in HOL to STREAM. */ -static void -hol_help (struct hol *hol, FILE *stream) -{ - unsigned num; - struct hol_entry *entry; - struct hol_entry *last_entry = 0; - int sep_groups = 0; /* True if we should separate different - sections with blank lines. */ - for (entry = hol->entries, num = hol->num_entries; num > 0; entry++, num--) - hol_entry_help (entry, stream, &last_entry, &sep_groups); -} - -/* Print a short usage description for the arguments in HOL to STREAM. */ -static void -hol_usage (struct hol *hol, FILE *stream) -{ - if (hol->num_entries > 0) - { - unsigned nentries; - struct hol_entry *entry; - char *short_no_arg_opts = alloca (strlen (hol->short_options) + 1); - char *snao_end = short_no_arg_opts; - - /* First we put a list of short options without arguments. */ - for (entry = hol->entries, nentries = hol->num_entries - ; nentries > 0 - ; entry++, nentries--) - { - inline int func2 (const struct argp_option *opt, - const struct argp_option *real) - { - if (! (opt->arg || real->arg)) - *snao_end++ = opt->key; - return 0; - } - hol_entry_short_iterate (entry, func2); - } - if (snao_end > short_no_arg_opts) - { - *snao_end++ = 0; - fprintf (stream, " [-%s]", short_no_arg_opts); - } - - /* Now a list of short options *with* arguments. */ - for (entry = hol->entries, nentries = hol->num_entries - ; nentries > 0 - ; entry++, nentries--) - { - inline int func3 (const struct argp_option *opt, - const struct argp_option *real) - { - if (opt->arg || real->arg) - if ((opt->flags | real->flags) & OPTION_ARG_OPTIONAL) - fprintf (stream, " [-%c[%s]]", - opt->key, opt->arg ?: real->arg); - else - { - const char *arg = opt->arg ?: real->arg; - /* Manually do line wrapping so that it (probably) won't - get wrapped at the embedded space. */ - if (line_wrap_point (stream) + 6 + strlen (arg) - >= line_wrap_rmargin (stream)) - putc ('\n', stream); - else - putc (' ', stream); - fprintf (stream, "[-%c %s]", opt->key, arg); - } - return 0; - } - hol_entry_short_iterate (entry, func3); - } - - /* Finally, a list of long options (whew!). */ - for (entry = hol->entries, nentries = hol->num_entries - ; nentries > 0 - ; entry++, nentries--) - { - int func4 (const struct argp_option *opt, - const struct argp_option *real) - { - if (opt->arg || real->arg) - if ((opt->flags | real->flags) & OPTION_ARG_OPTIONAL) - fprintf (stream, " [--%s[=%s]]", - opt->name, opt->arg ?: real->arg); - else - fprintf (stream, " [--%s=%s]", - opt->name, opt->arg ?: real->arg); - else - fprintf (stream, " [--%s]", opt->name); - return 0; - } - hol_entry_long_iterate (entry, func4); - } - } -} - -/* Make a HOL containing all levels of options in ARGP. */ -static struct hol * -argp_hol (const struct argp *argp) -{ - const struct argp **children = argp->children; - struct hol *hol = make_hol (argp->options); - if (children) - while (*children) - hol_append (hol, argp_hol (*children++)); - return hol; -} - -/* Print all the non-option args documented in ARGP to STREAM. Any output is - preceded by a space. */ -static void -argp_args_usage (const struct argp *argp, FILE *stream) -{ - const struct argp **children = argp->children; - const char *doc = argp->args_doc; - if (doc) - { - /* Manually do line wrapping so that it (probably) won't get wrapped at - any embedded spaces. */ - if (line_wrap_point (stream) + 1 + strlen (doc) - >= line_wrap_rmargin (stream)) - putc ('\n', stream); - else - putc (' ', stream); - fputs (doc, stream); - } - if (children) - while (*children) - argp_args_usage (*children++, stream); -} - -/* Print the documentation for ARGP to STREAM. Each separate bit of - documentation is preceded by a blank line. */ -static void -argp_doc (const struct argp *argp, FILE *stream) -{ - const struct argp **children = argp->children; - const char *doc = argp->doc; - if (doc) - { - putc ('\n', stream); - fputs (doc, stream); - if (line_wrap_point (stream) > line_wrap_lmargin (stream)) - putc ('\n', stream); - } - if (children) - while (*children) - argp_doc (*children++, stream); -} - -/* Output a usage message for ARGP to STREAM. FLAGS are from the set - ARGP_HELP_*. NAME is what to use wherever a `program name' is needed. */ -void argp_help (const struct argp *argp, FILE *stream, - unsigned flags, char *name) -{ - int first = 1; - struct hol *hol = 0; - - if (! stream) - return; - - stream = line_wrap_stream (stream, 0, RMARGIN, 0); - assert (stream); - - if (flags & (ARGP_HELP_USAGE | ARGP_HELP_SHORT_USAGE | ARGP_HELP_LONG)) - { - hol = argp_hol (argp); - - /* If present, these options always come last. */ - hol_set_group (hol, "help", -1); - hol_set_group (hol, "version", -1); - - hol_sort (hol); - } - - if (flags & (ARGP_HELP_USAGE | ARGP_HELP_SHORT_USAGE)) - /* Print a short `Usage:' message. */ - { - int old_lm; - int old_wm = line_wrap_set_wmargin (stream, USAGE_INDENT); - - fprintf (stream, "Usage: %s", name); - - /* We set the lmargin as well as the wmargin, because hol_usage - manually wraps options with newline to avoid annoying breaks. */ - old_lm = line_wrap_set_lmargin (stream, USAGE_INDENT); - - if (flags & ARGP_HELP_SHORT_USAGE) - /* Just show where the options go. */ - { - if (hol->num_entries > 0) - fputs (" [OPTION...]", stream); - } - else - /* Actually print the options. */ - hol_usage (hol, stream); - argp_args_usage (argp, stream); - - line_wrap_set_wmargin (stream, old_wm); - line_wrap_set_lmargin (stream, old_lm); - - putc ('\n', stream); - first = 0; - } - - if (flags & ARGP_HELP_SEE) - { - fprintf (stream, "Try `%s --help' for more information.\n", name); - first = 0; - } - - if (flags & ARGP_HELP_LONG) - /* Print a long, detailed help message. */ - { - /* Print info about all the options. */ - if (hol->num_entries > 0) - { - if (! first) - putc ('\n', stream); - hol_help (hol, stream); - first = 0; - } - - /* Finally, print any documentation strings at the end. */ - argp_doc (argp, stream); - } - - if (hol) - hol_free (hol); - - line_unwrap_stream (stream); -} - -/* Output, if appropriate, a usage message for STATE to STREAM. FLAGS are - from the set ARGP_HELP_*. */ -void -argp_state_help (struct argp_state *state, FILE *stream, unsigned flags) -{ - if ((!state || ! (state->flags & ARGP_NO_ERRS)) && stream) - { - argp_help (state ? state->argp : 0, stream, flags, - state ? state->name : program_invocation_name); - - if (!state || ! (state->flags & ARGP_NO_EXIT)) - { - if (flags & ARGP_HELP_EXIT_ERR) - exit (1); - if (flags & ARGP_HELP_EXIT_OK) - exit (0); - } - } -} - -/* If appropriate, print the printf string FMT and following args, preceded - by the program name and `:', to stderr, and followed by a `Try ... --help' - message, then exit (1). */ -void -argp_error (struct argp_state *state, const char *fmt, ...) -{ - if (!state || !(state->flags & ARGP_NO_ERRS)) - { - FILE *stream = state ? state->err_stream : stderr; - - if (stream) - { - va_list ap; - - fputs (program_invocation_name, stream); - putc (':', stream); - putc (' ', stream); - - va_start (ap, fmt); - vfprintf (stream, fmt, ap); - va_end (ap); - - putc ('\n', stream); - - argp_state_help (state, stream, ARGP_HELP_STD_ERR); - } - } -} - -/* Similar to the standard gnu error-reporting function error(), but will - respect the ARGP_NO_EXIT and ARGP_NO_ERRS flags in STATE, and will print - to STATE->err_stream. This is useful for argument parsing code that is - shared between program startup (when exiting is desired) and runtime - option parsing (when typically an error code is returned instead). The - difference between this function and argp_error is that the latter is for - *parsing errors*, and the former is for other problems that occur during - parsing but don't reflect a (syntactic) problem with the input. */ -void -argp_failure (struct argp_state *state, int status, int errnum, - const char *fmt, ...) -{ - if (!state || !(state->flags & ARGP_NO_ERRS)) - { - FILE *stream = state ? state->err_stream : stderr; - - if (stream) - { - fputs (state ? state->name : program_invocation_name, stream); - - if (fmt) - { - va_list ap; - - putc (':', stream); - putc (' ', stream); - - va_start (ap, fmt); - vfprintf (stream, fmt, ap); - va_end (ap); - } - - if (errnum) - { - putc (':', stream); - putc (' ', stream); - fputs (strerror (errnum), stream); - } - - putc ('\n', stream); - - if (status) - exit (status); - } - } -} diff --git a/libshouldbeinlibc/argp-parse.c b/libshouldbeinlibc/argp-parse.c deleted file mode 100644 index 73b28f06..00000000 --- a/libshouldbeinlibc/argp-parse.c +++ /dev/null @@ -1,662 +0,0 @@ -/* Hierarchial argument parsing, layered over getopt - - 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 <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <limits.h> -#include <getopt.h> -#include <cthreads.h> - -#include "argp.h" - -/* Getopt return values. */ -#define KEY_END (-1) /* The end of the options. */ -#define KEY_ARG 1 /* A non-option argument. */ -#define KEY_ERR '?' /* An error parsing the options. */ - -/* The meta-argument used to prevent any further arguments being interpreted - as options. */ -#define QUOTE "--" - -/* 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) - -/* EZ alias for ARGP_ERR_UNKNOWN. */ -#define EBADKEY ARGP_ERR_UNKNOWN - -/* ---------------------------------------------------------------- */ -/* Default options. */ - -/* When argp is given the --HANG switch, _ARGP_HANG is set and argp will sleep - for one second intervals, decrementing _ARGP_HANG until it's zero. Thus - you can force the program to continue by attaching a debugger and setting - it to 0 yourself. */ -volatile int _argp_hang = 0; - -#define OPT_PROGNAME -2 -#define OPT_USAGE -3 -#define OPT_HANG -4 - -static const struct argp_option argp_default_options[] = -{ - {"help", '?', 0, 0, "Give this help list", -1}, - {"usage", OPT_USAGE, 0, 0, "Give a short usage message"}, - {"program-name",OPT_PROGNAME,"NAME", OPTION_HIDDEN, "Set the program name"}, - {"HANG", OPT_HANG, "SECS", OPTION_ARG_OPTIONAL | OPTION_HIDDEN, - "Hang for SECS seconds (default 3600)"}, - {0, 0} -}; - -static error_t -argp_default_parser (int key, char *arg, struct argp_state *state) -{ - switch (key) - { - case '?': - argp_state_help (state, state->out_stream, ARGP_HELP_STD_HELP); - break; - case OPT_USAGE: - argp_state_help (state, state->out_stream, - ARGP_HELP_USAGE | ARGP_HELP_EXIT_OK); - break; - - case OPT_PROGNAME: /* Set the program name. */ - program_invocation_name = arg; - program_invocation_short_name = rindex (arg, '/'); - if (program_invocation_short_name) - program_invocation_short_name++; - else - program_invocation_short_name = program_invocation_name; - - if ((state->flags & (ARGP_PARSE_ARGV0 | ARGP_NO_ERRS)) - == ARGP_PARSE_ARGV0) - state->argv[0] = arg; /* Update what getopt uses too. */ - - break; - - case OPT_HANG: - _argp_hang = atoi (arg ?: "3600"); - while (_argp_hang-- > 0) - sleep (1); - break; - - default: - return EBADKEY; - } - return 0; -} - -static const struct argp argp_default_argp = - {argp_default_options, &argp_default_parser}; - - -static const struct argp_option argp_version_options[] = -{ - {"version", 'V', 0, 0, "Print program version", -1}, - {0, 0} -}; - -static error_t -argp_version_parser (int key, char *arg, struct argp_state *state) -{ - switch (key) - { - case 'V': - if (argp_program_version_hook) - (*argp_program_version_hook) (state->out_stream, state); - else if (argp_program_version) - fprintf (state->out_stream, "%s\n", argp_program_version); - else - argp_error (state, "No version known!?"); - if (! (state->flags & ARGP_NO_EXIT)) - exit (0); - break; - default: - return EBADKEY; - } - return 0; -} - -static const struct argp argp_version_argp = - {argp_version_options, &argp_version_parser}; - -/* ---------------------------------------------------------------- */ - -/* Returns the offset into the getopt long options array 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; - -/* This hack to allow programs that know what's going on to call argp - recursively. If someday argp is changed not to use the non-reentrant - getopt interface, we can get rid of this shit. XXX */ -void -_argp_unlock_xxx () -{ - mutex_unlock (&getopt_lock); -} - -/* The state of a `group' during parsing. Each group corresponds to a - particular argp structure from the tree of such descending from the top - level argp passed to argp_parse. */ -struct group -{ - /* This group's parsing function. */ - argp_parser_t parser; - - /* Points to the point in SHORT_OPTS corresponding to the end of the short - options for this group. We use it to determine from which group a - particular short options is from. */ - char *short_end; - - /* The number of non-option args sucessfully handled by this parser. */ - unsigned args_processed; - - /* This group's parser's parent's group. */ - struct group *parent; - unsigned parent_index; /* And the our position in the parent. */ - - /* These fields are swapped into and out of the state structure when - calling this group's parser. */ - void *input, **child_inputs; - void *hook; -}; - -/* Parse the options strings in ARGC & ARGV according to the argp in - ARGP. FLAGS is one of the ARGP_ 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 -argp_parse (const struct argp *argp, int argc, char **argv, unsigned flags, - int *end_index, void *input) -{ - error_t err = 0; - /* True if we think using getopt is still useful; if false, then - remaining arguments are just passed verbatim with ARGP_KEY_ARG. This is - cleared whenever getopt returns KEY_END, but may be set again if the user - moves the next argument pointer backwards. */ - int try_getopt = 1; - /* If true, then err == EBADKEY is a result of a non-option argument failing - to be parsed (which in some cases isn't actually an error). */ - int arg_ebadkey = 0; - /* SHORT_OPTS is the getopt short options string for the union of all the - groups of options. */ - char *short_opts; - /* LONG_OPTS is the array of getop long option structures for the union of - all the groups of options. */ - struct option *long_opts; - /* States of the various parsing groups. */ - struct group *groups; - /* The end of the GROUPS array. */ - struct group *egroup; - /* A pointer for people to use for iteration over GROUPS. */ - struct group *group; - /* An vector containing storage for the CHILD_INPUTS field in all groups. */ - void **child_inputs; - /* State block supplied to parsing routines. */ - struct argp_state state = - { argp, argc, argv, 0, flags, err_stream: stderr, out_stream: stdout }; - - /* Call GROUP's parser with KEY and ARG, swapping any group-specific info - from STATE before calling, and back into state afterwards. If GROUP has - no parser, EBADKEY is returned. */ - error_t group_parse (struct group *group, int key, char *arg) - { - if (group->parser) - { - error_t err; - state.hook = group->hook; - state.input = group->input; - state.child_inputs = group->child_inputs; - state.arg_num = group->args_processed; - err = (*group->parser)(key, arg, &state); - group->hook = state.hook; - return err; - } - else - return EBADKEY; - } - - /* Parse the non-option argument ARG, at the current position. Returns - any error, and sets ARG_EBADKEY to true if return EBADKEY. */ - error_t process_arg (char *val, int *arg_ebadkey) - { - int index = state.next; - error_t err = EBADKEY; - - for (group = groups; group < egroup && err == EBADKEY; group++) - err = group_parse (group, ARGP_KEY_ARG, val); - - if (!err) - if (state.next >= index) - /* Remember that we successfully processed a non-option - argument -- but only if the user hasn't gotten tricky and set - the clock back. */ - (--group)->args_processed++; - else - /* The user wants to reparse some args, give getopt another try. */ - try_getopt = 1; - - if (err == EBADKEY) - *arg_ebadkey = 1; - - return err; - } - - /* Parse the option OPT (with argument ARG), at the current position. - Returns any error, and sets ARG_EBADKEY to true if it was actually an - argument and the parser returned EBADKEY. */ - error_t process_opt (int opt, char *val, int *arg_ebadkey) - { - /* The group key encoded in the high bits; 0 for short opts or - group_number + 1 for long opts. */ - int group_key = opt >> USER_BITS; - error_t err = EBADKEY; /* until otherwise asserted */ - - if (group_key == 0) - /* A short option. */ - { - /* By comparing OPT's position in SHORT_OPTS to the various - starting positions in each group's SHORT_END field, we can - determine which group OPT came from. */ - char *short_index = index (short_opts, opt); - if (short_index) - for (group = groups; group < egroup; group++) - if (group->short_end > short_index) - { - err = group_parse (group, opt, optarg); - break; - } - } - else - /* A long option. We use shifts instead of masking for extracting - the user value in order to preserve the sign. */ - err = - group_parse (&groups[group_key - 1], - (opt << GROUP_BITS) >> GROUP_BITS, optarg); - - return err; - } - - if (! (state.flags & ARGP_NO_HELP)) - /* Add our own options. */ - { - const struct argp **plist = alloca (3 * sizeof (struct argp *)); - struct argp *top_argp = alloca (sizeof (struct argp)); - - /* TOP_ARGP has no options, it just serves to group the user & default - argps. */ - bzero (top_argp, sizeof (*top_argp)); - top_argp->children = plist; - - if (state.argp) - *plist++ = state.argp; - *plist++ = &argp_default_argp; - if (argp_program_version || argp_program_version_hook) - *plist++ = &argp_version_argp; - *plist = 0; - - state.argp = top_argp; - } - - /* Find the merged set of getopt options, with keys appropiately prefixed. */ - { - char *short_end; - unsigned short_len = (state.flags & ARGP_NO_ARGS) ? 0 : 1; - struct option *long_end; - unsigned long_len = 0; - unsigned num_groups = 0; - unsigned num_child_inputs = 0; - - /* For ARGP, increments NUM_GROUPS by the total number of argp structures - descended from it, and SHORT_LEN & LONG_LEN by the maximum lengths of - the resulting merged getopt short options string and long-options - array, respectively. */ - void calc_lengths (const struct argp *argp) - { - const struct argp **children = argp->children; - const struct argp_option *opt = argp->options; - - if (opt || argp->parser) - { - num_groups++; - if (opt) - { - int num_opts = 0; - while (!_option_is_end (opt++)) - num_opts++; - short_len += num_opts * 3; /* opt + up to 2 `:'s */ - long_len += num_opts; - } - } - - if (children) - while (*children) - { - calc_lengths (*children++); - num_child_inputs++; - } - } - - /* Converts all options in ARGP (which is put in GROUP) and ancestors - into getopt options stored in SHORT_OPTS and LONG_OPTS; SHORT_END and - LONG_END are the points at which new options are added. Returns the - next unused group entry. */ - struct group *convert_options (const struct argp *argp, - struct group *parent, unsigned parent_index, - struct group *group) - { - /* REAL is the most recent non-alias value of OPT. */ - const struct argp_option *real = argp->options; - const struct argp **children = argp->children; - - if (real || argp->parser) - { - const struct argp_option *opt; - - if (real) - for (opt = real; !_option_is_end (opt); opt++) - { - if (! (opt->flags & OPTION_ALIAS)) - /* OPT isn't an alias, so we can use values from it. */ - real = opt; - - if (_option_is_short (opt)) - /* OPT can be used as a short option. */ - { - *short_end++ = opt->key; - if (real->arg) - { - *short_end++ = ':'; - if (real->flags & OPTION_ARG_OPTIONAL) - *short_end++ = ':'; - } - *short_end = '\0'; /* keep 0 terminated */ - } - - if (opt->name && find_long_option (long_opts, opt->name) < 0) - /* OPT can be used as a long option. */ - { - long_end->name = opt->name; - long_end->has_arg = - (real->arg - ? (real->flags & OPTION_ARG_OPTIONAL - ? optional_argument - : required_argument) - : no_argument); - long_end->flag = 0; - /* 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 = - ((opt->key | real->key) & USER_MASK) - + (((group - groups) + 1) << USER_BITS); - - /* Keep the LONG_OPTS list terminated. */ - (++long_end)->name = NULL; - } - } - - group->parser = argp->parser; - group->short_end = short_end; - group->args_processed = 0; - group->parent = parent; - group->parent_index = parent_index; - group->input = 0; - group->hook = 0; - group->child_inputs = 0; - - if (children) - /* Assign GROUP's CHILD_INPUTS field a slice from CHILD_INPUTS.*/ - { - unsigned num_children = 0; - while (children[num_children]) - num_children++; - group->child_inputs = child_inputs; - child_inputs += num_children; - } - - parent = group++; - } - else - parent = 0; - - if (children) - { - unsigned index = 0; - while (*children) - group = convert_options (*children++, parent, index++, group); - } - - return group; - } - - if (state.argp) - calc_lengths (state.argp); - - short_opts = short_end = alloca (short_len + 1); - if (state.flags & ARGP_IN_ORDER) - *short_end++ = '-'; - else if (state.flags & ARGP_NO_ARGS) - *short_end++ = '+'; - *short_end = '\0'; - - long_opts = long_end = alloca ((long_len + 1) * sizeof (struct option)); - long_end->name = NULL; - - groups = alloca ((num_groups + 1) * sizeof (struct group)); - - child_inputs = alloca (num_child_inputs * sizeof (void *)); - bzero (child_inputs, num_child_inputs * sizeof (void *)); - - if (state.argp) - egroup = convert_options (state.argp, 0, 0, groups); - else - egroup = groups; /* No parsers at all! */ - } - - /* Call each parser for the first time, giving it a chance to propagate - values to child parsers. */ - if (groups < egroup) - groups->input = input; - for (group = groups ; group < egroup && (!err || err == EBADKEY); group++) - { - if (group->parent) - /* If a child parser, get the initial input value from the parent. */ - group->input = group->parent->child_inputs[group->parent_index]; - err = group_parse (group, ARGP_KEY_INIT, 0); - } - if (err == EBADKEY) - err = 0; /* Some parser didn't understand. */ - - /* Getopt is (currently) non-reentrant. */ - mutex_lock (&getopt_lock); - - /* Tell getopt to initialize. */ - state.next = 0; - - if (state.flags & ARGP_NO_ERRS) - { - opterr = 0; - if (state.flags & ARGP_PARSE_ARGV0) - /* 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. */ - state.argv--, state.argc++; - } - else - opterr = 1; /* Print error messages. */ - - if (state.argv == argv && argv[0]) - /* There's an argv[0]; use it for messages. */ - state.name = argv[0]; - else - state.name = program_invocation_name; - - /* Now use getopt on our coalesced options lists. */ - while (! err) - { - int opt; - - if (state.quoted && state.next < state.quoted) - /* The next argument pointer has been moved to before the quoted - region, so pretend we never saw the quoting `--', and give getopt - another chance. If the user hasn't removed it, getopt will just - process it again. */ - state.quoted = 0; - - if (try_getopt && !state.quoted) - /* Give getopt a chance to parse this. */ - { - optind = state.next; /* Put it back in OPTIND for getopt. */ - optopt = KEY_END; /* Distinguish KEY_ERR from a real option. */ - opt = getopt_long (state.argc, state.argv, short_opts, long_opts, 0); - state.next = optind; /* And see what getopt did. */ - - if (opt == KEY_END) - /* Getopt says there are no more options, so stop using - getopt; we'll continue if necessary on our own. */ - { - try_getopt = 0; - if (state.next > 1 - && strcmp (state.argv[state.next - 1], QUOTE) == 0) - /* Not only is this the end of the options, but it's a - `quoted' region, which may have args that *look* like - options, so we definitely shouldn't try to use getopt past - here, whatever happens. */ - state.quoted = state.next; - } - else if (opt == KEY_ERR && optopt != KEY_END) - /* KEY_ERR can have the same value as a valid user short - option, but in the case of a real error, getopt sets OPTOPT - to the offending character, which can never be KEY_END. */ - { - err = EBADKEY; - break; - } - } - else - opt = KEY_END; - - if (opt == KEY_END) - /* We're past what getopt considers the options. */ - if (state.next >= state.argc || (state.flags & ARGP_NO_ARGS)) - break; /* done */ - else - /* A non-option arg. */ - err = process_arg (state.argv[state.next++], &arg_ebadkey); - else if (opt == KEY_ARG) - /* A non-option argument; try each parser in turn. */ - err = process_arg (optarg, &arg_ebadkey); - else - err = process_opt (opt, optarg, &arg_ebadkey); - } - - mutex_unlock (&getopt_lock); - - if (err == EBADKEY && arg_ebadkey) - /* Suppress errors generated by unparsed arguments. */ - err = 0; - - if (!err) - if (state.next == state.argc) - /* We successfully parsed all arguments! Call all the parsers again, - just a few more times... */ - { - for (group = groups; group < egroup && (!err || err==EBADKEY); group++) - if (group->args_processed == 0) - err = group_parse (group, ARGP_KEY_NO_ARGS, 0); - for (group = groups; group < egroup && (!err || err==EBADKEY); group++) - err = group_parse (group, ARGP_KEY_END, 0); - if (err == EBADKEY) - err = 0; /* Some parser didn't understand. */ - } - else if (end_index) - /* Return any remaining arguments to the user. */ - *end_index = state.next; - else - /* No way to return the remaining arguments, they must be bogus. */ - { - if (!(state.flags & ARGP_NO_ERRS) && state.err_stream) - fprintf (state.err_stream, "%s: Too many arguments\n", state.name); - err = EBADKEY; - } - - /* Okay, we're all done, with either an error or success. We only call the - parsers once more, to indicate which one. */ - - if (err) - { - /* Maybe print an error message. */ - if (err == EBADKEY) - argp_state_help (&state, state.err_stream, ARGP_HELP_STD_ERR); - - /* Since we didn't exit, give each parser an error indication. */ - for (group = groups; group < egroup; group++) - group_parse (group, ARGP_KEY_ERROR, 0); - } - else - /* Do final cleanup, including propagating back values from parsers. */ - { - /* We pass over the groups in reverse order so that child groups are - given a chance to do there processing before passing back a value to - the parent. */ - for (group = egroup - 1 - ; group >= groups && (!err || err == EBADKEY) - ; group--) - err = group_parse (group, ARGP_KEY_SUCCESS, 0); - if (err == EBADKEY) - err = 0; /* Some parser didn't understand. */ - } - - if (err == EBADKEY) - err = EINVAL; - - return err; -} diff --git a/libshouldbeinlibc/argp-pvh.c b/libshouldbeinlibc/argp-pvh.c deleted file mode 100644 index a58c1923..00000000 --- a/libshouldbeinlibc/argp-pvh.c +++ /dev/null @@ -1,30 +0,0 @@ -/* Default definition for ARGP_PROGRAM_VERSION_HOOK - - 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. */ - -#include "argp.h" - -/* If set by the user program to a non-zero value, then a default option - --version is added (unless the ARGP_NO_HELP flag is used), which calls - this function with a stream to print the version to and a pointer to the - current parsing state, and then exits (unless the ARGP_NO_EXIT flag is - used). This variable takes precedent over ARGP_PROGRAM_VERSION. */ -void (*argp_program_version_hook) (FILE *stream, struct argp_state *state) = 0; diff --git a/libshouldbeinlibc/argp.h b/libshouldbeinlibc/argp.h deleted file mode 100644 index 9c59c407..00000000 --- a/libshouldbeinlibc/argp.h +++ /dev/null @@ -1,356 +0,0 @@ -/* Hierarchial argument parsing, layered over getopt - - 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 __ARGP_H__ -#define __ARGP_H__ - -#include <stdio.h> -#include <errno.h> -#include <ctype.h> -#include <getopt.h> - -/* A description of a particular option. A pointer to an array of - these is passed in the OPTIONS field of an argp structure. Each option - entry can correspond to one long option and/or one short option; more - names for the same option can be added by following an entry in an option - array with options having the OPTION_ALIAS flag set. */ -struct argp_option -{ - /* The long option name. For more than one name for the same option, you - can use following options with the OPTION_ALIAS flag set. */ - const char *name; - - /* What key is returned for this option. If > 0 and printable, then it's - also accepted as a short option. */ - int key; - - /* If non-NULL, this is the name of the argument associated with this - option, which is required unless the OPTION_ARG_OPTIONAL flag is set. */ - const char *arg; - - /* OPTION_ flags. */ - int flags; - - /* The doc string for this option. If both NAME and KEY are 0, This string - will be printed outdented from the normal option column, making it - useful as a group header (it will be the first thing printed in its - group); in this usage, it's conventional to end the string with a `:'. */ - const char *doc; - - /* The group this option is in. In a long help message, options are sorted - alphabetically within each group, and the groups presented in the order - 1, 2, ..., n, 0, -m, ..., -2, -1. Every entry in an options array with - if this field 0 will inherit the group number of the previous entry, or - zero if it's the first one. Automagic options such as --help are put - into group -1. */ - int group; -}; - -/* The argument associated with this option is optional. */ -#define OPTION_ARG_OPTIONAL 0x1 -/* This option isn't displayed in any help messages. */ -#define OPTION_HIDDEN 0x2 -/* This option is an alias for the closest previous non-alias option. This - means that it will be displayed in the same help entry, and will inherit - fields other than NAME and KEY from the aliased option. */ -#define OPTION_ALIAS 0x4 - -struct argp; /* fwd declare this type */ -struct argp_state; /* " */ - -/* The type of a pointer to an argp parsing function. */ -typedef error_t (*argp_parser_t)(int key, char *arg, struct argp_state *state); - -/* What to return for unrecognized keys. For special ARGP_KEY_ keys, such - returns will simply be ignored. For user keys, this error will be turned - into EINVAL (if the call to argp_parse is such that errors are propagated - back to the user instead of exiting); returning EINVAL itself would result - in an immediate stop to parsing in *all* cases. */ -#define ARGP_ERR_UNKNOWN E2BIG /* Hurd should never need E2BIG. XXX */ - -/* Special values for the KEY argument to an argument parsing function. - ARGP_ERR_UNKNOWN should be returned if they aren't understood. - - The sequence of keys to parser calls is either (where opt is a user key): - ARGP_KEY_INIT (opt | ARGP_KEY_ARG)... ARGP_KEY_END - or ARGP_KEY_INIT opt... ARGP_KEY_NO_ARGS ARGP_KEY_END - - If an error occurs, then the parser is called with ARGP_KEY_ERR, and no - other calls are made. */ - -/* This is not an option at all, but rather a command line argument. If a - parser receiving this key returns success, the fact is recorded, and the - ARGP_KEY_NO_ARGS case won't be used. HOWEVER, if while processing the - argument, a parser function decrements the NEXT field of the state it's - passed, the option won't be considered processed; this is to allow you to - actually modify the argument (perhaps into an option), and have it - processed again. */ -#define ARGP_KEY_ARG 0 -/* There are no more command line arguments at all. */ -#define ARGP_KEY_END 1 -/* Because it's common to want to do some special processing if there aren't - any non-option args, user parsers are called with this key if they didn't - successfully process any non-option arguments. Called just before - ARGP_KEY_END (where more general validity checks on previously parsed - arguments can take place). */ -#define ARGP_KEY_NO_ARGS 2 -/* Passed in before any parsing is done. Afterwards, the values of each - element of the CHILD_INPUT field, if any, in the state structure is - copied to each child's state to be the initial value of the INPUT field. */ -#define ARGP_KEY_INIT 3 -/* Passed in when parsing has successfully been completed (even if there are - still arguments remaining). */ -#define ARGP_KEY_SUCCESS 4 -/* Passed in if an error occurs (in which case a call with ARGP_KEY_SUCCESS is - never made, so any cleanup must be done here). */ -#define ARGP_KEY_ERROR 5 - -/* An argp structure contains a set of getopt options declarations, a - function to deal with getting one, and an optional pointer to another - argp structure. When actually parsing options, getopt is called with - the union of all the argp structures chained together through their - CHILD pointers, with conflicts being resolved in favor of the first - occurance in the chain. */ -struct argp -{ - /* An array of argp_option structures, terminated by an entry with both - NAME and KEY having a value of 0. */ - const struct argp_option *options; - - /* What to do with an option from this structure. KEY is the key - associated with the option, and ARG is any associated argument (NULL if - none was supplied). If KEY isn't understood, ARGP_ERR_UNKNOWN should be - returned. If a non-zero, non-ARGP_ERR_UNKNOWN value is returned, then - parsing is stopped immediately, and that value is returned from - argp_parse(). For special (non-user-supplied) values of KEY, see the - ARGP_KEY_ definitions below. */ - argp_parser_t parser; - - /* A string describing what other arguments are wanted by this program. It - is only used by argp_usage to print the `Usage:' message. */ - const char *args_doc; - - /* A string containing extra text to be printed after the options in a long - help message, if it is non-NULL. */ - const char *doc; - - /* A NULL terminated list of other argp structures that should be parsed - with this one. Any conflicts are resolved in favor of this argp, or - early argps in the CHILDREN list. This field is useful if you use - libraries that supply their own argp structure, which you want to use in - conjunction with your own. */ - const struct argp **children; -}; - -/* Parsing state. This is provided to parsing functions called by argp, - which may examine and, as noted, modify fields. */ -struct argp_state -{ - /* The top level ARGP being parsed. */ - const struct argp *argp; - - /* The argument vector being parsed. May be modified. */ - int argc; - char **argv; - - /* The index in ARGV of the next arg that to be parsed. May be modified. */ - int next; - - /* The flags supplied to argp_parse. May be modified. */ - unsigned flags; - - /* While calling a parsing function with a key of ARGP_KEY_ARG, this is the - number of the current arg, starting at zero, and incremented after each - such call returns. At all other times, this is the number of such - arguments that have been processed. */ - unsigned arg_num; - - /* If non-zero, the index in ARGV of the first argument following a special - `--' argument (which prevents anything following being interpreted as an - option). Only set once argument parsing has proceeded past this point. */ - int quoted; - - /* An arbitrary pointer passed in from the user. */ - void *input; - /* Values to pass to child parsers. This vector will be the same length as - the number of children for the current parser. */ - void **child_inputs; - - /* For the parser's use. Initialized to 0. */ - void *hook; - - /* The name used when printing messages. This is initialized to ARGV[0], - or PROGRAM_INVOCATION_NAME if that is unavailable. */ - char *name; - - /* Streams used when argp prints something. */ - FILE *err_stream; /* For errors; initialized to stderr. */ - FILE *out_stream; /* For information; initialized to stdout. */ -}; - -/* Flags for argp_parse (note that the defaults are those that are - convenient for program command line parsing): */ - -/* Don't ignore the first element of ARGV. Normally (and always unless - ARGP_NO_ERRS is set) the first element of the argument vector is - skipped for option parsing purposes, as it corresponds to the program name - in a command line. */ -#define ARGP_PARSE_ARGV0 0x1 - -/* Don't print error messages for unknown options to stderr; unless this flag - is set, ARGP_PARSE_ARGV0 is ignored, as ARGV[0] is used as the program - name in the error messages. This flag implies ARGP_NO_EXIT (on the - assumption that silent exiting upon errors is bad behaviour). */ -#define ARGP_NO_ERRS 0x2 - -/* Don't parse any non-option args. Normally non-option args are parsed by - calling the parse functions with a key of ARGP_KEY_ARG, 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 ARGP_ERR_UNKNOWN; if an argument is handled by no one, the - argp_parse returns prematurely (but with a return value of 0). If all - args have been parsed without error, all parsing functions are called one - last time with a key of ARGP_KEY_END. This flag needn't normally be set, - as the normal behavior is to stop parsing as soon as some argument can't - be handled. */ -#define ARGP_NO_ARGS 0x4 - -/* Parse options and arguments in the same order they occur on the command - line -- normally they're rearranged so that all options come first. */ -#define ARGP_IN_ORDER 0x8 - -/* Don't provide the standard long option --help, which causes usage and - option help information to be output to stdout, and exit (0) called. */ -#define ARGP_NO_HELP 0x10 - -/* Don't exit on errors (they may still result in error messages). */ -#define ARGP_NO_EXIT 0x20 - -/* Turns off any message-printing/exiting options. */ -#define ARGP_SILENT (ARGP_NO_EXIT | ARGP_NO_ERRS | ARGP_NO_HELP) - -/* Parse the options strings in ARGC & ARGV according to the options in ARGP. - FLAGS is one of the ARGP_ 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, ARGP_ERR_UNKNOWN is returned; if some parser - routine returned a non-zero value, it is returned; otherwise 0 is - returned. This function may also call exit unless the ARGP_NO_HELP flag - is set. INPUT is a pointer to a value to be passed in to the parser. */ -error_t argp_parse (const struct argp *argp, - int argc, char **argv, unsigned flags, - int *arg_index, void *input); - -/* If defined or set by the user program to a non-zero value, then a default - option --version is added (unless the ARGP_NO_HELP flag is used), which - will print this this string followed by a newline and exit (unless the - ARGP_NO_EXIT flag is used). Overridden by ARGP_PROGRAM_VERSION_HOOK. */ -extern char *argp_program_version; - -/* If defined or set by the user program to a non-zero value, then a default - option --version is added (unless the ARGP_NO_HELP flag is used), which - calls this function with a stream to print the version to and a pointer to - the current parsing state, and then exits (unless the ARGP_NO_EXIT flag is - used). This variable takes precedent over ARGP_PROGRAM_VERSION. */ -extern void (*argp_program_version_hook) (FILE *stream, - struct argp_state *state); - -/* Flags for argp_help. */ -#define ARGP_HELP_USAGE 0x01 /* Print a Usage: message. */ -#define ARGP_HELP_SHORT_USAGE 0x02 /* " but don't actually print options. */ -#define ARGP_HELP_SEE 0x04 /* Print a `for more help...' message. */ -#define ARGP_HELP_LONG 0x08 /* Print a long help message. */ - -/* These ARGP_HELP flags are only understood by argp_state_help. */ -#define ARGP_HELP_EXIT_ERR 0x10 /* Call exit(1) instead of returning. */ -#define ARGP_HELP_EXIT_OK 0x20 /* Call exit(0) instead of returning. */ - -/* The standard thing to do after a program command line parsing error, if an - error message has already been printed. */ -#define ARGP_HELP_STD_ERR \ - (ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR) -/* The standard thing to do after a program command line parsing error, if no - more specific error message has been printed. */ -#define ARGP_HELP_STD_USAGE \ - (ARGP_HELP_SHORT_USAGE | ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR) -/* The standard thing to do in response to a --help option. */ -#define ARGP_HELP_STD_HELP \ - (ARGP_HELP_SHORT_USAGE | ARGP_HELP_LONG | ARGP_HELP_EXIT_OK) - -/* Output a usage message for ARGP to STREAM. FLAGS are from the set - ARGP_HELP_*. */ -extern void argp_help (const struct argp *argp, FILE *stream, unsigned flags, - char *name); - -/* The following routines are intended to be called from within an argp - parsing routine (thus taking an argp_state structure as the first - argument). They may or may not print an error message and exit, depending - on the flags in STATE -- in any case, the caller should be prepared for - them *not* to exit, and should return an appropiate error after calling - them. [argp_usage & argp_error should probably be called argp_state_..., - but they're used often enough that they should be short] */ - -/* Output, if appropriate, a usage message for STATE to STREAM. FLAGS are - from the set ARGP_HELP_*. */ -void argp_state_help (struct argp_state *state, FILE *stream, unsigned flags); - -/* Possibly output the standard usage message for ARGP to stderr and exit. */ -extern inline void -argp_usage (struct argp_state *state) -{ - argp_state_help (state, stderr, ARGP_HELP_STD_USAGE); -} - -/* If appropriate, print the printf string FMT and following args, preceded - by the program name and `:', to stderr, and followed by a `Try ... --help' - message, then exit (1). */ -void argp_error (struct argp_state *state, const char *fmt, ...) - __attribute__ ((format (printf, 2, 3))); - -/* Similar to the standard gnu error-reporting function error(), but will - respect the ARGP_NO_EXIT and ARGP_NO_ERRS flags in STATE, and will print - to STATE->err_stream. This is useful for argument parsing code that is - shared between program startup (when exiting is desired) and runtime - option parsing (when typically an error code is returned instead). The - difference between this function and argp_error is that the latter is for - *parsing errors*, and the former is for other problems that occur during - parsing but don't reflect a (syntactic) problem with the input. */ -void argp_failure (struct argp_state *state, - int status, int errnum, const char *fmt, ...) - __attribute__ ((format (printf, 4, 5))); - -/* Returns true if the option OPT is a valid short option. */ -extern inline int -_option_is_short (const struct argp_option *opt) -{ - int key = opt->key; - return key > 0 && isprint (key); -} - -/* Returns true if the option OPT is in fact the last (unused) entry in an - options array. */ -extern inline int -_option_is_end (const struct argp_option *opt) -{ - return !opt->key && !opt->name && !opt->doc && !opt->group; -} - -#endif /* __ARGP_H__ */ diff --git a/libshouldbeinlibc/cacheq.c b/libshouldbeinlibc/cacheq.c index c8b0c989..5649903a 100644 --- a/libshouldbeinlibc/cacheq.c +++ b/libshouldbeinlibc/cacheq.c @@ -1,6 +1,6 @@ /* Helper functions for maintaining a fixed-size lru-ordered queue - Copyright (C) 1996 Free Software Foundation, Inc. + Copyright (C) 1996, 1998 Free Software Foundation, Inc. Written by Miles Bader <miles@gnu.ai.mit.edu> @@ -82,7 +82,8 @@ cacheq_set_length (struct cacheq *cq, int length) /* Source entries. */ struct cacheq_hdr *fh = cq->mru; /* Destination entries (and limit). */ - struct cacheq_hdr *th = new_entries, *end = new_entries + esz * length; + struct cacheq_hdr *th = new_entries; + struct cacheq_hdr *end = new_entries + esz * (length - 1); struct cacheq_hdr *prev_th = 0; if (! new_entries) @@ -91,7 +92,7 @@ cacheq_set_length (struct cacheq *cq, int length) while (fh || th) { struct cacheq_hdr *next_th = - (!th || th > end) ? 0 : (void *)th + esz; + (!th || th >= end) ? 0 : (void *)th + esz; if (fh && th) bcopy (fh, th, esz); /* Copy the bits in a moved entry. */ @@ -105,7 +106,7 @@ cacheq_set_length (struct cacheq *cq, int length) th->next = next_th; } - /* Call user hooks as appropiate. */ + /* Call user hooks as appropriate. */ if (fh && th) { if (cq->move_entry) diff --git a/libshouldbeinlibc/exec-reauth.c b/libshouldbeinlibc/exec-reauth.c index 2b068684..dd267ef7 100644 --- a/libshouldbeinlibc/exec-reauth.c +++ b/libshouldbeinlibc/exec-reauth.c @@ -1,6 +1,6 @@ /* Re-authentication in preparation for an exec - Copyright (C) 1995, 1996 Free Software Foundation, Inc. + Copyright (C) 1995, 96, 98, 2000 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> @@ -54,9 +54,12 @@ exec_reauth (auth_t auth, int secure, int must_reauth, (isproc ? proc_reauthenticate : io_reauthenticate) (*port, ref, MACH_MSG_TYPE_MAKE_SEND); + /* MAKE_SEND is safe here because we destroy REF ourselves. */ + if (!err) err = auth_user_authenticate (auth, ref, MACH_MSG_TYPE_MAKE_SEND, &newport); + mach_port_destroy (mach_task_self (), ref); if (err) { if (must_reauth) @@ -73,22 +76,23 @@ exec_reauth (auth_t auth, int secure, int must_reauth, *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 (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) diff --git a/libshouldbeinlibc/fsysops.c b/libshouldbeinlibc/fsysops.c index 4e282f0b..f26069df 100644 --- a/libshouldbeinlibc/fsysops.c +++ b/libshouldbeinlibc/fsysops.c @@ -1,6 +1,6 @@ /* Some handy utility routines for fsys control ports - Copyright (C) 1996 Free Software Foundation, Inc. + Copyright (C) 1996, 1999 Free Software Foundation, Inc. Written by Miles Bader <miles@gnu.ai.mit.edu> @@ -23,6 +23,7 @@ #include <errno.h> #include <argz.h> #include <mach.h> +#include <sys/mman.h> #include <hurd/fsys.h> /* Make FSYS readonly or writable. */ @@ -57,7 +58,7 @@ fsys_get_readonly (fsys_t fsys, int *readonly) for (opt = opts ; !ok && opt && opt < opts + opts_len - ; opt = argz_next (opts, opts_len, opt)) + ; opt = argz_next (opts, opts_len, opt)) if (strcasecmp (opt, "--readonly") == 0) { *readonly = 1; @@ -74,7 +75,7 @@ fsys_get_readonly (fsys_t fsys, int *readonly) if (opts != _opts) /* Free out-of-line memory returned by fsys_get_options. */ - vm_deallocate (mach_task_self (), (vm_address_t)opts, opts_len); + munmap (opts, opts_len); } return err; @@ -82,10 +83,10 @@ fsys_get_readonly (fsys_t fsys, int *readonly) /* Tell FSYS to remount itself. */ error_t -fsys_remount (fsys_t fsys, int readonly) +fsys_update (fsys_t fsys, int readonly) { error_t err; - char *opts = "--remount"; + char *opts = "--update"; size_t opts_len = strlen (opts) + 1; err = fsys_set_options (fsys, opts, opts_len, 0); if (err == EINVAL) diff --git a/libshouldbeinlibc/idvec-auth.c b/libshouldbeinlibc/idvec-auth.c index 896bfdb7..bb7f4afd 100644 --- a/libshouldbeinlibc/idvec-auth.c +++ b/libshouldbeinlibc/idvec-auth.c @@ -1,8 +1,9 @@ /* Idvec functions that interact with an auth server - Copyright (C) 1995 Free Software Foundation, Inc. + Copyright (C) 1995, 1998, 1999, 2001, 2002, 2008 + Free Software Foundation, Inc. - Written by Miles Bader <miles@gnu.ai.mit.edu> + 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 @@ -19,12 +20,11 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <mach.h> +#include <sys/mman.h> #include <hurd/auth.h> #include "idvec.h" -typedef uid_t id_t; - /* 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. */ @@ -34,12 +34,12 @@ idvec_merge_auth (struct idvec *eff_uids, struct idvec *avail_uids, auth_t auth) { error_t err; - id_t eff_uid_buf[10], avail_uid_buf[20]; - id_t *_eff_uids = eff_uid_buf, *_avail_uids = avail_uid_buf; - int num_eff_uids = 10, num_avail_uids = 20; - id_t eff_gid_buf[10], avail_gid_buf[20]; - id_t *_eff_gids = eff_gid_buf, *_avail_gids = avail_gid_buf; - int num_eff_gids = 10, num_avail_gids = 20; + uid_t eff_uid_buf[10], avail_uid_buf[20]; + uid_t *_eff_uids = eff_uid_buf, *_avail_uids = avail_uid_buf; + size_t 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; + size_t num_eff_gids = 10, num_avail_gids = 20; err = auth_getids (auth, &_eff_uids, &num_eff_uids, &_avail_uids, &num_avail_uids, @@ -60,21 +60,25 @@ idvec_merge_auth (struct idvec *eff_uids, struct idvec *avail_uids, /* 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); + if (eff_uids) + idvec_merge_ids (eff_uids, _eff_uids, num_eff_uids); + if (avail_uids) + idvec_merge_ids (avail_uids, _avail_uids, num_avail_uids); + if (eff_gids) + idvec_merge_ids (eff_gids, _eff_gids, num_eff_gids); + if (avail_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) - vm_deallocate (mach_task_self (), (vm_address_t)_eff_uids, num_eff_uids); + munmap ((caddr_t) _eff_uids, num_eff_uids * sizeof (uid_t)); if (_avail_uids != avail_uid_buf) - vm_deallocate (mach_task_self (), (vm_address_t)_avail_uids, num_avail_uids); + munmap ((caddr_t) _avail_uids, num_avail_uids * sizeof (uid_t)); if (_eff_gids != eff_gid_buf) - vm_deallocate (mach_task_self (), (vm_address_t)_eff_gids, num_eff_gids); + munmap ((caddr_t) _eff_gids, num_eff_gids * sizeof (gid_t)); if (_avail_gids != avail_gid_buf) - vm_deallocate (mach_task_self (), (vm_address_t)_avail_gids, num_avail_gids); + munmap ((caddr_t) _avail_gids, num_avail_gids * sizeof (gid_t)); return err; } diff --git a/libshouldbeinlibc/idvec-funcs.c b/libshouldbeinlibc/idvec-funcs.c new file mode 100644 index 00000000..3bb0318d --- /dev/null +++ b/libshouldbeinlibc/idvec-funcs.c @@ -0,0 +1,2 @@ +#define IDVEC_DEFINE_EI +#include "idvec.h" diff --git a/libshouldbeinlibc/idvec-impgids.c b/libshouldbeinlibc/idvec-impgids.c new file mode 100644 index 00000000..66f82e21 --- /dev/null +++ b/libshouldbeinlibc/idvec-impgids.c @@ -0,0 +1,127 @@ +/* Add gids implied by a user + + Copyright (C) 1997, 2001 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 (); +#ifdef HAVE_GETGROUPLIST + gid_t _gids[NUM_STATIC_GIDS], *gids = _gids; + int maxgids = NUM_STATIC_GIDS; + int 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 +#warning "getgrouplist() not available; supplementary group IDs unsupported." + if (! cache) + err = ENOMEM; + else + { + err = idvec_add_new (cache, pw->pw_gid); + if (err) + idvec_free (cache); + } +#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..981f86ac --- /dev/null +++ b/libshouldbeinlibc/idvec-verify.c @@ -0,0 +1,362 @@ +/* Verify user passwords + + Copyright (C) 1996, 1997, 1998, 1999, 2002, 2008 + 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. */ + +#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> +#include <crypt.h> + +#define SHADOW_PASSWORD_STRING "x" /* pw_passwd contents for shadow passwd */ + +#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 = (intptr_t)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 *)(intptr_t)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 != (uid_t) -1) + 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 index 6daa639a..24adeb8f 100644 --- a/libshouldbeinlibc/idvec.c +++ b/libshouldbeinlibc/idvec.c @@ -1,6 +1,6 @@ /* Routines for vectors of uids/gids - Copyright (C) 1995, 1996 Free Software Foundation, Inc. + Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc. Written by Miles Bader <miles@gnu.ai.mit.edu> @@ -22,8 +22,6 @@ #include <string.h> #include <idvec.h> -typedef uid_t id_t; - /* Return a new, empty, idvec, or NULL if there wasn't enough memory. */ struct idvec * make_idvec () @@ -67,7 +65,7 @@ idvec_ensure (struct idvec *idvec, unsigned num) { if (num > idvec->alloced) { - id_t *_ids = realloc (idvec->ids, num * sizeof (id_t)); + uid_t *_ids = realloc (idvec->ids, num * sizeof (uid_t)); if (! _ids) return ENOMEM; idvec->ids = _ids; @@ -83,47 +81,42 @@ 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 (struct idvec *idvec, unsigned pos, id_t id) +idvec_tail_contains (const struct idvec *idvec, unsigned pos, uid_t id) { - while (pos < idvec->num) - if (idvec->ids[pos++] == id) + uid_t *ids = idvec->ids, *end = ids + idvec->num, *p = ids + pos; + while (p < end) + if (*p++ == id) return 1; return 0; } - -/* Returns true if IDVEC contains ID. */ -int -idvec_contains (struct idvec *idvec, id_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, id_t id) +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_grow (idvec, num + 1); + err = idvec_ensure (idvec, new_num + num); else - err = idvec_grow (idvec, 1); + err = idvec_ensure (idvec, new_num); if (! err) { - id_t *ids = idvec->ids; + uid_t *ids = idvec->ids; if (pos < num) - bcopy (ids + pos, ids + pos + 1, (num - pos) * sizeof (id_t)); + bcopy (ids + pos, ids + pos + 1, (num - pos) * sizeof (uid_t)); else if (pos > num) - bzero (ids + num, (pos - num) * sizeof (id_t)); + bzero (ids + num, (pos - num) * sizeof (uid_t)); ids[pos] = id; - idvec->num = num + 1; + idvec->num = new_num; } return err; @@ -132,7 +125,7 @@ idvec_insert (struct idvec *idvec, unsigned pos, id_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, id_t id) +idvec_add (struct idvec *idvec, uid_t id) { return idvec_insert (idvec, idvec->num, id); } @@ -140,7 +133,7 @@ idvec_add (struct idvec *idvec, id_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, id_t id) +idvec_add_new (struct idvec *idvec, uid_t id) { if (idvec_contains (idvec, id)) return 0; @@ -151,7 +144,7 @@ idvec_add_new (struct idvec *idvec, id_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, id_t id) +idvec_insert_new (struct idvec *idvec, unsigned pos, uid_t id) { if (idvec_tail_contains (idvec, pos, id)) return 0; @@ -159,10 +152,33 @@ idvec_insert_new (struct idvec *idvec, unsigned pos, id_t id) 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, id_t *ids, unsigned num) +idvec_merge_ids (struct idvec *idvec, const uid_t *ids, unsigned num) { error_t err = 0; unsigned num_old = idvec->num; @@ -181,34 +197,77 @@ idvec_merge_ids (struct idvec *idvec, id_t *ids, unsigned num) /* Adds each id from NEW to IDVEC, as if with idvec_add_new(). */ error_t -idvec_merge (struct idvec *idvec, struct idvec *new) +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. */ +/* Remove any occurrences of ID in IDVEC after position POS. + Returns true if anything was done. */ int -idvec_remove (struct idvec *idvec, unsigned pos, id_t id) +idvec_remove (struct idvec *idvec, unsigned pos, uid_t id) { - int left = idvec->num - pos; - id_t *ids = idvec->ids + pos, *targ = ids; - while (left--) + if (pos < idvec->num) { - if (*ids != id) + int left = idvec->num - pos; + uid_t *ids = idvec->ids + pos, *targ = ids; + while (left--) { - if (ids != targ) - *targ = *ids; - targ++; + if (*ids != id) + { + if (ids != targ) + *targ = *ids; + targ++; + } + ids++; } - ids++; + if (ids == targ) + return 0; + idvec->num = targ - idvec->ids; + return 1; } - if (ids == targ) + else return 0; - idvec->num = targ - idvec->ids; - return 1; } +/* 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) @@ -216,20 +275,20 @@ idvec_delete (struct idvec *idvec, unsigned pos) unsigned num = idvec->num; if (pos < num) { - id_t *ids = idvec->ids; + uid_t *ids = idvec->ids; idvec->num = --num; if (num > pos) - bcopy (ids + pos + 1, ids + pos, (num - pos) * sizeof (id_t)); + bcopy (ids + pos + 1, ids + pos, (num - pos) * sizeof (uid_t)); } } -/* Insert ID at position POS in IDVEC, remoint any instances of ID previously +/* 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, id_t id) +idvec_insert_only (struct idvec *idvec, unsigned pos, uid_t id) { - if (idvec->ids[pos] == id) + if (idvec->num > pos && idvec->ids[pos] == id) return 0; else { @@ -238,39 +297,37 @@ idvec_insert_only (struct idvec *idvec, unsigned pos, id_t id) } } -/* EFF and AVAIL should be idvec's corresponding to a processes effective and - available ids. ID replaces the first id in EFF, and what it replaces is - preserved by adding it to AVAIL (if not already present). 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. */ +/* 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, id_t id, int *secure) +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. */ { - if (avail->num == 0) - /* The old eff[0] becomes avail[0] (the posix real id). */ - err = idvec_add (avail, eff->ids[0]); - else - /* We preserve the old real id, and add eff[0] to the list of saved - ids (if necessary). Inserting it means that the latest id saved - will correspond to the (single) posix saved id. */ - err = idvec_insert_only (avail, 1, eff->ids[0]); - - /* Replace eff[0] with the new id. */ - eff->ids[0] = id; + /* 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; diff --git a/libshouldbeinlibc/idvec.h b/libshouldbeinlibc/idvec.h index 8e99d433..abbc273e 100644 --- a/libshouldbeinlibc/idvec.h +++ b/libshouldbeinlibc/idvec.h @@ -1,8 +1,7 @@ /* Routines for vectors of uids/gids - Copyright (C) 1995, 1996 Free Software Foundation, Inc. - - Written by Miles Bader <miles@gnu.ai.mit.edu> + Copyright (C) 1995,96,97,99,2001 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 @@ -22,8 +21,16 @@ #define __IDVEC_H__ #include <sys/types.h> -#include <errno.h> #include <hurd/hurd_types.h> +#include <errno.h> +#include <string.h> +#include <features.h> + +#ifdef IDVEC_DEFINE_EI +#define IDVEC_EI +#else +#define IDVEC_EI __extern_inline +#endif struct idvec { @@ -31,11 +38,14 @@ struct idvec 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); @@ -43,13 +53,40 @@ void idvec_free_wrapper (struct idvec *idvec); /* Free IDVEC and any storage associated with it. */ void idvec_free (struct idvec *idvec); +extern void idvec_clear (struct idvec *idvec); + +extern int idvec_is_empty (const struct idvec *idvec); + +extern int idvec_equal (const struct idvec *idvec1, const struct idvec *idvec2); + +#if defined(__USE_EXTERN_INLINES) || defined(IDVEC_DEFINE_EI) + /* Mark IDVEC as not containing any ids. */ -extern inline void +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); +} + +#endif /* Use extern inlines. */ + /* 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 @@ -61,10 +98,20 @@ error_t idvec_ensure (struct idvec *idvec, unsigned num); error_t idvec_grow (struct idvec *idvec, unsigned inc); /* Returns true if IDVEC contains ID, at or after position POS. */ -int idvec_tail_contains (struct idvec *idvec, unsigned pos, uid_t id); +int idvec_tail_contains (const struct idvec *idvec, unsigned pos, uid_t id); + +extern int idvec_contains (const struct idvec *idvec, uid_t id); + +#if defined(__USE_EXTERN_INLINES) || defined(IDVEC_DEFINE_EI) /* Returns true if IDVEC contains ID. */ -int idvec_contains (struct idvec *idvec, uid_t id); +IDVEC_EI int +idvec_contains (const struct idvec *idvec, uid_t id) +{ + return idvec_tail_contains (idvec, 0, id); +} + +#endif /* Use extern inlines. */ /* Insert ID into IDVEC at position POS, returning ENOMEM if there wasn't enough memory, or 0. */ @@ -82,31 +129,47 @@ error_t idvec_add_new (struct idvec *idvec, uid_t id); 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, uid_t *ids, unsigned num); +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, struct idvec *new); +error_t idvec_merge (struct idvec *idvec, const struct idvec *new); -/* Remove any occurances of ID in IDVEC after position POS> Returns true if +/* 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 occurrences 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, remoint any instances of ID previously +/* 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 processes effective and - available ids. ID replaces the first id in EFF, and what it replaces is - preserved by adding it to AVAIL (if not already present). 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. */ +/* 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); @@ -117,4 +180,58 @@ 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/localhost.c b/libshouldbeinlibc/localhost.c index f0c67541..f0225116 100644 --- a/libshouldbeinlibc/localhost.c +++ b/libshouldbeinlibc/localhost.c @@ -39,18 +39,27 @@ localhost () errno = 0; if (buf) { + char *new; buf_len += buf_len; - buf = realloc (buf, buf_len); + new = realloc (buf, buf_len); + if (! new) + { + free (buf); + buf = 0; + errno = ENOMEM; + return 0; + } + else + buf = new; } else { buf_len = 128; /* Initial guess */ buf = malloc (buf_len); + if (! buf) + { + errno = ENOMEM; + return 0; + } } - - if (! buf) - { - errno = ENOMEM; - return 0; - } } while ((gethostname(buf, buf_len) == 0 && !memchr (buf, '\0', buf_len)) || errno == ENAMETOOLONG); diff --git a/libshouldbeinlibc/maptime-funcs.c b/libshouldbeinlibc/maptime-funcs.c new file mode 100644 index 00000000..080e3ae6 --- /dev/null +++ b/libshouldbeinlibc/maptime-funcs.c @@ -0,0 +1,5 @@ +#define MAPTIME_DEFINE_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 index 95ae64cb..bc750458 100644 --- a/libshouldbeinlibc/maptime.c +++ b/libshouldbeinlibc/maptime.c @@ -1,6 +1,6 @@ /* Support for mach's mapped time - Copyright (C) 1996 Free Software Foundation, Inc. + Copyright (C) 1996, 1997 Free Software Foundation, Inc. Written by Miles Bader <miles@gnu.ai.mit.edu> @@ -18,6 +18,7 @@ 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> @@ -34,11 +35,11 @@ maptime_map (int use_mach_dev, char *dev_name, volatile struct mapped_time_value **mtime) { error_t err; - device_t device; - mach_port_t mobj; + mach_port_t memobj; if (use_mach_dev) { + device_t device; mach_port_t device_master; err = get_privileged_ports (0, &device_master); @@ -47,72 +48,32 @@ maptime_map (int use_mach_dev, char *dev_name, 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_msg_type_number_t data_len = 100; - mach_msg_type_number_t num_ints = 10, num_ports = 10, num_offsets = 10; - int _ints[num_ints], *ints = _ints; - mach_port_t _ports[num_ports], *ports = _ports; - off_t _offsets[num_offsets], *offsets = _offsets; - char _data[data_len], *data = _data; - file_t node = file_name_lookup (dev_name ?: "/dev/time", 0, 0); + 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 = file_get_storage_info (node, &ports, &num_ports, &ints, &num_ints, - &offsets, &num_offsets, &data, &data_len); - - if (! err) - { - int i; - - if (num_ints >= 6 && ints[0] == STORAGE_DEVICE) - /* This a device. */ - if (num_ports != 1) - err = EGRATUITOUS; - else if (! MACH_PORT_VALID (ports[0])) - err = EPERM; /* Didn't pass back the device port. XXX */ - else - { - device = ports[0]; - ports[0] = MACH_PORT_NULL; /* Don't deallocate here. */ - } - else - err = ENODEV; /* Not admitting to being a device. XXX */ - - /* Deallocate any ports we got back. */ - for (i = 0; i < num_ports; i++) - if (MACH_PORT_VALID (ports[i])) - mach_port_deallocate (mach_task_self (), ports[i]); - - /* Deallocate any out of line vectors return by gsi. */ -#define DISCARD_MEM(v, vl, b) \ - if (vl && v != b) \ - vm_deallocate (mach_task_self (), (vm_address_t)v, vl * sizeof *v); - DISCARD_MEM (ints, num_ints, _ints); - DISCARD_MEM (offsets, num_offsets, _offsets); - DISCARD_MEM (ports, num_ports, _ports); - DISCARD_MEM (data, data_len, _data); - } + 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) - return err; - - err = device_map (device, VM_PROT_READ, 0, sizeof *mtime, &mobj, 0); if (! err) { + *mtime = 0; err = vm_map (mach_task_self (), (vm_address_t *)mtime, sizeof *mtime, 0, 1, - mobj, 0, 0, VM_PROT_READ, VM_PROT_READ, VM_INHERIT_NONE); - mach_port_deallocate (mach_task_self (), mobj); + memobj, 0, 0, VM_PROT_READ, VM_PROT_READ, VM_INHERIT_NONE); + mach_port_deallocate (mach_task_self (), memobj); } - mach_port_deallocate (mach_task_self (), device); - return err; } diff --git a/libshouldbeinlibc/maptime.h b/libshouldbeinlibc/maptime.h index 244cbcf1..947ad640 100644 --- a/libshouldbeinlibc/maptime.h +++ b/libshouldbeinlibc/maptime.h @@ -1,8 +1,8 @@ /* Support for mach's mapped time - Copyright (C) 1996 Free Software Foundation, Inc. + Copyright (C) 1996, 1997, 2000, 2007 Free Software Foundation, Inc. - Written by Miles Bader <miles@gnu.ai.mit.edu> + 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 @@ -22,17 +22,30 @@ #define __MAPTIME_H__ #include <mach/time_value.h> +#include <sys/time.h> +#include <errno.h> +#include <features.h> + +#ifdef MAPTIME_DEFINE_EI +#define MAPTIME_EI +#else +#define MAPTIME_EI __extern_inline +#endif /* 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 + 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 uptime - may be converted to a struct timeval at any time using read_uptime. */ + 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); +extern void maptime_read (volatile struct mapped_time_value *mtime, struct timeval *tv); + +#if defined(__USE_EXTERN_INLINES) || defined(MAPTIME_DEFINE_EI) + /* Read the current time from MTIME into TV. This should be very fast. */ -static inline void +MAPTIME_EI void maptime_read (volatile struct mapped_time_value *mtime, struct timeval *tv) { do @@ -43,4 +56,6 @@ maptime_read (volatile struct mapped_time_value *mtime, struct timeval *tv) while (tv->tv_sec != mtime->check_seconds); } +#endif /* Use extern inlines. */ + #endif /* __MAPTIME_H__ */ diff --git a/libshouldbeinlibc/options.c b/libshouldbeinlibc/options.c deleted file mode 100644 index 5f719616..00000000 --- a/libshouldbeinlibc/options.c +++ /dev/null @@ -1,231 +0,0 @@ -/* 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 deleted file mode 100644 index 46651add..00000000 --- a/libshouldbeinlibc/options.h +++ /dev/null @@ -1,79 +0,0 @@ -/* 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 index cb4e9605..e6305c6e 100644 --- a/libshouldbeinlibc/portinfo.c +++ b/libshouldbeinlibc/portinfo.c @@ -1,8 +1,7 @@ /* Print information about a task's ports - Copyright (C) 1996 Free Software Foundation, Inc. - - Written by Miles Bader <miles@gnu.ai.mit.edu> + Copyright (C) 1996,98,99,2002 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 @@ -18,6 +17,9 @@ 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 @@ -41,7 +43,7 @@ print_port_info (mach_port_t name, mach_port_type_t type, task_t task, mach_port_urefs_t refs; error_t err = mach_port_get_refs (task, name, right, &refs); if (! err) - fprintf (stream, " (refs: %u)", refs); + fprintf (stream, " (refs: %zu)", refs); } if (type == 0) @@ -51,7 +53,7 @@ print_port_info (mach_port_t name, mach_port_type_t type, task_t task, return err; } - fprintf (stream, hex_names ? "%#6x: " : "%6d: ", name); + fprintf (stream, hex_names ? "%#6zx: " : "%6zd: ", name); if (type & MACH_PORT_TYPE_RECEIVE) { @@ -66,15 +68,15 @@ print_port_info (mach_port_t name, mach_port_type_t type, task_t task, fprintf (stream, " ("); if (status.mps_pset != MACH_PORT_NULL) fprintf (stream, - hex_names ? "port-set: %#x, " : "port-set: %d, ", + hex_names ? "port-set: %#zx, " : "port-set: %zd, ", status.mps_pset); - fprintf (stream, "seqno: %u", status.mps_seqno); + fprintf (stream, "seqno: %zu", status.mps_seqno); if (status.mps_mscount) - fprintf (stream, ", ms-count: %u", status.mps_mscount); + fprintf (stream, ", ms-count: %zu", status.mps_mscount); if (status.mps_qlimit != MACH_PORT_QLIMIT_DEFAULT) - fprintf (stream, ", qlimit: %u", status.mps_qlimit); + fprintf (stream, ", qlimit: %zu", status.mps_qlimit); if (status.mps_msgcount) - fprintf (stream, ", msgs: %u", status.mps_msgcount); + fprintf (stream, ", msgs: %zu", status.mps_msgcount); fprintf (stream, "%s%s%s)", status.mps_srights ? ", send-rights" : "", status.mps_pdrequest ? ", pd-req" : "", @@ -112,17 +114,19 @@ print_port_info (mach_port_t name, mach_port_type_t type, task_t task, 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, ")"); - vm_deallocate (mach_task_self (), (vm_address_t)members, - members_len * sizeof *members); - } + { + if (members_len == 0) + fprintf (stream, " (empty)"); + else + { + fprintf (stream, hex_names ? " (%#zx" : " (%zu", members[0]); + for (i = 1; i < members_len; i++) + fprintf (stream, hex_names ? ", %#zx" : ", %zu", + members[i]); + fprintf (stream, ")"); + munmap ((caddr_t) members, members_len * sizeof *members); + } + } } } putc ('\n', stream); @@ -147,10 +151,8 @@ print_task_ports_info (task_t task, mach_port_type_t only, if (types[i] & only) print_port_info (names[i], types[i], task, show, stream); - vm_deallocate (mach_task_self (), - (vm_address_t)names, names_len * sizeof *names); - vm_deallocate (mach_task_self (), - (vm_address_t)types, types_len * sizeof *types); + 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 index bef2fa00..143c2898 100644 --- a/libshouldbeinlibc/portinfo.h +++ b/libshouldbeinlibc/portinfo.h @@ -1,6 +1,6 @@ /* Print information about a task's ports - Copyright (C) 1996 Free Software Foundation, Inc. + Copyright (C) 1996, 1999 Free Software Foundation, Inc. Written by Miles Bader <miles@gnu.ai.mit.edu> diff --git a/libshouldbeinlibc/portxlate.c b/libshouldbeinlibc/portxlate.c index 07b2fc03..291bcf3a 100644 --- a/libshouldbeinlibc/portxlate.c +++ b/libshouldbeinlibc/portxlate.c @@ -1,8 +1,7 @@ /* Translate mach port names between two tasks - Copyright (C) 1996 Free Software Foundation, Inc. - - Written by Miles Bader <miles@gnu.ai.mit.edu> + Copyright (C) 1996,99,2002 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 @@ -19,12 +18,14 @@ 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 +error_t port_name_xlator_create (mach_port_t from_task, mach_port_t to_task, struct port_name_xlator **xlator) { @@ -59,12 +60,10 @@ port_name_xlator_create (mach_port_t from_task, mach_port_t to_task, } else { - vm_deallocate (mach_task_self (), - (vm_address_t)x->to_names, - x->to_names_len * sizeof (mach_port_t)); - vm_deallocate (mach_task_self (), - (vm_address_t)x->to_types, - x->to_types_len * sizeof (mach_port_type_t)); + 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; } } @@ -88,12 +87,8 @@ port_name_xlator_free (struct port_name_xlator *x) mach_port_deallocate (mach_task_self (), x->ports[i]); free (x->ports); - vm_deallocate (mach_task_self (), - (vm_address_t)x->to_names, - x->to_names_len * sizeof (mach_port_t)); - vm_deallocate (mach_task_self (), - (vm_address_t)x->to_types, - x->to_types_len * sizeof (mach_port_type_t)); + 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); @@ -112,8 +107,8 @@ port_name_xlator_xlate (struct port_name_xlator *x, 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; + mach_msg_type_name_t aquired_type; + mach_msg_type_name_t valid_to_types; if (from_type == 0) { @@ -130,7 +125,7 @@ port_name_xlator_xlate (struct port_name_xlator *x, return EKERN_INVALID_RIGHT; /* Translate the name FROM, in FROM_TASK's namespace into our namespace. */ - err = + err = mach_port_extract_right (x->from_task, from, ((from_type & MACH_PORT_TYPE_RECEIVE) ? MACH_MSG_TYPE_MAKE_SEND diff --git a/libshouldbeinlibc/timefmt.c b/libshouldbeinlibc/timefmt.c index da4ccde0..aa8965b7 100644 --- a/libshouldbeinlibc/timefmt.c +++ b/libshouldbeinlibc/timefmt.c @@ -21,6 +21,7 @@ #include <stdio.h> #include <string.h> #include <sys/time.h> +#include <time.h> #include "timefmt.h" diff --git a/libshouldbeinlibc/ugids-argp.c b/libshouldbeinlibc/ugids-argp.c new file mode 100644 index 00000000..dc076d27 --- /dev/null +++ b/libshouldbeinlibc/ugids-argp.c @@ -0,0 +1,175 @@ +/* Parse user and group ids + + Copyright (C) 1997, 1999, 2008 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; + int err; + err = getpwnam_r (arg, &_pw, id_lookup_buf, + sizeof id_lookup_buf, &pw); + if (err == 0) + { + if (pw == NULL) + { + argp_failure (state, 10, 0, "%s: Unknown user", arg); + return EINVAL; + } + + uid = pw->pw_uid; + } + else + { + argp_failure (state, 12, err, + "Could not get uid for user: %s", arg); + return err; + } + } + + 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; + int err = getgrnam_r (arg, &_gr, id_lookup_buf, + sizeof id_lookup_buf, &gr); + if (err == 0) + { + if (gr == NULL) + { + argp_failure (state, 11, 0, "%s: Unknown group", arg); + return EINVAL; + } + + return ugids_add_gid (ugids, gr->gr_gid, key == 'G'); + } + else + { + argp_failure (state, 13, err, + "Could not get gid for group: %s", arg); + return err; + } + } + + 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/argp-pv.c b/libshouldbeinlibc/ugids-imply.c index e6e87adb..9c2a8a2c 100644 --- a/libshouldbeinlibc/argp-pv.c +++ b/libshouldbeinlibc/ugids-imply.c @@ -1,17 +1,15 @@ -/* Default definition for ARGP_PROGRAM_VERSION +/* Calculate implied group ids from user ids - Copyright (C) 1996 Free Software Foundation, Inc. + Copyright (C) 1997 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 + 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. - The GNU Hurd is distributed in the hope that it will be useful, but + 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. @@ -20,8 +18,18 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* If set by the user program to a non-zero value, then a default option - --version is added (unless the ARGP_NO_HELP flag is used), which will - print this this string followed by a newline and exit (unless the - ARGP_NO_EXIT flag is used). Overridden by ARGP_PROGRAM_VERSION_HOOK. */ -char *argp_program_version = 0; +#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..107de8b9 --- /dev/null +++ b/libshouldbeinlibc/ugids-xinl.c @@ -0,0 +1,23 @@ +/* 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_DEFINE_EI +#include "ugids.h" diff --git a/libshouldbeinlibc/ugids.c b/libshouldbeinlibc/ugids.c new file mode 100644 index 00000000..2b9b6b71 --- /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 appropriate 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 appropriate 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..10e7a242 --- /dev/null +++ b/libshouldbeinlibc/ugids.h @@ -0,0 +1,229 @@ +/* Uid/gid parsing/frobbing + + Copyright (C) 1997,2001 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 __UGIDS_H__ +#define __UGIDS_H__ + +#include <stdlib.h> /* For inline function stuff. */ +#include <idvec.h> +#include <features.h> + +#ifdef UGIDS_DEFINE_EI +#define UGIDS_EI +#else +#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 (); + +extern void ugids_fini (struct ugids *ugids); + +extern void ugids_free (struct ugids *ugids); + +extern int ugids_is_empty (const struct ugids *ugids); + +extern int ugids_equal (const struct ugids *ugids1, const struct ugids *ugids2); + +#if defined(__USE_EXTERN_INLINES) || defined(UGIDS_DEFINE_EI) + +/* 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); +} + +#endif /* Use extern inlines. */ + +/* 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 index 7be04dee..bafc9599 100644 --- a/libshouldbeinlibc/wire.c +++ b/libshouldbeinlibc/wire.c @@ -1,5 +1,5 @@ /* Function to wire down text and data (including from shared libraries) - Copyright (C) 1996 Free Software Foundation, Inc. + Copyright (C) 1996,99,2000,01,02 Free Software Foundation, Inc. Written by Michael I. Bushnell, p/BSG. This file is part of the GNU Hurd. @@ -20,14 +20,28 @@ #include <link.h> +#include <dlfcn.h> #include <mach.h> #include <hurd.h> +#include <error.h> + +#pragma weak _DYNAMIC +#pragma weak dlopen +#pragma weak dlclose +#pragma weak dlerror +#pragma weak dlsym +#ifndef RTLD_NOLOAD +#define RTLD_NOLOAD 0 +#endif /* Find the list of shared objects */ static struct link_map * loaded (void) { - Elf32_Dyn *d; + ElfW(Dyn) *d; + + if (&_DYNAMIC == 0) /* statically linked */ + return 0; for (d = _DYNAMIC; d->d_tag != DT_NULL; ++d) if (d->d_tag == DT_DEBUG) @@ -40,13 +54,27 @@ loaded (void) } /* Compute the extent of a particular shared object. */ -static Elf32_Addr +static ElfW(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_filesz; + /* In fact, LIB == MAP, but doing it this way makes it entirely kosher. */ + void *lib = dlopen (map->l_name, RTLD_NOLOAD); + if (lib == 0) + { + error (2, 0, "cannot dlopen %s: %s", map->l_name, dlerror ()); + /* NOTREACHED */ + return 0; + } + else + { + /* Find the _end symbol's runtime address and subtract the load base. */ + void *end = dlsym (lib, "_end"); + if (end == 0) + error (2, 0, "cannot wire library %s with no _end symbol: %s", + map->l_name, dlerror ()); + dlclose (lib); + return (ElfW(Addr)) end - map->l_addr; + } } /* Wire down all memory currently allocated at START for LEN bytes; @@ -70,7 +98,7 @@ wire_segment_internal (vm_address_t start, do { addr = start; - err = vm_region (mach_task_self (), &addr, &size, &protection, + err = vm_region (mach_task_self (), &addr, &size, &protection, &max_protection, &inheritance, &shared, &object_name, &offset); if (err) @@ -80,25 +108,25 @@ wire_segment_internal (vm_address_t start, 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; + 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; } @@ -112,7 +140,7 @@ wire_segment (vm_address_t start, { mach_port_t host, device; error_t error; - + error = get_privileged_ports (&host, &device); if (!error) { @@ -132,17 +160,17 @@ wire_task_self () 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, + wire_segment_internal (text_start, (vm_size_t) (&_etext - text_start), host); wire_segment_internal ((vm_address_t) &__data_start, @@ -156,4 +184,3 @@ wire_task_self () mach_port_deallocate (mach_task_self (), host); mach_port_deallocate (mach_task_self (), device); } - diff --git a/libshouldbeinlibc/xportinfo.c b/libshouldbeinlibc/xportinfo.c index cdd1da38..cce6fb6c 100644 --- a/libshouldbeinlibc/xportinfo.c +++ b/libshouldbeinlibc/xportinfo.c @@ -1,6 +1,6 @@ /* Print information about a port, with the name translated between tasks - Copyright (C) 1996 Free Software Foundation, Inc. + Copyright (C) 1996, 1999 Free Software Foundation, Inc. Written by Miles Bader <miles@gnu.ai.mit.edu> @@ -18,6 +18,9 @@ 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 @@ -32,7 +35,7 @@ print_xlated_port_info (mach_port_t name, mach_port_type_t type, error_t err = port_name_xlator_xlate (x, name, type, &name, &type); if (! err) { - fprintf (stream, (show & PORTINFO_HEX_NAMES) ? "%#6x => " : "%6d => ", + fprintf (stream, (show & PORTINFO_HEX_NAMES) ? "%#6zx => " : "%6zd => ", old_name); err = print_port_info (name, type, x->to_task, show, stream); } @@ -59,10 +62,8 @@ print_xlated_task_ports_info (struct port_name_xlator *x, if (types[i] & only) print_xlated_port_info (names[i], types[i], x, show, stream); - vm_deallocate (mach_task_self (), - (vm_address_t)names, names_len * sizeof *names); - vm_deallocate (mach_task_self (), - (vm_address_t)types, types_len * sizeof *types); + munmap ((caddr_t) names, names_len * sizeof *names); + munmap ((caddr_t) types, types_len * sizeof *types); return 0; } |