Initial revision

This commit is contained in:
Jim Meyering 1992-11-01 05:44:29 +00:00
parent 144b82c6c2
commit ccbd1d7dc5
44 changed files with 11209 additions and 0 deletions

194
lib/alloca.c Normal file
View File

@ -0,0 +1,194 @@
/*
alloca -- (mostly) portable public-domain implementation -- D A Gwyn
last edit: 86/05/30 rms
include config.h, since on VMS it renames some symbols.
Use xmalloc instead of malloc.
This implementation of the PWB library alloca() function,
which is used to allocate space off the run-time stack so
that it is automatically reclaimed upon procedure exit,
was inspired by discussions with J. Q. Johnson of Cornell.
It should work under any C implementation that uses an
actual procedure stack (as opposed to a linked list of
frames). There are some preprocessor constants that can
be defined when compiling for your specific system, for
improved efficiency; however, the defaults should be okay.
The general concept of this implementation is to keep
track of all alloca()-allocated blocks, and reclaim any
that are found to be deeper in the stack than the current
invocation. This heuristic does not reclaim storage as
soon as it becomes invalid, but it will do so eventually.
As a special case, alloca(0) reclaims storage without
allocating any. It is a good idea to use alloca(0) in
your main control loop, etc. to force garbage collection.
*/
#ifndef lint
static char SCCSid[] = "@(#)alloca.c 1.1"; /* for the "what" utility */
#endif
#ifdef emacs
#include "config.h"
#ifdef static
/* actually, only want this if static is defined as ""
-- this is for usg, in which emacs must undefine static
in order to make unexec workable
*/
#ifndef STACK_DIRECTION
you
lose
-- must know STACK_DIRECTION at compile-time
#endif /* STACK_DIRECTION undefined */
#endif /* static */
#endif /* emacs */
#ifndef alloca /* If compiling with GCC, this file's not needed. */
#ifdef __STDC__
typedef void *pointer; /* generic pointer type */
#else
typedef char *pointer; /* generic pointer type */
#endif
#define NULL 0 /* null pointer constant */
extern void free();
extern pointer xmalloc();
/*
Define STACK_DIRECTION if you know the direction of stack
growth for your system; otherwise it will be automatically
deduced at run-time.
STACK_DIRECTION > 0 => grows toward higher addresses
STACK_DIRECTION < 0 => grows toward lower addresses
STACK_DIRECTION = 0 => direction of growth unknown
*/
#ifndef STACK_DIRECTION
#define STACK_DIRECTION 0 /* direction unknown */
#endif
#if STACK_DIRECTION != 0
#define STACK_DIR STACK_DIRECTION /* known at compile-time */
#else /* STACK_DIRECTION == 0; need run-time code */
static int stack_dir; /* 1 or -1 once known */
#define STACK_DIR stack_dir
static void
find_stack_direction (/* void */)
{
static char *addr = NULL; /* address of first
`dummy', once known */
auto char dummy; /* to get stack address */
if (addr == NULL)
{ /* initial entry */
addr = &dummy;
find_stack_direction (); /* recurse once */
}
else /* second entry */
if (&dummy > addr)
stack_dir = 1; /* stack grew upward */
else
stack_dir = -1; /* stack grew downward */
}
#endif /* STACK_DIRECTION == 0 */
/*
An "alloca header" is used to:
(a) chain together all alloca()ed blocks;
(b) keep track of stack depth.
It is very important that sizeof(header) agree with malloc()
alignment chunk size. The following default should work okay.
*/
#ifndef ALIGN_SIZE
#define ALIGN_SIZE sizeof(double)
#endif
typedef union hdr
{
char align[ALIGN_SIZE]; /* to force sizeof(header) */
struct
{
union hdr *next; /* for chaining headers */
char *deep; /* for stack depth measure */
} h;
} header;
/*
alloca( size ) returns a pointer to at least `size' bytes of
storage which will be automatically reclaimed upon exit from
the procedure that called alloca(). Originally, this space
was supposed to be taken from the current stack frame of the
caller, but that method cannot be made to work for some
implementations of C, for example under Gould's UTX/32.
*/
static header *last_alloca_header = NULL; /* -> last alloca header */
pointer
alloca (size) /* returns pointer to storage */
unsigned size; /* # bytes to allocate */
{
auto char probe; /* probes stack depth: */
register char *depth = &probe;
#if STACK_DIRECTION == 0
if (STACK_DIR == 0) /* unknown growth direction */
find_stack_direction ();
#endif
/* Reclaim garbage, defined as all alloca()ed storage that
was allocated from deeper in the stack than currently. */
{
register header *hp; /* traverses linked list */
for (hp = last_alloca_header; hp != NULL;)
if ((STACK_DIR > 0 && hp->h.deep > depth)
|| (STACK_DIR < 0 && hp->h.deep < depth))
{
register header *np = hp->h.next;
free ((pointer) hp); /* collect garbage */
hp = np; /* -> next header */
}
else
break; /* rest are not deeper */
last_alloca_header = hp; /* -> last valid storage */
}
if (size == 0)
return NULL; /* no allocation required */
/* Allocate combined header + user data storage. */
{
register pointer new = xmalloc (sizeof (header) + size);
/* address of header */
((header *)new)->h.next = last_alloca_header;
((header *)new)->h.deep = depth;
last_alloca_header = (header *)new;
/* User storage begins just after header. */
return (pointer)((char *)new + sizeof(header));
}
}
#endif /* no alloca */

35
lib/basename.c Normal file
View File

@ -0,0 +1,35 @@
/* basename.c -- return the last element in a path
Copyright (C) 1990 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#if defined(USG) || defined(STDC_HEADERS)
#include <string.h>
#define rindex strrchr
#else
#include <strings.h>
#endif
/* Return NAME with any leading path stripped off. */
char *
basename (name)
char *name;
{
char *base;
base = rindex (name, '/');
return base ? base + 1 : name;
}

105
lib/error.c Normal file
View File

@ -0,0 +1,105 @@
/* error.c -- error handler for noninteractive utilities
Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by David MacKenzie. */
#include <stdio.h>
#ifdef HAVE_VPRINTF
#if __STDC__
#include <stdarg.h>
#define VA_START(args, lastarg) va_start(args, lastarg)
#else /* !__STDC__ */
#include <varargs.h>
#define VA_START(args, lastarg) va_start(args)
#endif /* !__STDC__ */
#else /* !HAVE_VPRINTF */
#ifdef HAVE_DOPRNT
#define va_alist args
#define va_dcl int args;
#else /* !HAVE_DOPRNT */
#define va_alist a1, a2, a3, a4, a5, a6, a7, a8
#define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
#endif /* !HAVE_DOPRNT */
#endif /* !HAVE_VPRINTF */
#ifdef STDC_HEADERS
#include <stdlib.h>
#include <string.h>
#else /* !STDC_HEADERS */
void exit ();
#endif /* !STDC_HEADERS */
#ifndef HAVE_STRERROR
static char *
private_strerror (errnum)
int errnum;
{
extern char *sys_errlist[];
extern int sys_nerr;
if (errnum > 0 && errnum <= sys_nerr)
return sys_errlist[errnum];
return "Unknown system error";
}
#define strerror private_strerror
#endif /* !HAVE_STRERROR */
/* Print the program name and error message MESSAGE, which is a printf-style
format string with optional args.
If ERRNUM is nonzero, print its corresponding system error message.
Exit with status STATUS if it is nonzero. */
/* VARARGS */
void
#if defined (HAVE_VPRINTF) && __STDC__
error (int status, int errnum, char *message, ...)
#else /* !HAVE_VPRINTF or !__STDC__ */
error (status, errnum, message, va_alist)
int status;
int errnum;
char *message;
va_dcl
#endif /* !HAVE_VPRINTF or !__STDC__ */
{
extern char *program_name;
#ifdef HAVE_VPRINTF
va_list args;
#endif /* HAVE_VPRINTF */
fprintf (stderr, "%s: ", program_name);
#ifdef HAVE_VPRINTF
VA_START (args, message);
vfprintf (stderr, message, args);
va_end (args);
#else /* !HAVE_VPRINTF */
#ifdef HAVE_DOPRNT
_doprnt (message, &args, stderr);
#else /* !HAVE_DOPRNT */
fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
#endif /* !HAVE_DOPRNT */
#endif /* !HAVE_VPRINTF */
if (errnum)
fprintf (stderr, ": %s", strerror (errnum));
putc ('\n', stderr);
fflush (stderr);
if (status)
exit (status);
}

965
lib/getdate.y Normal file
View File

@ -0,0 +1,965 @@
%{
/* $Revision: 2.1 $
**
** Originally written by Steven M. Bellovin <smb@research.att.com> while
** at the University of North Carolina at Chapel Hill. Later tweaked by
** a couple of people on Usenet. Completely overhauled by Rich $alz
** <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
** send any email to Rich.
**
** This grammar has eight shift/reduce conflicts.
**
** This code is in the public domain and has no copyright.
*/
/* SUPPRESS 287 on yaccpar_sccsid *//* Unusd static variable */
/* SUPPRESS 288 on yyerrlab *//* Label unused */
#ifdef __GNUC__
#define alloca __builtin_alloca
#else
#ifdef sparc
#include <alloca.h>
#else
#ifdef _AIX /* for Bison */
#pragma alloca
#else
char *alloca ();
#endif
#endif
#endif
#include <stdio.h>
#include <ctype.h>
/* The code at the top of get_date which figures out the offset of the
current time zone checks various CPP symbols to see if special
tricks are need, but defaults to using the gettimeofday system call.
Include <sys/time.h> if that will be used. */
#if !defined (USG) && !defined (sgi) && !defined (__386BSD__)
#include <sys/time.h>
#endif
#if defined(vms)
#include <types.h>
#include <time.h>
#else
#include <sys/types.h>
#if defined(USG) || !defined(HAVE_FTIME)
/*
** If you need to do a tzset() call to set the
** timezone, and don't have ftime().
*/
struct timeb {
time_t time; /* Seconds since the epoch */
unsigned short millitm; /* Field not used */
short timezone;
short dstflag; /* Field not used */
};
#else
#include <sys/timeb.h>
#endif /* defined(USG) && !defined(HAVE_FTIME) */
#if defined(BSD4_2) || defined(BSD4_1C) || (defined (hp9000) && !defined (hpux))
#include <sys/time.h>
#else
#if defined(_AIX)
#include <sys/time.h>
#endif
#include <time.h>
#endif /* defined(BSD4_2) */
#endif /* defined(vms) */
#if defined (STDC_HEADERS) || defined (USG)
#include <string.h>
#endif
#if sgi
#undef timezone
#endif
extern struct tm *localtime();
#define yyparse getdate_yyparse
#define yylex getdate_yylex
#define yyerror getdate_yyerror
#if !defined(lint) && !defined(SABER)
static char RCS[] =
"$Header: str2date.y,v 2.1 90/09/06 08:15:06 cronan Exp $";
#endif /* !defined(lint) && !defined(SABER) */
#define EPOCH 1970
#define HOUR(x) ((time_t)(x) * 60)
#define SECSPERDAY (24L * 60L * 60L)
/*
** An entry in the lexical lookup table.
*/
typedef struct _TABLE {
char *name;
int type;
time_t value;
} TABLE;
/*
** Daylight-savings mode: on, off, or not yet known.
*/
typedef enum _DSTMODE {
DSTon, DSToff, DSTmaybe
} DSTMODE;
/*
** Meridian: am, pm, or 24-hour style.
*/
typedef enum _MERIDIAN {
MERam, MERpm, MER24
} MERIDIAN;
/*
** Global variables. We could get rid of most of these by using a good
** union as the yacc stack. (This routine was originally written before
** yacc had the %union construct.) Maybe someday; right now we only use
** the %union very rarely.
*/
static char *yyInput;
static DSTMODE yyDSTmode;
static time_t yyDayOrdinal;
static time_t yyDayNumber;
static int yyHaveDate;
static int yyHaveDay;
static int yyHaveRel;
static int yyHaveTime;
static int yyHaveZone;
static time_t yyTimezone;
static time_t yyDay;
static time_t yyHour;
static time_t yyMinutes;
static time_t yyMonth;
static time_t yySeconds;
static time_t yyYear;
static MERIDIAN yyMeridian;
static time_t yyRelMonth;
static time_t yyRelSeconds;
%}
%union {
time_t Number;
enum _MERIDIAN Meridian;
}
%token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
%token tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST
%type <Number> tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
%type <Number> tSEC_UNIT tSNUMBER tUNUMBER tZONE
%type <Meridian> tMERIDIAN o_merid
%%
spec : /* NULL */
| spec item
;
item : time {
yyHaveTime++;
}
| zone {
yyHaveZone++;
}
| date {
yyHaveDate++;
}
| day {
yyHaveDay++;
}
| rel {
yyHaveRel++;
}
| number
;
time : tUNUMBER tMERIDIAN {
yyHour = $1;
yyMinutes = 0;
yySeconds = 0;
yyMeridian = $2;
}
| tUNUMBER ':' tUNUMBER o_merid {
yyHour = $1;
yyMinutes = $3;
yySeconds = 0;
yyMeridian = $4;
}
| tUNUMBER ':' tUNUMBER tSNUMBER {
yyHour = $1;
yyMinutes = $3;
yyMeridian = MER24;
yyDSTmode = DSToff;
yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
}
| tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
yyHour = $1;
yyMinutes = $3;
yySeconds = $5;
yyMeridian = $6;
}
| tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
yyHour = $1;
yyMinutes = $3;
yySeconds = $5;
yyMeridian = MER24;
yyDSTmode = DSToff;
yyTimezone = - ($6 % 100 + ($6 / 100) * 60);
}
;
zone : tZONE {
yyTimezone = $1;
yyDSTmode = DSToff;
}
| tDAYZONE {
yyTimezone = $1;
yyDSTmode = DSTon;
}
|
tZONE tDST {
yyTimezone = $1;
yyDSTmode = DSTon;
}
;
day : tDAY {
yyDayOrdinal = 1;
yyDayNumber = $1;
}
| tDAY ',' {
yyDayOrdinal = 1;
yyDayNumber = $1;
}
| tUNUMBER tDAY {
yyDayOrdinal = $1;
yyDayNumber = $2;
}
;
date : tUNUMBER '/' tUNUMBER {
yyMonth = $1;
yyDay = $3;
}
| tUNUMBER '/' tUNUMBER '/' tUNUMBER {
yyMonth = $1;
yyDay = $3;
yyYear = $5;
}
| tUNUMBER tSNUMBER tSNUMBER {
/* ISO 8601 format. yyyy-mm-dd. */
yyYear = $1;
yyMonth = -$2;
yyDay = -$3;
}
| tMONTH tUNUMBER {
yyMonth = $1;
yyDay = $2;
}
| tMONTH tUNUMBER ',' tUNUMBER {
yyMonth = $1;
yyDay = $2;
yyYear = $4;
}
| tUNUMBER tMONTH {
yyMonth = $2;
yyDay = $1;
}
| tUNUMBER tMONTH tUNUMBER {
yyMonth = $2;
yyDay = $1;
yyYear = $3;
}
;
rel : relunit tAGO {
yyRelSeconds = -yyRelSeconds;
yyRelMonth = -yyRelMonth;
}
| relunit
;
relunit : tUNUMBER tMINUTE_UNIT {
yyRelSeconds += $1 * $2 * 60L;
}
| tSNUMBER tMINUTE_UNIT {
yyRelSeconds += $1 * $2 * 60L;
}
| tMINUTE_UNIT {
yyRelSeconds += $1 * 60L;
}
| tSNUMBER tSEC_UNIT {
yyRelSeconds += $1;
}
| tUNUMBER tSEC_UNIT {
yyRelSeconds += $1;
}
| tSEC_UNIT {
yyRelSeconds++;
}
| tSNUMBER tMONTH_UNIT {
yyRelMonth += $1 * $2;
}
| tUNUMBER tMONTH_UNIT {
yyRelMonth += $1 * $2;
}
| tMONTH_UNIT {
yyRelMonth += $1;
}
;
number : tUNUMBER {
if (yyHaveTime && yyHaveDate && !yyHaveRel)
yyYear = $1;
else {
if($1>10000) {
time_t date_part;
date_part= $1/10000;
yyHaveDate++;
yyDay= (date_part)%100;
yyMonth= (date_part/100)%100;
yyYear = date_part/10000;
}
yyHaveTime++;
if ($1 < 100) {
yyHour = $1;
yyMinutes = 0;
}
else {
yyHour = $1 / 100;
yyMinutes = $1 % 100;
}
yySeconds = 0;
yyMeridian = MER24;
}
}
;
o_merid : /* NULL */ {
$$ = MER24;
}
| tMERIDIAN {
$$ = $1;
}
;
%%
/* Month and day table. */
static TABLE MonthDayTable[] = {
{ "january", tMONTH, 1 },
{ "february", tMONTH, 2 },
{ "march", tMONTH, 3 },
{ "april", tMONTH, 4 },
{ "may", tMONTH, 5 },
{ "june", tMONTH, 6 },
{ "july", tMONTH, 7 },
{ "august", tMONTH, 8 },
{ "september", tMONTH, 9 },
{ "sept", tMONTH, 9 },
{ "october", tMONTH, 10 },
{ "november", tMONTH, 11 },
{ "december", tMONTH, 12 },
{ "sunday", tDAY, 0 },
{ "monday", tDAY, 1 },
{ "tuesday", tDAY, 2 },
{ "tues", tDAY, 2 },
{ "wednesday", tDAY, 3 },
{ "wednes", tDAY, 3 },
{ "thursday", tDAY, 4 },
{ "thur", tDAY, 4 },
{ "thurs", tDAY, 4 },
{ "friday", tDAY, 5 },
{ "saturday", tDAY, 6 },
{ NULL }
};
/* Time units table. */
static TABLE UnitsTable[] = {
{ "year", tMONTH_UNIT, 12 },
{ "month", tMONTH_UNIT, 1 },
{ "fortnight", tMINUTE_UNIT, 14 * 24 * 60 },
{ "week", tMINUTE_UNIT, 7 * 24 * 60 },
{ "day", tMINUTE_UNIT, 1 * 24 * 60 },
{ "hour", tMINUTE_UNIT, 60 },
{ "minute", tMINUTE_UNIT, 1 },
{ "min", tMINUTE_UNIT, 1 },
{ "second", tSEC_UNIT, 1 },
{ "sec", tSEC_UNIT, 1 },
{ NULL }
};
/* Assorted relative-time words. */
static TABLE OtherTable[] = {
{ "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 },
{ "yesterday", tMINUTE_UNIT, -1 * 24 * 60 },
{ "today", tMINUTE_UNIT, 0 },
{ "now", tMINUTE_UNIT, 0 },
{ "last", tUNUMBER, -1 },
{ "this", tMINUTE_UNIT, 0 },
{ "next", tUNUMBER, 2 },
{ "first", tUNUMBER, 1 },
/* { "second", tUNUMBER, 2 }, */
{ "third", tUNUMBER, 3 },
{ "fourth", tUNUMBER, 4 },
{ "fifth", tUNUMBER, 5 },
{ "sixth", tUNUMBER, 6 },
{ "seventh", tUNUMBER, 7 },
{ "eighth", tUNUMBER, 8 },
{ "ninth", tUNUMBER, 9 },
{ "tenth", tUNUMBER, 10 },
{ "eleventh", tUNUMBER, 11 },
{ "twelfth", tUNUMBER, 12 },
{ "ago", tAGO, 1 },
{ NULL }
};
/* The timezone table. */
/* Some of these are commented out because a time_t can't store a float. */
static TABLE TimezoneTable[] = {
{ "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */
{ "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */
{ "utc", tZONE, HOUR( 0) },
{ "wet", tZONE, HOUR( 0) }, /* Western European */
{ "bst", tDAYZONE, HOUR( 0) }, /* British Summer */
{ "wat", tZONE, HOUR( 1) }, /* West Africa */
{ "at", tZONE, HOUR( 2) }, /* Azores */
#if 0
/* For completeness. BST is also British Summer, and GST is
* also Guam Standard. */
{ "bst", tZONE, HOUR( 3) }, /* Brazil Standard */
{ "gst", tZONE, HOUR( 3) }, /* Greenland Standard */
#endif
#if 0
{ "nft", tZONE, HOUR(3.5) }, /* Newfoundland */
{ "nst", tZONE, HOUR(3.5) }, /* Newfoundland Standard */
{ "ndt", tDAYZONE, HOUR(3.5) }, /* Newfoundland Daylight */
#endif
{ "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */
{ "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */
{ "est", tZONE, HOUR( 5) }, /* Eastern Standard */
{ "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */
{ "cst", tZONE, HOUR( 6) }, /* Central Standard */
{ "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */
{ "mst", tZONE, HOUR( 7) }, /* Mountain Standard */
{ "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */
{ "pst", tZONE, HOUR( 8) }, /* Pacific Standard */
{ "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */
{ "yst", tZONE, HOUR( 9) }, /* Yukon Standard */
{ "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */
{ "hst", tZONE, HOUR(10) }, /* Hawaii Standard */
{ "hdt", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */
{ "cat", tZONE, HOUR(10) }, /* Central Alaska */
{ "ahst", tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */
{ "nt", tZONE, HOUR(11) }, /* Nome */
{ "idlw", tZONE, HOUR(12) }, /* International Date Line West */
{ "cet", tZONE, -HOUR(1) }, /* Central European */
{ "met", tZONE, -HOUR(1) }, /* Middle European */
{ "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */
{ "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */
{ "swt", tZONE, -HOUR(1) }, /* Swedish Winter */
{ "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */
{ "fwt", tZONE, -HOUR(1) }, /* French Winter */
{ "fst", tDAYZONE, -HOUR(1) }, /* French Summer */
{ "eet", tZONE, -HOUR(2) }, /* Eastern Europe, USSR Zone 1 */
{ "bt", tZONE, -HOUR(3) }, /* Baghdad, USSR Zone 2 */
#if 0
{ "it", tZONE, -HOUR(3.5) },/* Iran */
#endif
{ "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */
{ "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */
#if 0
{ "ist", tZONE, -HOUR(5.5) },/* Indian Standard */
#endif
{ "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */
#if 0
/* For completeness. NST is also Newfoundland Stanard, and SST is
* also Swedish Summer. */
{ "nst", tZONE, -HOUR(6.5) },/* North Sumatra */
{ "sst", tZONE, -HOUR(7) }, /* South Sumatra, USSR Zone 6 */
#endif /* 0 */
{ "wast", tZONE, -HOUR(7) }, /* West Australian Standard */
{ "wadt", tDAYZONE, -HOUR(7) }, /* West Australian Daylight */
#if 0
{ "jt", tZONE, -HOUR(7.5) },/* Java (3pm in Cronusland!) */
#endif
{ "cct", tZONE, -HOUR(8) }, /* China Coast, USSR Zone 7 */
{ "jst", tZONE, -HOUR(9) }, /* Japan Standard, USSR Zone 8 */
#if 0
{ "cast", tZONE, -HOUR(9.5) },/* Central Australian Standard */
{ "cadt", tDAYZONE, -HOUR(9.5) },/* Central Australian Daylight */
#endif
{ "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */
{ "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */
{ "gst", tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */
{ "nzt", tZONE, -HOUR(12) }, /* New Zealand */
{ "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */
{ "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */
{ "idle", tZONE, -HOUR(12) }, /* International Date Line East */
{ NULL }
};
/* Military timezone table. */
static TABLE MilitaryTable[] = {
{ "a", tZONE, HOUR( 1) },
{ "b", tZONE, HOUR( 2) },
{ "c", tZONE, HOUR( 3) },
{ "d", tZONE, HOUR( 4) },
{ "e", tZONE, HOUR( 5) },
{ "f", tZONE, HOUR( 6) },
{ "g", tZONE, HOUR( 7) },
{ "h", tZONE, HOUR( 8) },
{ "i", tZONE, HOUR( 9) },
{ "k", tZONE, HOUR( 10) },
{ "l", tZONE, HOUR( 11) },
{ "m", tZONE, HOUR( 12) },
{ "n", tZONE, HOUR(- 1) },
{ "o", tZONE, HOUR(- 2) },
{ "p", tZONE, HOUR(- 3) },
{ "q", tZONE, HOUR(- 4) },
{ "r", tZONE, HOUR(- 5) },
{ "s", tZONE, HOUR(- 6) },
{ "t", tZONE, HOUR(- 7) },
{ "u", tZONE, HOUR(- 8) },
{ "v", tZONE, HOUR(- 9) },
{ "w", tZONE, HOUR(-10) },
{ "x", tZONE, HOUR(-11) },
{ "y", tZONE, HOUR(-12) },
{ "z", tZONE, HOUR( 0) },
{ NULL }
};
/* ARGSUSED */
int
yyerror(s)
char *s;
{
return 0;
}
static time_t
ToSeconds(Hours, Minutes, Seconds, Meridian)
time_t Hours;
time_t Minutes;
time_t Seconds;
MERIDIAN Meridian;
{
if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
return -1;
switch (Meridian) {
case MER24:
if (Hours < 0 || Hours > 23)
return -1;
return (Hours * 60L + Minutes) * 60L + Seconds;
case MERam:
if (Hours < 1 || Hours > 12)
return -1;
return (Hours * 60L + Minutes) * 60L + Seconds;
case MERpm:
if (Hours < 1 || Hours > 12)
return -1;
return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
}
/* NOTREACHED */
}
static time_t
Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode)
time_t Month;
time_t Day;
time_t Year;
time_t Hours;
time_t Minutes;
time_t Seconds;
MERIDIAN Meridian;
DSTMODE DSTmode;
{
static int DaysInMonth[12] = {
31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
time_t tod;
time_t Julian;
int i;
if (Year < 0)
Year = -Year;
if (Year < 100)
Year += 1900;
DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
? 29 : 28;
if (Year < EPOCH || Year > 1999
|| Month < 1 || Month > 12
/* Lint fluff: "conversion from long may lose accuracy" */
|| Day < 1 || Day > DaysInMonth[(int)--Month])
return -1;
for (Julian = Day - 1, i = 0; i < Month; i++)
Julian += DaysInMonth[i];
for (i = EPOCH; i < Year; i++)
Julian += 365 + (i % 4 == 0);
Julian *= SECSPERDAY;
Julian += yyTimezone * 60L;
if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
return -1;
Julian += tod;
if (DSTmode == DSTon
|| (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
Julian -= 60 * 60;
return Julian;
}
static time_t
DSTcorrect(Start, Future)
time_t Start;
time_t Future;
{
time_t StartDay;
time_t FutureDay;
StartDay = (localtime(&Start)->tm_hour + 1) % 24;
FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
}
static time_t
RelativeDate(Start, DayOrdinal, DayNumber)
time_t Start;
time_t DayOrdinal;
time_t DayNumber;
{
struct tm *tm;
time_t now;
now = Start;
tm = localtime(&now);
now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
return DSTcorrect(Start, now);
}
static time_t
RelativeMonth(Start, RelMonth)
time_t Start;
time_t RelMonth;
{
struct tm *tm;
time_t Month;
time_t Year;
if (RelMonth == 0)
return 0;
tm = localtime(&Start);
Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
Year = Month / 12;
Month = Month % 12 + 1;
return DSTcorrect(Start,
Convert(Month, (time_t)tm->tm_mday, Year,
(time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
MER24, DSTmaybe));
}
static int
LookupWord(buff)
char *buff;
{
register char *p;
register char *q;
register TABLE *tp;
int i;
int abbrev;
/* Make it lowercase. */
for (p = buff; *p; p++)
if (isupper(*p))
*p = tolower(*p);
if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
yylval.Meridian = MERam;
return tMERIDIAN;
}
if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
yylval.Meridian = MERpm;
return tMERIDIAN;
}
/* See if we have an abbreviation for a month. */
if (strlen(buff) == 3)
abbrev = 1;
else if (strlen(buff) == 4 && buff[3] == '.') {
abbrev = 1;
buff[3] = '\0';
}
else
abbrev = 0;
for (tp = MonthDayTable; tp->name; tp++) {
if (abbrev) {
if (strncmp(buff, tp->name, 3) == 0) {
yylval.Number = tp->value;
return tp->type;
}
}
else if (strcmp(buff, tp->name) == 0) {
yylval.Number = tp->value;
return tp->type;
}
}
for (tp = TimezoneTable; tp->name; tp++)
if (strcmp(buff, tp->name) == 0) {
yylval.Number = tp->value;
return tp->type;
}
if (strcmp(buff, "dst") == 0)
return tDST;
for (tp = UnitsTable; tp->name; tp++)
if (strcmp(buff, tp->name) == 0) {
yylval.Number = tp->value;
return tp->type;
}
/* Strip off any plural and try the units table again. */
i = strlen(buff) - 1;
if (buff[i] == 's') {
buff[i] = '\0';
for (tp = UnitsTable; tp->name; tp++)
if (strcmp(buff, tp->name) == 0) {
yylval.Number = tp->value;
return tp->type;
}
buff[i] = 's'; /* Put back for "this" in OtherTable. */
}
for (tp = OtherTable; tp->name; tp++)
if (strcmp(buff, tp->name) == 0) {
yylval.Number = tp->value;
return tp->type;
}
/* Military timezones. */
if (buff[1] == '\0' && isalpha(*buff)) {
for (tp = MilitaryTable; tp->name; tp++)
if (strcmp(buff, tp->name) == 0) {
yylval.Number = tp->value;
return tp->type;
}
}
/* Drop out any periods and try the timezone table again. */
for (i = 0, p = q = buff; *q; q++)
if (*q != '.')
*p++ = *q;
else
i++;
*p = '\0';
if (i)
for (tp = TimezoneTable; tp->name; tp++)
if (strcmp(buff, tp->name) == 0) {
yylval.Number = tp->value;
return tp->type;
}
return tID;
}
int
yylex()
{
register char c;
register char *p;
char buff[20];
int Count;
int sign;
for ( ; ; ) {
while (isspace(*yyInput))
yyInput++;
if (isdigit(c = *yyInput) || c == '-' || c == '+') {
if (c == '-' || c == '+') {
sign = c == '-' ? -1 : 1;
if (!isdigit(*++yyInput))
/* skip the '-' sign */
continue;
}
else
sign = 0;
for (yylval.Number = 0; isdigit(c = *yyInput++); )
yylval.Number = 10 * yylval.Number + c - '0';
yyInput--;
if (sign < 0)
yylval.Number = -yylval.Number;
return sign ? tSNUMBER : tUNUMBER;
}
if (isalpha(c)) {
for (p = buff; isalpha(c = *yyInput++) || c == '.'; )
if (p < &buff[sizeof buff - 1])
*p++ = c;
*p = '\0';
yyInput--;
return LookupWord(buff);
}
if (c != '(')
return *yyInput++;
Count = 0;
do {
c = *yyInput++;
if (c == '\0')
return c;
if (c == '(')
Count++;
else if (c == ')')
Count--;
} while (Count > 0);
}
}
time_t
get_date(p, now)
char *p;
struct timeb *now;
{
struct tm *tm;
struct timeb ftz;
time_t Start;
time_t tod;
yyInput = p;
if (now == NULL) {
now = &ftz;
#if !defined(HAVE_FTIME)
(void)time(&ftz.time);
/* Set the timezone global. */
tzset();
{
#if sgi
ftz.timezone = (int) _timezone / 60;
#else /* not sgi */
#ifdef __386BSD__
ftz.timezone = 0;
#else /* neither sgi nor 386BSD */
#if defined (USG)
extern time_t timezone;
ftz.timezone = (int) timezone / 60;
#else /* neither sgi nor 386BSD nor USG */
struct timeval tv;
struct timezone tz;
gettimeofday (&tv, &tz);
ftz.timezone = (int) tz.tz_minuteswest;
#endif /* neither sgi nor 386BSD nor USG */
#endif /* neither sgi nor 386BSD */
#endif /* not sgi */
}
#else /* HAVE_FTIME */
(void)ftime(&ftz);
#endif /* HAVE_FTIME */
}
tm = localtime(&now->time);
yyYear = tm->tm_year;
yyMonth = tm->tm_mon + 1;
yyDay = tm->tm_mday;
yyTimezone = now->timezone;
yyDSTmode = DSTmaybe;
yyHour = 0;
yyMinutes = 0;
yySeconds = 0;
yyMeridian = MER24;
yyRelSeconds = 0;
yyRelMonth = 0;
yyHaveDate = 0;
yyHaveDay = 0;
yyHaveRel = 0;
yyHaveTime = 0;
yyHaveZone = 0;
if (yyparse()
|| yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
return -1;
if (yyHaveDate || yyHaveTime || yyHaveDay) {
Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
yyMeridian, yyDSTmode);
if (Start < 0)
return -1;
}
else {
Start = now->time;
if (!yyHaveRel)
Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
}
Start += yyRelSeconds;
Start += RelativeMonth(Start, yyRelMonth);
if (yyHaveDay && !yyHaveDate) {
tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber);
Start += tod;
}
/* Have to do *something* with a legitimate -1 so it's distinguishable
* from the error return value. (Alternately could set errno on error.) */
return Start == -1 ? 0 : Start;
}
#if defined(TEST)
/* ARGSUSED */
main(ac, av)
int ac;
char *av[];
{
char buff[128];
time_t d;
(void)printf("Enter date, or blank line to exit.\n\t> ");
(void)fflush(stdout);
while (gets(buff) && buff[0]) {
d = get_date(buff, (struct timeb *)NULL);
if (d == -1)
(void)printf("Bad format - couldn't convert.\n");
else
(void)printf("%s", ctime(&d));
(void)printf("\t> ");
(void)fflush(stdout);
}
exit(0);
/* NOTREACHED */
}
#endif /* defined(TEST) */

49
lib/gethostname.c Normal file
View File

@ -0,0 +1,49 @@
/* gethostname emulation for SysV and POSIX.1.
Copyright (C) 1992 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* David MacKenzie <djm@gnu.ai.mit.edu> */
#ifdef HAVE_UNAME
#include <sys/utsname.h>
#endif
/* Put up to LEN chars of the host name into NAME.
Null terminate it if the name is shorter than LEN.
Return 0 if ok, -1 if error. */
int
gethostname (name, len)
char *name;
int len;
{
#ifdef HAVE_UNAME
struct utsname uts;
if (uname (&uts) == -1)
return -1;
if (len > sizeof (uts.nodename))
{
/* More space than we need is available. */
name[sizeof (uts.nodename)] = '\0';
len = sizeof (uts.nodename);
}
strncpy (name, uts.nodename, len);
#else
strcpy (name, ""); /* Hardcode your system name if you want. */
#endif
return 0;
}

679
lib/getopt.c Normal file
View File

@ -0,0 +1,679 @@
/* Getopt for GNU.
NOTE: getopt is now part of the C library, so if you don't know what
"Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
before changing it!
Copyright (C) 1987, 88, 89, 90, 91, 1992 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* AIX requires this to be the first thing in the file. */
#ifdef __GNUC__
#define alloca __builtin_alloca
#else /* not __GNUC__ */
#if defined (HAVE_ALLOCA_H) || (defined(sparc) && (defined(sun) || (!defined(USG) && !defined(SVR4) && !defined(__svr4__))))
#include <alloca.h>
#else
#ifdef _AIX
#pragma alloca
#else
char *alloca ();
#endif
#endif /* alloca.h */
#endif /* not __GNUC__ */
#include <stdio.h>
/* This needs to come after some library #include
to get __GNU_LIBRARY__ defined. */
#ifdef __GNU_LIBRARY__
#undef alloca
/* Don't include stdlib.h for non-GNU C libraries because some of them
contain conflicting prototypes for getopt. */
#include <stdlib.h>
#else /* Not GNU C library. */
#define __alloca alloca
#endif /* GNU C library. */
#if !__STDC__
#define const
#endif
/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
long-named option. Because this is not POSIX.2 compliant, it is
being phased out. */
#define GETOPT_COMPAT
/* This version of `getopt' appears to the caller like standard Unix `getopt'
but it behaves differently for the user, since it allows the user
to intersperse the options with the other arguments.
As `getopt' works, it permutes the elements of ARGV so that,
when it is done, all the options precede everything else. Thus
all application programs are extended to handle flexible argument order.
Setting the environment variable POSIXLY_CORRECT disables permutation.
Then the behavior is completely standard.
GNU application programs can use a third alternative mode in which
they can distinguish the relative order of options and other arguments. */
#include "getopt.h"
/* For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
char *optarg = 0;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to `getopt'.
On entry to `getopt', zero means this is the first call; initialize.
When `getopt' returns EOF, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
int optind = 0;
/* The next char to be scanned in the option-element
in which the last option character we returned was found.
This allows us to pick up the scan where we left off.
If this is zero, or a null string, it means resume the scan
by advancing to the next ARGV-element. */
static char *nextchar;
/* Callers store zero here to inhibit the error message
for unrecognized options. */
int opterr = 1;
/* Describe how to deal with options that follow non-option ARGV-elements.
If the caller did not specify anything,
the default is REQUIRE_ORDER if the environment variable
POSIXLY_CORRECT is defined, PERMUTE otherwise.
REQUIRE_ORDER means don't recognize them as options;
stop option processing when the first non-option is seen.
This is what Unix does.
This mode of operation is selected by either setting the environment
variable POSIXLY_CORRECT, or using `+' as the first character
of the list of option characters.
PERMUTE is the default. We permute the contents of ARGV as we scan,
so that eventually all the non-options are at the end. This allows options
to be given in any order, even with programs that were not written to
expect this.
RETURN_IN_ORDER is an option available to programs that were written
to expect options and other ARGV-elements in any order and that care about
the ordering of the two. We describe each non-option ARGV-element
as if it were the argument of an option with character code 1.
Using `-' as the first character of the list of option characters
selects this mode of operation.
The special argument `--' forces an end of option-scanning regardless
of the value of `ordering'. In the case of RETURN_IN_ORDER, only
`--' can cause `getopt' to return EOF with `optind' != ARGC. */
static enum
{
REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
} ordering;
#ifdef __GNU_LIBRARY__
/* We want to avoid inclusion of string.h with non-GNU libraries
because there are many ways it can cause trouble.
On some systems, it contains special magic macros that don't work
in GCC. */
#include <string.h>
#define my_index strchr
#define my_bcopy(src, dst, n) memcpy ((dst), (src), (n))
#else
/* Avoid depending on library functions or files
whose names are inconsistent. */
char *getenv ();
static char *
my_index (string, chr)
char *string;
int chr;
{
while (*string)
{
if (*string == chr)
return string;
string++;
}
return 0;
}
static void
my_bcopy (from, to, size)
char *from, *to;
int size;
{
int i;
for (i = 0; i < size; i++)
to[i] = from[i];
}
#endif /* GNU C library. */
/* Handle permutation of arguments. */
/* Describe the part of ARGV that contains non-options that have
been skipped. `first_nonopt' is the index in ARGV of the first of them;
`last_nonopt' is the index after the last of them. */
static int first_nonopt;
static int last_nonopt;
/* Exchange two adjacent subsequences of ARGV.
One subsequence is elements [first_nonopt,last_nonopt)
which contains all the non-options that have been skipped so far.
The other is elements [last_nonopt,optind), which contains all
the options processed since those non-options were skipped.
`first_nonopt' and `last_nonopt' are relocated so that they describe
the new indices of the non-options in ARGV after they are moved. */
static void
exchange (argv)
char **argv;
{
int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *);
char **temp = (char **) __alloca (nonopts_size);
/* Interchange the two blocks of data in ARGV. */
my_bcopy ((char *) &argv[first_nonopt], (char *) temp, nonopts_size);
my_bcopy ((char *) &argv[last_nonopt], (char *) &argv[first_nonopt],
(optind - last_nonopt) * sizeof (char *));
my_bcopy ((char *) temp,
(char *) &argv[first_nonopt + optind - last_nonopt],
nonopts_size);
/* Update records for the slots the non-options now occupy. */
first_nonopt += (optind - last_nonopt);
last_nonopt = optind;
}
/* Scan elements of ARGV (whose length is ARGC) for option characters
given in OPTSTRING.
If an element of ARGV starts with '-', and is not exactly "-" or "--",
then it is an option element. The characters of this element
(aside from the initial '-') are option characters. If `getopt'
is called repeatedly, it returns successively each of the option characters
from each of the option elements.
If `getopt' finds another option character, it returns that character,
updating `optind' and `nextchar' so that the next call to `getopt' can
resume the scan with the following option character or ARGV-element.
If there are no more option characters, `getopt' returns `EOF'.
Then `optind' is the index in ARGV of the first ARGV-element
that is not an option. (The ARGV-elements have been permuted
so that those that are not options now come last.)
OPTSTRING is a string containing the legitimate option characters.
If an option character is seen that is not listed in OPTSTRING,
return '?' after printing an error message. If you set `opterr' to
zero, the error message is suppressed but we still return '?'.
If a char in OPTSTRING is followed by a colon, that means it wants an arg,
so the following text in the same ARGV-element, or the text of the following
ARGV-element, is returned in `optarg'. Two colons mean an option that
wants an optional arg; if there is text in the current ARGV-element,
it is returned in `optarg', otherwise `optarg' is set to zero.
If OPTSTRING starts with `-' or `+', it requests different methods of
handling the non-option ARGV-elements.
See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
Long-named options begin with `--' instead of `-'.
Their names may be abbreviated as long as the abbreviation is unique
or is an exact match for some defined option. If they have an
argument, it follows the option name in the same ARGV-element, separated
from the option name by a `=', or else the in next ARGV-element.
When `getopt' finds a long-named option, it returns 0 if that option's
`flag' field is nonzero, the value of the option's `val' field
if the `flag' field is zero.
The elements of ARGV aren't really const, because we permute them.
But we pretend they're const in the prototype to be compatible
with other systems.
LONGOPTS is a vector of `struct option' terminated by an
element containing a name which is zero.
LONGIND returns the index in LONGOPT of the long-named option found.
It is only valid when a long-named option has been found by the most
recent call.
If LONG_ONLY is nonzero, '-' as well as '--' can introduce
long-named options. */
int
_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
int argc;
char *const *argv;
const char *optstring;
const struct option *longopts;
int *longind;
int long_only;
{
int option_index;
optarg = 0;
/* Initialize the internal data when the first call is made.
Start processing options with ARGV-element 1 (since ARGV-element 0
is the program name); the sequence of previously skipped
non-option ARGV-elements is empty. */
if (optind == 0)
{
first_nonopt = last_nonopt = optind = 1;
nextchar = NULL;
/* Determine how to handle the ordering of options and nonoptions. */
if (optstring[0] == '-')
{
ordering = RETURN_IN_ORDER;
++optstring;
}
else if (optstring[0] == '+')
{
ordering = REQUIRE_ORDER;
++optstring;
}
else if (getenv ("POSIXLY_CORRECT") != NULL)
ordering = REQUIRE_ORDER;
else
ordering = PERMUTE;
}
if (nextchar == NULL || *nextchar == '\0')
{
if (ordering == PERMUTE)
{
/* If we have just processed some options following some non-options,
exchange them so that the options come first. */
if (first_nonopt != last_nonopt && last_nonopt != optind)
exchange ((char **) argv);
else if (last_nonopt != optind)
first_nonopt = optind;
/* Now skip any additional non-options
and extend the range of non-options previously skipped. */
while (optind < argc
&& (argv[optind][0] != '-' || argv[optind][1] == '\0')
#ifdef GETOPT_COMPAT
&& (longopts == NULL
|| argv[optind][0] != '+' || argv[optind][1] == '\0')
#endif /* GETOPT_COMPAT */
)
optind++;
last_nonopt = optind;
}
/* Special ARGV-element `--' means premature end of options.
Skip it like a null option,
then exchange with previous non-options as if it were an option,
then skip everything else like a non-option. */
if (optind != argc && !strcmp (argv[optind], "--"))
{
optind++;
if (first_nonopt != last_nonopt && last_nonopt != optind)
exchange ((char **) argv);
else if (first_nonopt == last_nonopt)
first_nonopt = optind;
last_nonopt = argc;
optind = argc;
}
/* If we have done all the ARGV-elements, stop the scan
and back over any non-options that we skipped and permuted. */
if (optind == argc)
{
/* Set the next-arg-index to point at the non-options
that we previously skipped, so the caller will digest them. */
if (first_nonopt != last_nonopt)
optind = first_nonopt;
return EOF;
}
/* If we have come to a non-option and did not permute it,
either stop the scan or describe it to the caller and pass it by. */
if ((argv[optind][0] != '-' || argv[optind][1] == '\0')
#ifdef GETOPT_COMPAT
&& (longopts == NULL
|| argv[optind][0] != '+' || argv[optind][1] == '\0')
#endif /* GETOPT_COMPAT */
)
{
if (ordering == REQUIRE_ORDER)
return EOF;
optarg = argv[optind++];
return 1;
}
/* We have found another option-ARGV-element.
Start decoding its characters. */
nextchar = (argv[optind] + 1
+ (longopts != NULL && argv[optind][1] == '-'));
}
if (longopts != NULL
&& ((argv[optind][0] == '-'
&& (argv[optind][1] == '-' || long_only))
#ifdef GETOPT_COMPAT
|| argv[optind][0] == '+'
#endif /* GETOPT_COMPAT */
))
{
const struct option *p;
char *s = nextchar;
int exact = 0;
int ambig = 0;
const struct option *pfound = NULL;
int indfound;
while (*s && *s != '=')
s++;
/* Test all options for either exact match or abbreviated matches. */
for (p = longopts, option_index = 0; p->name;
p++, option_index++)
if (!strncmp (p->name, nextchar, s - nextchar))
{
if (s - nextchar == strlen (p->name))
{
/* Exact match found. */
pfound = p;
indfound = option_index;
exact = 1;
break;
}
else if (pfound == NULL)
{
/* First nonexact match found. */
pfound = p;
indfound = option_index;
}
else
/* Second nonexact match found. */
ambig = 1;
}
if (ambig && !exact)
{
if (opterr)
fprintf (stderr, "%s: option `%s' is ambiguous\n",
argv[0], argv[optind]);
nextchar += strlen (nextchar);
optind++;
return '?';
}
if (pfound != NULL)
{
option_index = indfound;
optind++;
if (*s)
{
/* Don't test has_arg with >, because some C compilers don't
allow it to be used on enums. */
if (pfound->has_arg)
optarg = s + 1;
else
{
if (opterr)
{
if (argv[optind - 1][1] == '-')
/* --option */
fprintf (stderr,
"%s: option `--%s' doesn't allow an argument\n",
argv[0], pfound->name);
else
/* +option or -option */
fprintf (stderr,
"%s: option `%c%s' doesn't allow an argument\n",
argv[0], argv[optind - 1][0], pfound->name);
}
nextchar += strlen (nextchar);
return '?';
}
}
else if (pfound->has_arg == 1)
{
if (optind < argc)
optarg = argv[optind++];
else
{
if (opterr)
fprintf (stderr, "%s: option `%s' requires an argument\n",
argv[0], argv[optind - 1]);
nextchar += strlen (nextchar);
return '?';
}
}
nextchar += strlen (nextchar);
if (longind != NULL)
*longind = option_index;
if (pfound->flag)
{
*(pfound->flag) = pfound->val;
return 0;
}
return pfound->val;
}
/* Can't find it as a long option. If this is not getopt_long_only,
or the option starts with '--' or is not a valid short
option, then it's an error.
Otherwise interpret it as a short option. */
if (!long_only || argv[optind][1] == '-'
#ifdef GETOPT_COMPAT
|| argv[optind][0] == '+'
#endif /* GETOPT_COMPAT */
|| my_index (optstring, *nextchar) == NULL)
{
if (opterr)
{
if (argv[optind][1] == '-')
/* --option */
fprintf (stderr, "%s: unrecognized option `--%s'\n",
argv[0], nextchar);
else
/* +option or -option */
fprintf (stderr, "%s: unrecognized option `%c%s'\n",
argv[0], argv[optind][0], nextchar);
}
nextchar = (char *) "";
optind++;
return '?';
}
}
/* Look at and handle the next option-character. */
{
char c = *nextchar++;
char *temp = my_index (optstring, c);
/* Increment `optind' when we start to process its last character. */
if (*nextchar == '\0')
++optind;
if (temp == NULL || c == ':')
{
if (opterr)
{
if (c < 040 || c >= 0177)
fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
argv[0], c);
else
fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
}
return '?';
}
if (temp[1] == ':')
{
if (temp[2] == ':')
{
/* This is an option that accepts an argument optionally. */
if (*nextchar != '\0')
{
optarg = nextchar;
optind++;
}
else
optarg = 0;
nextchar = NULL;
}
else
{
/* This is an option that requires an argument. */
if (*nextchar != '\0')
{
optarg = nextchar;
/* If we end this ARGV-element by taking the rest as an arg,
we must advance to the next element now. */
optind++;
}
else if (optind == argc)
{
if (opterr)
fprintf (stderr, "%s: option `-%c' requires an argument\n",
argv[0], c);
c = '?';
}
else
/* We already incremented `optind' once;
increment it again when taking next ARGV-elt as argument. */
optarg = argv[optind++];
nextchar = NULL;
}
}
return c;
}
}
int
getopt (argc, argv, optstring)
int argc;
char *const *argv;
const char *optstring;
{
return _getopt_internal (argc, argv, optstring,
(const struct option *) 0,
(int *) 0,
0);
}
#ifdef TEST
/* Compile with -DTEST to make an executable for use in testing
the above definition of `getopt'. */
int
main (argc, argv)
int argc;
char **argv;
{
int c;
int digit_optind = 0;
while (1)
{
int this_option_optind = optind ? optind : 1;
c = getopt (argc, argv, "abc:d:0123456789");
if (c == EOF)
break;
switch (c)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (digit_optind != 0 && digit_optind != this_option_optind)
printf ("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf ("option %c\n", c);
break;
case 'a':
printf ("option a\n");
break;
case 'b':
printf ("option b\n");
break;
case 'c':
printf ("option c with value `%s'\n", optarg);
break;
case '?':
break;
default:
printf ("?? getopt returned character code 0%o ??\n", c);
}
}
if (optind < argc)
{
printf ("non-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
printf ("\n");
}
exit (0);
}
#endif /* TEST */

125
lib/getopt.h Normal file
View File

@ -0,0 +1,125 @@
/* Declarations for getopt.
Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef _GETOPT_H
#define _GETOPT_H 1
#ifdef __cplusplus
extern "C" {
#endif
/* For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
extern char *optarg;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to `getopt'.
On entry to `getopt', zero means this is the first call; initialize.
When `getopt' returns EOF, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
extern int optind;
/* Callers store zero here to inhibit the error message `getopt' prints
for unrecognized options. */
extern int opterr;
/* Describe the long-named options requested by the application.
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
of `struct option' terminated by an element containing a name which is
zero.
The field `has_arg' is:
no_argument (or 0) if the option does not take an argument,
required_argument (or 1) if the option requires an argument,
optional_argument (or 2) if the option takes an optional argument.
If the field `flag' is not NULL, it points to a variable that is set
to the value given in the field `val' when the option is found, but
left unchanged if the option is not found.
To have a long-named option do something other than set an `int' to
a compiled-in constant, such as set a value from `optarg', set the
option's `flag' field to zero and its `val' field to a nonzero
value (the equivalent single-letter option character, if there is
one). For long options that have a zero `flag' field, `getopt'
returns the contents of the `val' field. */
struct option
{
#if __STDC__
const char *name;
#else
char *name;
#endif
/* has_arg can't be an enum because some compilers complain about
type mismatches in all the code that assumes it is an int. */
int has_arg;
int *flag;
int val;
};
/* Names for the values of the `has_arg' field of `struct option'. */
#define no_argument 0
#define required_argument 1
#define optional_argument 2
#if __STDC__
#if defined(__GNU_LIBRARY__)
/* Many other libraries have conflicting prototypes for getopt, with
differences in the consts, in stdlib.h. To avoid compilation
errors, only prototype getopt for the GNU C library. */
extern int getopt (int argc, char *const *argv, const char *shortopts);
#else /* not __GNU_LIBRARY__ */
extern int getopt ();
#endif /* not __GNU_LIBRARY__ */
extern int getopt_long (int argc, char *const *argv, const char *shortopts,
const struct option *longopts, int *longind);
extern int getopt_long_only (int argc, char *const *argv,
const char *shortopts,
const struct option *longopts, int *longind);
/* Internal only. Users should not call this directly. */
extern int _getopt_internal (int argc, char *const *argv,
const char *shortopts,
const struct option *longopts, int *longind,
int long_only);
#else /* not __STDC__ */
extern int getopt ();
extern int getopt_long ();
extern int getopt_long_only ();
extern int _getopt_internal ();
#endif /* not __STDC__ */
#ifdef __cplusplus
}
#endif
#endif /* _GETOPT_H */

153
lib/getopt1.c Normal file
View File

@ -0,0 +1,153 @@
/* Getopt for GNU.
Copyright (C) 1987, 88, 89, 90, 91, 1992 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "getopt.h"
#ifndef __STDC__
#define const
#endif
#if defined(STDC_HEADERS) || defined(__GNU_LIBRARY__) || defined (LIBC)
#include <stdlib.h>
#else /* STDC_HEADERS or __GNU_LIBRARY__ */
char *getenv ();
#endif /* STDC_HEADERS or __GNU_LIBRARY__ */
#ifndef NULL
#define NULL 0
#endif
int
getopt_long (argc, argv, options, long_options, opt_index)
int argc;
char *const *argv;
const char *options;
const struct option *long_options;
int *opt_index;
{
return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
}
/* Like getopt_long, but '-' as well as '--' can indicate a long option.
If an option that starts with '-' (not '--') doesn't match a long option,
but does match a short option, it is parsed as a short option
instead. */
int
getopt_long_only (argc, argv, options, long_options, opt_index)
int argc;
char *const *argv;
const char *options;
const struct option *long_options;
int *opt_index;
{
return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
}
#ifdef TEST
#include <stdio.h>
int
main (argc, argv)
int argc;
char **argv;
{
int c;
int digit_optind = 0;
while (1)
{
int this_option_optind = optind ? optind : 1;
int option_index = 0;
static struct option long_options[] =
{
{"add", 1, 0, 0},
{"append", 0, 0, 0},
{"delete", 1, 0, 0},
{"verbose", 0, 0, 0},
{"create", 0, 0, 0},
{"file", 1, 0, 0},
{0, 0, 0, 0}
};
c = getopt_long (argc, argv, "abc:d:0123456789",
long_options, &option_index);
if (c == EOF)
break;
switch (c)
{
case 0:
printf ("option %s", long_options[option_index].name);
if (optarg)
printf (" with arg %s", optarg);
printf ("\n");
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (digit_optind != 0 && digit_optind != this_option_optind)
printf ("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf ("option %c\n", c);
break;
case 'a':
printf ("option a\n");
break;
case 'b':
printf ("option b\n");
break;
case 'c':
printf ("option c with value `%s'\n", optarg);
break;
case 'd':
printf ("option d with value `%s'\n", optarg);
break;
case '?':
break;
default:
printf ("?? getopt returned character code 0%o ??\n", c);
}
}
if (optind < argc)
{
printf ("non-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
printf ("\n");
}
exit (0);
}
#endif /* TEST */

86
lib/getugroups.c Normal file
View File

@ -0,0 +1,86 @@
/* getugroups.c -- return a list of the groups a user is in
Copyright (C) 1990, 1991 Free Software Foundation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by David MacKenzie. */
#include <sys/types.h>
#include <grp.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
/* Even though SunOS 4, Ultrix 4, and 386BSD are mostly POSIX.1 compliant,
their getgroups system call (except in the `System V' environment, which
is troublesome in other ways) fills in an array of int, not gid_t
(which is `short' on those systems). We do the same, for consistency.
Kludge, kludge. */
#ifdef _POSIX_VERSION
#if !defined(sun) && !defined(ultrix) && !defined(__386BSD__)
#define GETGROUPS_T gid_t
#else /* sun or ultrix or 386BSD */
#define GETGROUPS_T int
#endif /* sun or ultrix or 386BSD */
#else /* not _POSIX_VERSION */
#define GETGROUPS_T int
#endif /* not _POSIX_VERSION */
/* setgrent, getgrent, and endgrent are not specified by POSIX.1,
so header files might not declare them.
If you don't have them at all, we can't implement this function.
You lose! */
struct group *getgrent ();
#if defined(USG) || defined(STDC_HEADERS)
#include <string.h>
#else
#include <strings.h>
#endif
/* Like `getgroups', but for user USERNAME instead of for
the current process. */
int
getugroups (maxcount, grouplist, username)
int maxcount;
GETGROUPS_T *grouplist;
char *username;
{
struct group *grp;
register char **cp;
register int count = 0;
setgrent ();
while ((grp = getgrent ()) != 0)
for (cp = grp->gr_mem; *cp; ++cp)
if (!strcmp (username, *cp))
{
if (maxcount != 0)
{
if (count >= maxcount)
{
endgrent ();
return count;
}
grouplist[count] = grp->gr_gid;
}
count++;
}
endgrent ();
return count;
}

196
lib/getusershell.c Normal file
View File

@ -0,0 +1,196 @@
/* getusershell.c -- Return names of valid user shells.
Copyright (C) 1991 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by David MacKenzie <djm@gnu.ai.mit.edu> */
#ifndef SHELLS_FILE
/* File containing a list of nonrestricted shells, one per line. */
#define SHELLS_FILE "/etc/shells"
#endif
#include <stdio.h>
#include <ctype.h>
#ifdef STDC_HEADERS
#include <stdlib.h>
#else
char *malloc ();
char *realloc ();
#endif
static int readname ();
/* List of shells to use if the shells file is missing. */
static char *default_shells[] =
{
"/bin/sh", "/bin/csh", "/usr/bin/sh", "/usr/bin/csh", NULL
};
/* Index of the next shell in `default_shells' to return.
0 means we are not using `default_shells'. */
static int default_index = 0;
/* Input stream from the shells file. */
static FILE *shellstream = NULL;
/* Line of input from the shells file. */
static char *line = NULL;
/* Number of bytes allocated for `line'. */
static int line_size = 0;
/* Return an entry from the shells file, ignoring comment lines.
Return NULL if there are no more entries. */
char *
getusershell ()
{
if (default_index > 0)
{
if (default_shells[default_index])
/* Not at the end of the list yet. */
return default_shells[default_index++];
return NULL;
}
if (shellstream == NULL)
{
shellstream = fopen (SHELLS_FILE, "r");
if (shellstream == NULL)
{
/* No shells file. Use the default list. */
default_index = 1;
return default_shells[0];
}
}
while (readname (&line, &line_size, shellstream))
{
if (*line != '#')
return line;
}
return NULL; /* End of file. */
}
/* Rewind the shells file. */
void
setusershell ()
{
default_index = 0;
if (shellstream == NULL)
shellstream = fopen (SHELLS_FILE, "r");
else
fseek (shellstream, 0L, 0);
}
/* Close the shells file. */
void
endusershell ()
{
if (shellstream)
{
fclose (shellstream);
shellstream = NULL;
}
}
/* Allocate N bytes of memory dynamically, with error checking. */
static char *
xmalloc (n)
unsigned n;
{
char *p;
p = malloc (n);
if (p == 0)
{
fprintf (stderr, "virtual memory exhausted\n");
exit (1);
}
return p;
}
/* Reallocate space P to size N, with error checking. */
static char *
xrealloc (p, n)
char *p;
unsigned n;
{
p = realloc (p, n);
if (p == 0)
{
fprintf (stderr, "virtual memory exhausted\n");
exit (1);
}
return p;
}
/* Read a line from STREAM, removing any newline at the end.
Place the result in *NAME, which is malloc'd
and/or realloc'd as necessary and can start out NULL,
and whose size is passed and returned in *SIZE.
Return the number of characters placed in *NAME
if some nonempty sequence was found, otherwise 0. */
static int
readname (name, size, stream)
char **name;
int *size;
FILE *stream;
{
int c;
int name_index = 0;
if (*name == NULL)
{
*size = 10;
*name = (char *) xmalloc (*size);
}
/* Skip blank space. */
while ((c = getc (stream)) != EOF && isspace (c))
/* Do nothing. */ ;
while (c != EOF && !isspace (c))
{
(*name)[name_index++] = c;
while (name_index >= *size)
{
*size *= 2;
*name = (char *) xrealloc (*name, *size);
}
c = getc (stream);
}
(*name)[name_index] = '\0';
return name_index;
}
#ifdef TEST
main ()
{
char *s;
while (s = getusershell ())
puts (s);
exit (0);
}
#endif

224
lib/mktime.c Normal file
View File

@ -0,0 +1,224 @@
/* Copyright (C) 1991 Free Software Foundation, Inc.
This file is part of the GNU C Library.
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., 675 Mass Ave,
Cambridge, MA 02139, USA. */
#include <sys/types.h>
#include <errno.h>
#ifndef STDC_HEADERS
extern int errno;
#endif
#ifdef TM_IN_SYS_TIME
#include <sys/time.h>
#else
#include <time.h>
#endif
#ifdef HAVE_LIMITS_H
#include <limits.h>
#else
#define LONG_MAX (~(1 << (sizeof (long) * 8 - 1)))
#define LONG_MIN (-LONG_MAX - 1)
#define INT_MAX (~(1 << (sizeof (int) * 8 - 1)))
#define INT_MIN (-INT_MAX - 1)
#endif
#ifndef NULL
#define NULL 0
#endif
#ifndef __isleap
/* Nonzero if YEAR is a leap year (every 4 years,
except every 100th isn't, and every 1000th is). */
#define __isleap(year) \
((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 1000 == 0))
#endif
/* How many days are in each month. */
static unsigned short int __mon_lengths[2][12] =
{
/* Normal years. */
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
/* Leap years. */
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
};
#define invalid() return (time_t) -1
/* Return the `time_t' representation of TP and normalizes TP.
Return (time_t) -1 if TP is not representable as a `time_t'.
Note that 31 Dec 1969 23:59:59 is not representable
because it is represented as (time_t) -1. */
time_t
mktime(tp)
register struct tm *tp;
{
static struct tm min, max;
static char init = 0;
register time_t result;
register time_t t;
register int i;
register unsigned short *l;
register struct tm *new;
time_t end;
if (tp == NULL)
{
errno = EINVAL;
invalid();
}
if (!init)
{
init = 1;
end = (time_t) LONG_MIN;
new = gmtime(&end);
if (new != NULL)
min = *new;
else
min.tm_sec = min.tm_min = min.tm_hour =
min.tm_mday = min.tm_mon = min.tm_year = INT_MIN;
end = (time_t) LONG_MAX;
new = gmtime(&end);
if (new != NULL)
max = *new;
else
max.tm_sec = max.tm_min = max.tm_hour =
max.tm_mday = max.tm_mon = max.tm_year = INT_MAX;
}
/* Make all the elements of TP that we pay attention to
be within the ranges of reasonable values for those things. */
#define normalize(elt, min, max, nextelt) \
while (tp->elt < min) \
{ \
--tp->nextelt; \
tp->elt += max + 1; \
} \
while (tp->elt > max) \
{ \
++tp->nextelt; \
tp->elt -= max + 1; \
}
normalize (tm_sec, 0, 59, tm_min);
normalize (tm_min, 0, 59, tm_hour);
normalize (tm_hour, 0, 24, tm_mday);
/* Normalize the month first so we can use
it to figure the range for the day. */
normalize (tm_mon, 0, 11, tm_year);
normalize (tm_mday, 1, __mon_lengths[__isleap (tp->tm_year)][tp->tm_mon],
tm_mon);
/* Normalize the month again, since normalizing
the day may have pushed it out of range. */
normalize (tm_mon, 0, 11, tm_year);
/* Normalize the day again, because normalizing
the month may have changed the range. */
normalize (tm_mday, 1, __mon_lengths[__isleap (tp->tm_year)][tp->tm_mon],
tm_mon);
/* Check for out-of-range values. */
#define lowhigh(field, minmax, cmp) (tp->field cmp minmax.field)
#define low(field) lowhigh(field, min, <)
#define high(field) lowhigh(field, max, >)
#define oor(field) (low(field) || high(field))
#define lowbound(field) (tp->field == min.field)
#define highbound(field) (tp->field == max.field)
if (oor(tm_year))
invalid();
else if (lowbound(tm_year))
{
if (low(tm_mon))
invalid();
else if (lowbound(tm_mon))
{
if (low(tm_mday))
invalid();
else if (lowbound(tm_mday))
{
if (low(tm_hour))
invalid();
else if (lowbound(tm_hour))
{
if (low(tm_min))
invalid();
else if (lowbound(tm_min))
{
if (low(tm_sec))
invalid();
}
}
}
}
}
else if (highbound(tm_year))
{
if (high(tm_mon))
invalid();
else if (highbound(tm_mon))
{
if (high(tm_mday))
invalid();
else if (highbound(tm_mday))
{
if (high(tm_hour))
invalid();
else if (highbound(tm_hour))
{
if (high(tm_min))
invalid();
else if (highbound(tm_min))
{
if (high(tm_sec))
invalid();
}
}
}
}
}
t = 0;
for (i = 1970; i > 1900 + tp->tm_year; --i)
t -= __isleap(i) ? 366 : 365;
for (i = 1970; i < 1900 + tp->tm_year; ++i)
t += __isleap(i) ? 366 : 365;
l = __mon_lengths[__isleap(1900 + tp->tm_year)];
for (i = 0; i < tp->tm_mon; ++i)
t += l[i];
t += tp->tm_mday - 1;
result = ((t * 60 * 60 * 24) +
(tp->tm_hour * 60 * 60) +
(tp->tm_min * 60) +
tp->tm_sec);
end = result;
#if 0 /* This code breaks it, on SunOS anyway. */
if (tp->tm_isdst < 0)
new = localtime(&end);
else
#endif
new = gmtime(&end);
if (new == NULL)
invalid();
new->tm_isdst = tp->tm_isdst;
*tp = *new;
return result;
}

173
lib/posixtm.y Normal file
View File

@ -0,0 +1,173 @@
/* Parse dates for touch.
Copyright (C) 1989, 1990, 1991 Free Software Foundation Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by Jim Kingdon and David MacKenzie. */
%{
#ifdef __GNUC__
#define alloca __builtin_alloca
#else
#ifdef sparc
#include <alloca.h>
#else
#ifdef _AIX
#pragma alloca
#else
char *alloca ();
#endif
#endif
#endif
#include <stdio.h>
#include <sys/types.h>
#include <time.h>
#define YYDEBUG 1
/* Lexical analyzer's current scan position in the input string. */
static char *curpos;
/* The return value. */
static struct tm t;
time_t mktime ();
#define yyparse posixtime_yyparse
static int yylex ();
static int yyerror ();
%}
%token DIGIT
%%
date :
digitpair /* month */
digitpair /* day */
digitpair /* hours */
digitpair /* minutes */
year
seconds {
if ($1 >= 1 && $1 <= 12)
t.tm_mon = $1 - 1;
else {
YYABORT;
}
if ($2 >= 1 && $2 <= 31)
t.tm_mday = $2;
else {
YYABORT;
}
if ($3 >= 0 && $3 <= 23)
t.tm_hour = $3;
else {
YYABORT;
}
if ($4 >= 0 && $4 <= 59)
t.tm_min = $4;
else {
YYABORT;
}
}
year : digitpair {
t.tm_year = $1;
/* Deduce the century based on the year.
See POSIX.2 section 4.63.3. */
if ($1 <= 68)
t.tm_year += 100;
}
| digitpair digitpair {
t.tm_year = $1 * 100 + $2;
if (t.tm_year < 1900) {
YYABORT;
} else
t.tm_year -= 1900;
}
| /* empty */ {
time_t now;
struct tm *tmp;
/* Use current year. */
time (&now);
tmp = localtime (&now);
t.tm_year = tmp->tm_year;
}
;
seconds : /* empty */ {
t.tm_sec = 0;
}
| '.' digitpair {
if ($2 >= 0 && $2 <= 61)
t.tm_sec = $2;
else {
YYABORT;
}
}
;
digitpair : DIGIT DIGIT {
$$ = $1 * 10 + $2;
}
;
%%
static int
yylex ()
{
char ch = *curpos++;
if (ch >= '0' && ch <= '9')
{
yylval = ch - '0';
return DIGIT;
}
else if (ch == '.' || ch == 0)
return ch;
else
return '?'; /* Cause an error. */
}
static int
yyerror ()
{
return 0;
}
/* Parse a POSIX-style date and return it, or (time_t)-1 for an error. */
time_t
posixtime (s)
char *s;
{
curpos = s;
/* Let mktime decide whether it is daylight savings time. */
t.tm_isdst = -1;
if (yyparse ())
return (time_t)-1;
else
return mktime (&t);
}
/* Parse a POSIX-style date and return it, or NULL for an error. */
struct tm *
posixtm (s)
char *s;
{
if (posixtime (s) == -1)
return NULL;
return &t;
}

101
lib/putenv.c Normal file
View File

@ -0,0 +1,101 @@
/* Copyright (C) 1991 Free Software Foundation, Inc.
This file is part of the GNU C Library.
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., 675 Mass Ave,
Cambridge, MA 02139, USA. */
#include <sys/types.h>
#include <errno.h>
#ifdef STDC_HEADERS
#include <stdlib.h>
#else
extern int errno;
#endif
#if defined(STDC_HEADERS) || defined(USG)
#include <string.h>
#define index strchr
#define bcopy(s, d, n) memcpy((d), (s), (n))
#else /* not (STDC_HEADERS or USG) */
#include <strings.h>
#endif /* STDC_HEADERS or USG */
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifndef NULL
#define NULL 0
#endif
#if !__STDC__
#define const
#endif
extern char **environ;
/* Put STRING, which is of the form "NAME=VALUE", in the environment. */
int
putenv (string)
const char *string;
{
char *name_end = index (string, '=');
register size_t size;
register char **ep;
if (name_end == NULL)
{
/* Remove the variable from the environment. */
size = strlen (string);
for (ep = environ; *ep != NULL; ++ep)
if (!strncmp (*ep, string, size) && (*ep)[size] == '=')
{
while (ep[1] != NULL)
{
ep[0] = ep[1];
++ep;
}
*ep = NULL;
return 0;
}
}
size = 0;
for (ep = environ; *ep != NULL; ++ep)
if (!strncmp (*ep, string, name_end - string) &&
(*ep)[name_end - string] == '=')
break;
else
++size;
if (*ep == NULL)
{
static char **last_environ = NULL;
char **new_environ = (char **) malloc ((size + 2) * sizeof (char *));
if (new_environ == NULL)
return -1;
(void) bcopy ((char *) environ, (char *) new_environ, size * sizeof (char *));
new_environ[size] = (char *) string;
new_environ[size + 1] = NULL;
if (last_environ != NULL)
free ((char *) last_environ);
last_environ = new_environ;
environ = new_environ;
}
else
*ep = (char *) string;
return 0;
}

34
lib/stime.c Normal file
View File

@ -0,0 +1,34 @@
/* stime -- set the system clock
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* David MacKenzie <djm@ai.mit.edu> */
#include <sys/types.h>
#include <sys/time.h>
/* Set the system time to *WHEN seconds past the start of 1970 GMT. */
int
stime (when)
time_t *when;
{
struct timeval tv;
tv.tv_sec = *when;
tv.tv_usec = 0;
return settimeofday (&tv, (struct timezone *) 0);
}

37
lib/strcspn.c Normal file
View File

@ -0,0 +1,37 @@
/* Copyright (C) 1991 Free Software Foundation, Inc.
This file is part of the GNU C Library.
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., 675 Mass Ave,
Cambridge, MA 02139, USA. */
char *index ();
/* Return the length of the maximum inital segment of S
which contains no characters from REJECT. */
int
strcspn (s, reject)
register char *s;
register char *reject;
{
register int count = 0;
while (*s != '\0')
if (index (reject, *s++) == 0)
++count;
else
return count;
return count;
}

428
lib/strftime.c Normal file
View File

@ -0,0 +1,428 @@
/* strftime - custom formatting of date and/or time
Copyright (C) 1989, 1991, 1992 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Note: this version of strftime lacks locale support,
but it is standalone.
Performs `%' substitutions similar to those in printf. Except
where noted, substituted fields have a fixed size; numeric fields are
padded if necessary. Padding is with zeros by default; for fields
that display a single number, padding can be changed or inhibited by
following the `%' with one of the modifiers described below. Unknown
field specifiers are copied as normal characters. All other
characters are copied to the output without change.
Supports a superset of the ANSI C field specifiers.
Literal character fields:
% %
n newline
t tab
Numeric modifiers (a nonstandard extension):
- do not pad the field
_ pad the field with spaces
Time fields:
%H hour (00..23)
%I hour (01..12)
%k hour ( 0..23)
%l hour ( 1..12)
%M minute (00..59)
%p locale's AM or PM
%r time, 12-hour (hh:mm:ss [AP]M)
%R time, 24-hour (hh:mm)
%S second (00..61)
%T time, 24-hour (hh:mm:ss)
%X locale's time representation (%H:%M:%S)
%Z time zone (EDT), or nothing if no time zone is determinable
Date fields:
%a locale's abbreviated weekday name (Sun..Sat)
%A locale's full weekday name, variable length (Sunday..Saturday)
%b locale's abbreviated month name (Jan..Dec)
%B locale's full month name, variable length (January..December)
%c locale's date and time (Sat Nov 04 12:02:33 EST 1989)
%C century (00..99)
%d day of month (01..31)
%e day of month ( 1..31)
%D date (mm/dd/yy)
%h same as %b
%j day of year (001..366)
%m month (01..12)
%U week number of year with Sunday as first day of week (00..53)
%w day of week (0..6)
%W week number of year with Monday as first day of week (00..53)
%x locale's date representation (mm/dd/yy)
%y last two digits of year (00..99)
%Y year (1970...)
David MacKenzie <djm@gnu.ai.mit.edu> */
#include <sys/types.h>
#if defined(TM_IN_SYS_TIME) || (!defined(HAVE_TM_ZONE) && !defined(HAVE_TZNAME))
#include <sys/time.h>
#else
#include <time.h>
#endif
#if defined(HAVE_TZNAME)
extern char *tzname[2];
#endif
#if !__STDC__
#define const
#endif
/* Types of padding for numbers in date and time. */
enum padding
{
none, blank, zero
};
static char *days[] =
{
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
};
static char *months[] =
{
"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"
};
/* Add character C to STRING and increment LENGTH,
unless LENGTH would exceed MAX. */
#define add_char(c) (length + 1 <= max) && (string[length++] = (c))
/* Add a 2 digit number to STRING, padding if specified.
Return the number of characters added, up to MAX. */
static int
add_num2 (string, num, max, pad)
char *string;
int num;
int max;
enum padding pad;
{
int top = num / 10;
int length = 0;
if (top == 0 && pad == blank)
add_char (' ');
else if (top != 0 || pad == zero)
add_char (top + '0');
add_char (num % 10 + '0');
return length;
}
/* Add a 3 digit number to STRING, padding if specified.
Return the number of characters added, up to MAX. */
static int
add_num3 (string, num, max, pad)
char *string;
int num;
int max;
enum padding pad;
{
int top = num / 100;
int mid = (num - top * 100) / 10;
int length = 0;
if (top == 0 && pad == blank)
add_char (' ');
else if (top != 0 || pad == zero)
add_char (top + '0');
if (mid == 0 && top == 0 && pad == blank)
add_char (' ');
else if (mid != 0 || top != 0 || pad == zero)
add_char (mid + '0');
add_char (num % 10 + '0');
return length;
}
/* Like strncpy except return the number of characters copied. */
static int
add_str (to, from, max)
char *to;
char *from;
int max;
{
int i;
for (i = 0; from[i] && i <= max; ++i)
to[i] = from[i];
return i;
}
/* Return the week in the year of the time in TM, with the weeks
starting on Sundays. */
static int
sun_week (tm)
struct tm *tm;
{
int dl;
/* Set `dl' to the day in the year of the last day of the week previous
to the one containing the day specified in TM. If the day specified
in TM is in the first week of the year, `dl' will be negative or 0.
Otherwise, calculate the number of complete weeks before our week
(dl / 7) and add any partial week at the start of the year (dl % 7). */
dl = tm->tm_yday - tm->tm_wday;
return dl <= 0 ? 0 : dl / 7 + (dl % 7 != 0);
}
/* Return the week in the year of the time in TM, with the weeks
starting on Mondays. */
static int
mon_week (tm)
struct tm *tm;
{
int dl, wday;
if (tm->tm_wday == 0)
wday = 6;
else
wday = tm->tm_wday - 1;
dl = tm->tm_yday - wday;
return dl <= 0 ? 0 : dl / 7 + (dl % 7 != 0);
}
#if !defined(HAVE_TM_ZONE) && !defined(HAVE_TZNAME)
char *
zone_name (tp)
struct tm *tp;
{
char *timezone ();
struct timeval tv;
struct timezone tz;
gettimeofday (&tv, &tz);
return timezone (tz.tz_minuteswest, tp->tm_isdst);
}
#endif
/* Format the time given in TM according to FORMAT, and put the
results in STRING.
Return the number of characters (not including terminating null)
that were put into STRING, or 0 if the length would have
exceeded MAX. */
size_t
strftime (string, max, format, tm)
char *string;
size_t max;
const char *format;
const struct tm *tm;
{
enum padding pad; /* Type of padding to apply. */
size_t length = 0; /* Characters put in STRING so far. */
for (; *format && length < max; ++format)
{
if (*format != '%')
add_char (*format);
else
{
++format;
/* Modifiers: */
if (*format == '-')
{
pad = none;
++format;
}
else if (*format == '_')
{
pad = blank;
++format;
}
else
pad = zero;
switch (*format)
{
/* Literal character fields: */
case 0:
case '%':
add_char ('%');
break;
case 'n':
add_char ('\n');
break;
case 't':
add_char ('\t');
break;
default:
add_char (*format);
break;
/* Time fields: */
case 'H':
case 'k':
length +=
add_num2 (&string[length], tm->tm_hour, max - length,
*format == 'H' ? pad : blank);
break;
case 'I':
case 'l':
{
int hour12;
if (tm->tm_hour == 0)
hour12 = 12;
else if (tm->tm_hour > 12)
hour12 = tm->tm_hour - 12;
else
hour12 = tm->tm_hour;
length +=
add_num2 (&string[length], hour12, max - length,
*format == 'I' ? pad : blank);
}
break;
case 'M':
length +=
add_num2 (&string[length], tm->tm_min, max - length, pad);
break;
case 'p':
if (tm->tm_hour < 12)
add_char ('A');
else
add_char ('P');
add_char ('M');
break;
case 'r':
length +=
strftime (&string[length], max - length, "%I:%M:%S %p", tm);
break;
case 'R':
length +=
strftime (&string[length], max - length, "%H:%M", tm);
break;
case 'S':
length +=
add_num2 (&string[length], tm->tm_sec, max - length, pad);
break;
case 'T':
length +=
strftime (&string[length], max - length, "%H:%M:%S", tm);
break;
case 'X':
length +=
strftime (&string[length], max - length, "%H:%M:%S", tm);
break;
case 'Z':
#ifdef HAVE_TM_ZONE
length += add_str (&string[length], tm->tm_zone, max - length);
#else
#ifdef HAVE_TZNAME
if (tm->tm_isdst && tzname[1] && *tzname[1])
length += add_str (&string[length], tzname[1], max - length);
else
length += add_str (&string[length], tzname[0], max - length);
#else
length += add_str (&string[length], zone_name (tm), max - length);
#endif
#endif
break;
/* Date fields: */
case 'a':
add_char (days[tm->tm_wday][0]);
add_char (days[tm->tm_wday][1]);
add_char (days[tm->tm_wday][2]);
break;
case 'A':
length +=
add_str (&string[length], days[tm->tm_wday], max - length);
break;
case 'b':
case 'h':
add_char (months[tm->tm_mon][0]);
add_char (months[tm->tm_mon][1]);
add_char (months[tm->tm_mon][2]);
break;
case 'B':
length +=
add_str (&string[length], months[tm->tm_mon], max - length);
break;
case 'c':
length +=
strftime (&string[length], max - length,
"%a %b %d %H:%M:%S %Z %Y", tm);
break;
case 'C':
length +=
add_num2 (&string[length], (tm->tm_year + 1900) / 100,
max - length, pad);
break;
case 'd':
length +=
add_num2 (&string[length], tm->tm_mday, max - length, pad);
break;
case 'e':
length +=
add_num2 (&string[length], tm->tm_mday, max - length, blank);
break;
case 'D':
length +=
strftime (&string[length], max - length, "%m/%d/%y", tm);
break;
case 'j':
length +=
add_num3 (&string[length], tm->tm_yday + 1, max - length, pad);
break;
case 'm':
length +=
add_num2 (&string[length], tm->tm_mon + 1, max - length, pad);
break;
case 'U':
length +=
add_num2 (&string[length], sun_week (tm), max - length, pad);
break;
case 'w':
add_char (tm->tm_wday + '0');
break;
case 'W':
length +=
add_num2 (&string[length], mon_week (tm), max - length, pad);
break;
case 'x':
length +=
strftime (&string[length], max - length, "%m/%d/%y", tm);
break;
case 'y':
length +=
add_num2 (&string[length], tm->tm_year % 100,
max - length, pad);
break;
case 'Y':
add_char ((tm->tm_year + 1900) / 1000 + '0');
length +=
add_num3 (&string[length],
(1900 + tm->tm_year) % 1000, max - length, zero);
break;
}
}
}
add_char (0);
return length - 1;
}

188
lib/strtod.c Normal file
View File

@ -0,0 +1,188 @@
/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
This file is part of the GNU C Library.
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., 675 Mass Ave,
Cambridge, MA 02139, USA. */
#include <errno.h>
#include <ctype.h>
#include <math.h>
#if STDC_HEADERS
#include <float.h>
#include <stdlib.h>
#include <string.h>
#else
#define NULL 0
#define DBL_MAX 1.7976931348623159e+308
#define DBL_MIN 2.2250738585072010e-308
extern int errno;
#endif
#ifndef HUGE_VAL
#define HUGE_VAL HUGE
#endif
#if !__STDC__
#define const
#endif
/* Convert NPTR to a double. If ENDPTR is not NULL, a pointer to the
character after the last one used in the number is put in *ENDPTR. */
double
strtod (nptr, endptr)
const char *nptr;
char **endptr;
{
register const char *s;
short int sign;
/* The number so far. */
double num;
int got_dot; /* Found a decimal point. */
int got_digit; /* Seen any digits. */
/* The exponent of the number. */
long int exponent;
if (nptr == NULL)
{
errno = EINVAL;
goto noconv;
}
s = nptr;
/* Eat whitespace. */
while (isspace (*s))
++s;
/* Get the sign. */
sign = *s == '-' ? -1 : 1;
if (*s == '-' || *s == '+')
++s;
num = 0.0;
got_dot = 0;
got_digit = 0;
exponent = 0;
for (;; ++s)
{
if (isdigit (*s))
{
got_digit = 1;
/* Make sure that multiplication by 10 will not overflow. */
if (num > DBL_MAX * 0.1)
/* The value of the digit doesn't matter, since we have already
gotten as many digits as can be represented in a `double'.
This doesn't necessarily mean the result will overflow.
The exponent may reduce it to within range.
We just need to record that there was another
digit so that we can multiply by 10 later. */
++exponent;
else
num = (num * 10.0) + (*s - '0');
/* Keep track of the number of digits after the decimal point.
If we just divided by 10 here, we would lose precision. */
if (got_dot)
--exponent;
}
else if (!got_dot && *s == '.')
/* Record that we have found the decimal point. */
got_dot = 1;
else
/* Any other character terminates the number. */
break;
}
if (!got_digit)
goto noconv;
if (tolower (*s) == 'e')
{
/* Get the exponent specified after the `e' or `E'. */
int save = errno;
char *end;
long int exp;
errno = 0;
++s;
exp = strtol (s, &end, 10);
if (errno == ERANGE)
{
/* The exponent overflowed a `long int'. It is probably a safe
assumption that an exponent that cannot be represented by
a `long int' exceeds the limits of a `double'. */
if (endptr != NULL)
*endptr = end;
if (exp < 0)
goto underflow;
else
goto overflow;
}
else if (end == s)
/* There was no exponent. Reset END to point to
the 'e' or 'E', so *ENDPTR will be set there. */
end = (char *) s - 1;
errno = save;
s = end;
exponent += exp;
}
if (endptr != NULL)
*endptr = (char *) s;
if (num == 0.0)
return 0.0;
/* Multiply NUM by 10 to the EXPONENT power,
checking for overflow and underflow. */
if (exponent < 0)
{
if (num < DBL_MIN * pow (10.0, (double) -exponent))
goto underflow;
}
else if (exponent > 0)
{
if (num > DBL_MAX * pow (10.0, (double) -exponent))
goto overflow;
}
num *= pow (10.0, (double) exponent);
return num * sign;
overflow:
/* Return an overflow error. */
errno = ERANGE;
return HUGE_VAL * sign;
underflow:
/* Return an underflow error. */
if (endptr != NULL)
*endptr = (char *) nptr;
errno = ERANGE;
return 0.0;
noconv:
/* There was no number. */
if (endptr != NULL)
*endptr = (char *) nptr;
return 0.0;
}

65
lib/xmalloc.c Normal file
View File

@ -0,0 +1,65 @@
/* xmalloc.c -- malloc with out of memory checking
Copyright (C) 1990, 1991 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifdef STDC_HEADERS
#include <stdlib.h>
#else
char *malloc ();
char *realloc ();
void free ();
#endif
void error ();
/* Allocate N bytes of memory dynamically, with error checking. */
char *
xmalloc (n)
unsigned n;
{
char *p;
p = malloc (n);
if (p == 0)
/* Must exit with 2 for `cmp'. */
error (2, 0, "virtual memory exhausted");
return p;
}
/* Change the size of an allocated block of memory P to N bytes,
with error checking.
If P is NULL, run xmalloc.
If N is 0, run free and return NULL. */
char *
xrealloc (p, n)
char *p;
unsigned n;
{
if (p == 0)
return xmalloc (n);
if (n == 0)
{
free (p);
return 0;
}
p = realloc (p, n);
if (p == 0)
/* Must exit with 2 for `cmp'. */
error (2, 0, "virtual memory exhausted");
return p;
}

696
old/sh-utils/ChangeLog Normal file
View File

@ -0,0 +1,696 @@
Wed Oct 28 14:16:48 1992 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu)
* Version 1.8.
* stty.c: Accept Irix VRPRNT for VREPRINT.
From Jim Meyering.
* stty.c: Fix some type mismatches. From Bruce Evans, bde@runx.oz.au.
* who.c (read_utmp): Close file on error.
From Bruce Evans.
* su.c, test.c: Add some decls. From Bruce Evans.
* sleep.c (main): Arg to sleep is unsigned, not long.
From Bruce Evans.
Fri Sep 11 00:25:52 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
* echo.c, echo.1: New files.
Thu Sep 10 18:42:44 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
* pathchk.c (main): Don't strip trailing slashes from args;
they might make a path invalid.
(portable_chars_only, dir_ok): New functions.
(validate_path): Renamed from validate_new_path.
Call them. Don't complain if a leading
dir doesn't exist. Don't replace `parent' with a dir that
doesn't exist. Don't print a message when falling back
from pathconf to constant values.
* who.c [!UTMP_FILE]: If _PATH_UTMP is defined, use it instead
of /etc/utmp. From Marc Boucher <marc@cam.org>.
Tue Aug 25 17:02:25 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
* Version 1.7.
* groups.sh, nohup.sh: Add $(bindir) to front of path.
Mon Aug 24 16:39:39 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
* stty.c: make sane value for "min" 1, not 0.
From haible@ma2s2.mathematik.uni-karlsruhe.de (Bruno Haible).
Sun Aug 23 03:02:07 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
* id.c, test.c: Use NGROUPS_MAX if it's defined. 386BSD is like sun.
Sat Aug 22 03:16:41 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
* test.c: Rename STANDALONE to TEST_STANDALONE to avoid IBM RT
ACIS sys/param.h conflict.
* su.c (correct_password) [HAVE_SHADOW_H]: Try to get the
encrypted correct password from the shadow password file.
Fri Jul 17 15:25:01 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
* su.c, getusershell.c: New files.
Fri Jul 3 15:08:43 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
* stty.c, who.c: Change FOO_MISSING to HAVE_FOO.
Fri Jun 5 01:49:29 1992 David J. MacKenzie (djm@churchy.gnu.ai.mit.edu)
* strcspn.c: New file.
* expr.c: Misc. cleanups.
* expr.c (eval7): Renamed from eval6.
Give syntax error if no more args. Don't coerce all values to numbers.
(eval6): New function.
(eval5): Accept == as a synonym for =.
(eval2): Coerce values to numbers for comparisons.
Above all from Dana Jacobsen (jacobsd@prism.cs.orst.edu).
Thu Jun 4 19:32:09 1992 David J. MacKenzie (djm@churchy.gnu.ai.mit.edu)
* printf.c (print_formatted): Move main loop into new function.
(main): Add an outer loop to use the format multiple times.
(verify): Don't reject a completely empty string.
Check errno (for overflow).
* false.sh, true.sh: New programs. Oh, boy.
Thu May 14 01:17:22 1992 David J. MacKenzie (djm@churchy.gnu.ai.mit.edu)
* stty.c (set_mode): Support crt and dec modes partially if
necessary, so they work on, for example, Ultrix . . . .
Wed May 13 14:47:45 1992 David J. MacKenzie (djm@churchy.gnu.ai.mit.edu)
* stty.c (set_mode): Swap nl and -nl. Have them also affect
output as well as input.
Tue May 12 00:07:28 1992 David J. MacKenzie (djm@churchy.gnu.ai.mit.edu)
* date.c (show_date): Use strftime for the whole conversion.
Tue May 5 15:20:24 1992 David J. MacKenzie (djm@hal)
* stty.c (wrapf): Print the formatted buffer; don't redo the
formatting using vprintf.
Thu Apr 30 01:17:08 1992 David J. MacKenzie (djm@churchy.gnu.ai.mit.edu)
* printf.c (xstrtol, xstrtoul, xstrtod, verify): New functions.
(main, print_direc): Use them. Make error messages more specific.
* tee.c (tee): Only malloc and free the table of file descriptors
if >0 files are given.
Fri Apr 17 11:56:48 1992 David J. MacKenzie (djm@wookumz.gnu.ai.mit.edu)
* pathchk.c (validate_new_path): Print the name of the component that
failed the length test, not the whole path.
From Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de).
Mon Apr 6 15:11:36 1992 David J. MacKenzie (djm@wookumz.gnu.ai.mit.edu)
* who.c (read_utmp): Check close return for error.
(print_heading): Align columns based on sizes of utmp members.
(who_am_i): Skip past /dev/ instead of skipping leading path.
Mon Mar 16 23:47:03 1992 David J. MacKenzie (djm@apple-gunkies.gnu.ai.mit.edu)
* date.c (show_date): Don't call strftime if FORMAT is the
empty string.
* date.c (main): Reorganize to reduce duplicated code.
Add -d option.
(usage): Document -d.
(set_date): Function removed.
Tue Feb 11 16:12:18 1992 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
* printf.c (print_esc): When a numeric escape is given,
don't call print_esc_char, and return 1 less.
From Thorston Ohl.
Mon Jan 20 02:17:18 1992 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
* Version 1.6.
* test.c: HAVE_MULTIPLE_GROUPS -> HAVE_GETGROUPS, for bash 1.11.
Fri Jan 17 15:46:18 1992 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
* expr.c (docolon): Use re_nsub to find the number of
subexpressions . . . From Karl Berry, who knows.
Wed Dec 25 23:27:53 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
* expr.c (docolon): Use the new way (re_regs.num_regs > 0) to find
out if there were any subexpressions, instead of the old way
(re_regs.start[1] >= 0), which can cause random memory
accesses with regex 0.1. From Brian Matthews.
Tue Dec 24 02:12:15 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
* system.h, id.c, pathchk.c, tee.c: Change POSIX ifdefs to
HAVE_UNISTD_H and _POSIX_VERSION.
Wed Dec 11 13:15:09 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
* Version 1.5.
* expr.c (main): Set obscure_syntax to tell re_match to
allocate memory for the group registers.
Mon Dec 9 16:03:14 1991 Charles Hannum (mycroft at hal.gnu.ai.mit.edu)
* who.c (list_entries): Check type == USER_PROCESS if defined, for SysV.
Sat Dec 7 00:32:02 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
* Version 1.4.
* env, id, nice, pathchk, stty, tee, tty, uname: Change usage
messages and documentation to list long-named options starting
with `--' rather than `+'.
* env.c (main), nice.c (main): Simplify test for which exit
status to use if exec fails.
Fri Dec 6 23:49:42 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
* tee.c (main) [POSIX]: Use sigaction instead of signal, which
POSIX doesn't have.
Fri Oct 18 00:31:35 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
* test.c (two_arguments): Fix from Chet.
* expr.c: Include regex.h after sys/types.h, not before, so
size_t gets defined.
* test.c: New version, adapted from bash 1.10.
* id.c: GID_T -> GETGROUPS_T, for clarity.
Sat Oct 12 14:38:34 1991 David J. MacKenzie (djm at churchy.gnu.ai.mit.edu)
* configure: Define uid_t and gid_t as int if they're not
defined in sys/types.h. That's probably right for old Unixes
and avoids trying to find the C preprocessor.
Sat Sep 28 13:01:23 1991 David J. MacKenzie (djm at churchy.gnu.ai.mit.edu)
* stty.c (set_mode): Make `raw' and `cooked' not change parity
and character size, which would probably make them useless on
7-bit lines.
Make `raw' set the `time' character to 0, not 1.
From Bruce Evans.
* nohup.sh: If creating nohup.out, give it mode 0600, for POSIX.
Fri Sep 13 14:59:51 1991 David J. MacKenzie (djm at churchy.gnu.ai.mit.edu)
* id.c [POSIX]: Always use sysconf to get NGROUPS_MAX.
Thu Aug 29 14:43:07 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
* test.c: Don't include sys/file.h if POSIX.
Use gid_t for getgroups.
* stty.c (set_mode): Use CEOF and CEOL instead of hardcoding them.
(display_speed): Fix a printf string type mismatch.
From Bruce Evans.
Mon Aug 26 16:52:51 1991 David J. MacKenzie (djm at pogo.gnu.ai.mit.edu)
* configure, src/Makefile.in, lib/Makefile.in: Only put $< in
Makefiles if VPATH is being used, because older makes don't
understand it.
Mon Aug 19 01:57:46 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
* Version 1.3.
Sat Aug 17 22:48:15 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu)
* src/Makefile.in (install): Install a link to test called '['.
Wed Aug 14 12:22:57 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu)
* test.c (unary_operator): Check first char of string, not its address.
Sun Aug 11 18:10:30 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
* Version 1.2.
* system.h: Define S_IFMT if needed, for test.c.
* test.c: New file, from bash.
* nice.c: Change +priority to +adjustment (more accurate).
Sat Aug 10 13:09:51 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
* stty.c [WINSIZE_IN_PTEM]: sys/ptem.h requires sys/stream.h.
* nice.c, configure: Use nice if available and setpriority is missing.
Thu Aug 8 01:34:05 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
* date.c: USG needs TZ=GMT0 for UCT timezone, also.
* stty.c: Add pass8 and litout modes.
Sun Aug 4 22:45:51 1991 David J. MacKenzie (djm at wheat-chex)
* Version 1.1.
Fri Aug 2 13:22:31 1991 David J. MacKenzie (djm at apple-gunkies)
* configure: Implement +srcdir. Don't check for bison.
* stty.c: Don't change ixon in "sane" mode.
* configure: Use 1 instead of 255 for checking tzname,
because of signedness.
Thu Aug 1 13:40:58 1991 David J. MacKenzie (djm at apple-gunkies)
* printenv.c (main): Don't print the variable names when given
args, as people seem to use printenv in scripts after all . . . .
* stty.c: Don't change parity or character size settings in
"sane" mode. The right values for those depend on the hardware.
Wed Jul 31 01:19:01 1991 David J. MacKenzie (djm at hal)
* stty.c [_AIX]: Include sys/ioctl.h -- needed on
AIX to get window size.
Tue Jul 30 00:06:54 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
* getdate.y: New file.
* date.c: Add -s option to set date in English.
* configure: Check for ftime.
* date.c: Remove COMPUTE_TM_ZONE code, which didn't work.
* configure: Instead of checking whether tzname is declared,
check whether it exists.
* logname.c (main): Go back to just printing an error message
if getlogin fails, as required by POSIX.
* stty.c (screen_columns, wrapf): New functions to implement
output wrapping.
Globally: use them.
* configure: Define uid_t and gid_t if sys/types.h doesn't.
* system.h: Define F_OK et al. if nothing else does.
Mon Jul 29 21:11:16 1991 David J. MacKenzie (djm at wombat.gnu.ai.mit.edu)
* pathchk.c (validate_new_path): Rearrange tests so that
pathconf is only called on existing directories. Use access
instead of stat to determine directory searchability.
From Jim Meyering.
* stty.c, configure: Add WINSIZE_IN_PTEM and GWINSZ_BROKEN for SCO.
Wed Jul 24 02:13:31 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
* stty.c (sane_mode): Always set control chars to sane values.
Set min and time if they're different from eof and eol.
* whoami.c: Print UID as unsigned.
* logname.c: Do "whoami" if getlogin fails.
* logname.c (main): fprintf was missing an arg.
Tue Jul 23 02:20:15 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
* id.c: GID_T is int if ultrix as well as if sun.
* stty.c: Implement raw and cooked modes.
Mon Jul 22 15:21:21 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
* tee.c (main): close stdin and stdout to check for errors.
* stty.c: Use tcflag_t for termios bitmasks.
Use speed_t for speeds. Use unsigned long for baud rates to
accomodate large values, and support 57600 and 115200 if available.
* date.c, configure: Instead of SIZE_T_MISSING,
define size_t if it's missing.
* id.c, whoami.c: Use uid_t and gid_t.
* id.c: If POSIX and not sun (bogus!), pass getgroups and
getugroups an array of gid_t instead of int.
* system.h: New file.
* Most programs: include it.
Fri Jul 19 12:04:58 1991 David J. MacKenzie (djm at apple-gunkies)
* env.c [!STDC_HEADERS]: Declare errno.
* printf.c, pathchk.c: Don't include errno.h; not needed.
* version.c: New file.
* All C programs: Link with it, to get version number in the
binary where at least `strings -' and grep can find it.
* pathchk.c (strip_trailing_slashes): Function removed; use
version in lib.
Mon Jul 15 11:34:22 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
* Version 1.0.
* pathchk.c: Always check whether _POSIX_PATH_MAX and
_POSIX_NAME_MAX need to be defined.
[POSIX]: If no PATH_MAX or NAME_MAX and pathconf for the path
returns -1 (some systems do this if the path does not exist),
use pathconf for "/".
Sun Jul 14 21:17:22 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu)
* date.c (date_seconds): Function removed, replaced with
posixtm.y in lib.
(set_date): Change caller.
* configure: Check for bison.
* stty.c [!C_LINE_MISSING]: Add support for setting and
printing the line discipline.
* configure: Check for C_LINE_MISSING.
* configure: Check for Minix.
Sat Jul 13 01:33:59 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu)
* Add `man' directory and manual pages.
* configure: Set INSTALLDATA and MAN.
* id.c: Add #ifdefs for POSIX ways of getting max groups list size.
(print_group_list, print_full_info): Allocate list of groups
with malloc since its size might not be constant.
* nice.c (main): Don't adjust priority if printing it.
Default adjustment of 10, not 0.
* printf.c: Add \c escape and %b conversion.
Implement '*' for field width and precision.
Make all errors fatal.
(print_esc_string, print_esc): New functions.
* configure, date.c: Change SYS_TIME_H to TM_IN_SYS_TIME.
* configure: Always check where to find struct tm.
* yes.c: Rewrite to accept multiple arguments.
* Add groups.sh.
Fri Jul 12 10:57:00 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
* dirname.c: Move code from dirname function into main,
simplifying things quite a bit. From Jim Meyering.
* Omit strdup from lib; no longer used.
* configure: Don't check for strdup.
* printenv.c (main): If args given, print the values in the order
given on the command line rather than the order given in the
environment.
* tee.c, tty.c (struct longopts): Revise to make short-option
equivalents clear.
Thu Jul 11 12:46:11 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu)
* nice.c: Add long options.
* Add date command and libraries it needs.
* configure: Updated.
* env.c: Add long options. Use GNU putenv instead of custom
setenv function.
* id.c: Add long options.
* pathchk.c [POSIX]: Use pathconf if necessary to get NAME_MAX
and PATH_MAX.
* nice.c: Use exit status required for nohup by POSIX.2
(nohup execs nice).
* sleep.c: Don't bother with hex and octal.
* env.c: Fix exit status for POSIX.2 draft 11.1.
* Many files: Remove private copies of xmalloc, error, xstrdup,
etc. to use shared versions.
Fix #includes for USG, STDC_HEADERS, POSIX.
Mon Jul 8 18:56:24 1991 David J. MacKenzie (djm at churchy.gnu.ai.mit.edu)
* date.c (main): For -u, set TZ to "" instead of "GMT0",
unless on HP-UX or Ultrix.
* Rename some feature-test macros.
* stime.c: Created from code in date.c.
* date.c (compute_tm_zone): New function.
(date_seconds, show_date): Use it.
(xmalloc, xrealloc): Functions removed; use xmalloc.c instead.
Tue Jul 2 02:28:11 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu)
* tee.c (tee): Report errors in closing files.
Mon Mar 18 10:13:59 1991 Jeffrey A. Law (law at geech.ai.mit.edu)
* date.c (date_seconds, show_date): #if COMPUTE_TMZONE then
compute the proper value to place in tm->tm_zone from
information returned by localtime and gettimeofday.
Fri Apr 26 11:38:09 1991 David J. MacKenzie (djm at mole.gnu.ai.mit.edu)
* stty.c: Define default values for control chars if necessary.
Complain about invalid options if no other options follow.
Use POSIX functions instead of ioctl, for manipulating termios.
* expr.c (main): Exit status was backwards.
Thu Dec 20 00:36:01 1990 David J. MacKenzie (djm at apple-gunkies)
* id.c: Reorganization and many changes to fix bugs and POSIX
compliance problems.
Mon Dec 10 03:09:13 1990 David J. MacKenzie (djm at apple-gunkies)
* stty.c: Don't declare printf and some other functions that
might have variable numbers of args in system header file decls.
Tue Nov 14 23:37:22 1990 Roland McGrath (roland at geech.ai.mit.edu)
* id.c (print_groups): Put spaces after commas.
(print_group): New fn, to print a group id. Uses numeric fmt
unless -n, in which case it uses group names.
(print_groups): Call it. Find the rgid and egid, and print them as
well as the supplementary groups. Make sure we print each group only
once.
Sun Sep 16 01:49:14 1990 David J. MacKenzie (djm at apple-gunkies)
* id.c (main): Add -G option for POSIX.2 draft 10.
Allow a username to be given.
(print_groups): New function from code in main.
(getugroups): New function.
Sun Aug 12 00:32:01 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
* env.c (main): Instead of setting _POSIX_OPTION_ORDER,
tell getopt to not permute, with `+'.
Sat Aug 11 01:32:53 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
* expr.c: Use regex.c library instead of private regex routines.
* nice.c (main): Add -n option for POSIX.2a.
(usage): New function.
Fri Aug 10 23:58:11 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
* who.c: Add -m, -i, -w options for POSIX.2a.
Tue Aug 7 00:01:02 1990 David J. MacKenzie (djm at apple-gunkies)
* expr.c: Use exit directly instead of longjmp on error.
Use argv[0] instead of hardcoded "expr" in messages.
Make some functions void.
Sat Aug 4 21:19:25 1990 David J. MacKenzie (djm at pogo.ai.mit.edu)
* env.c: Change exit statuses for POSIX draft 10.
Wed Jul 4 04:32:51 1990 David J. MacKenzie (djm at apple-gunkies)
* tee.c: Use error instead of perror_with_name and
out_of_memory.
Wed Jun 20 02:39:49 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
* date.c: Change -DSETTOD to -DSTIME_MISSING, -DSIZE_T to
-DSIZE_T_IN_TYPES, and -DSTDC_HDRS to -DSTDC_HEADERS.
Declare some more functions. Replace fatal, memory_out, and
nonfatal_perror with error.
Mon Jun 18 00:16:52 1990 David J. MacKenzie (djm at apple-gunkies)
* stty.c: Add some Unix compatibility modes.
Sat Jun 16 21:05:59 1990 David J. MacKenzie (djm at apple-gunkies)
* stty.c (display_changed, display_all): Print values of min
and time.
Thu Jun 14 17:49:31 1990 David J. MacKenzie (djm at apple-gunkies)
* stty.c: Implement tab, backspace, etc. delay args.
Thu May 31 12:25:40 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
* nohup.sh: Don't ignore SIGTERM.
If ./nohup.out is unwritable, try $HOME/nohup.out.
Thu May 3 22:33:32 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
* who.c: Use error instead of fatal and fatal_perror.
(print_headings): Print headings in all caps, like SYSV does.
(list_entries): New function for -q to make it like SYSV -q.
(valid_entries): Function removed.
Mon Apr 2 01:27:23 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
* id.c (main): Don't strip off leading path from program name.
Revise a couple of error messages.
* whoami.c (main): Use geteuid, not getuid, for Unix compatibility.
Tue Mar 20 14:28:25 1990 David J. MacKenzie (djm at pogo.ai.mit.edu)
* tee.c (main): Pass list of files and its size as args to tee
rather than as global vars. Exit with return value of tee
instead of always 0.
(tee): Use unbuffered I/O instead of stdio, for POSIX.
Return an error status.
(xwrite): New function.
Tue Mar 13 00:38:13 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
* who.c (who_am_i): Print heading before checking to see
whether there is an entry for the tty on stdin, for
consistency with the who function.
(main): Use argv[optind], not argv[1], as alternate file.
Fri Mar 9 15:49:04 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
* who.c: Rename UTMP to UTMP_FILE for compatibility with SysV
utmp.h. Include some additional header files.
(main): Recognize some options from SysVr3 who. Call usage.
Set new global var `program_name' from argv[0].
(usage): New function.
(who): If -q given, only print count of users logged on.
(print_entry): New function to format an entry on the output;
make format more like that of the Unix who programs.
(print_heading): New function to print a line describing each
output field.
(who, who_am_i): Call print_entry and print_heading.
(valid_entries): New function to return count of nonempty
entries in utmp.
(search_entries): Compare with utmp tty field instead of
username field. Don't assume null termination in utmp field.
(who_am_i): Print the entry for the tty on stdin rather than
the first entry found for the uid. If hostname is not
available, use a null one instead of "<unknown>".
Don't hardcode max hostname length.
(idle_string): New function to format idle time field.
(fatal, fatal_perror): Use program_name instead of hardcoded "who"
in error messages.
Tue Mar 6 00:59:03 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
* printenv.c (main): Allow multiple variables to be specified.
(barf): Function removed.
Sat Jan 20 18:41:48 1990 Jim Kingdon (kingdon at geech)
* expr.c (nextarg): Do not pass *args to strcmp if NULL.
Mon Dec 18 09:57:20 1989 David J. MacKenzie (djm at hobbes.ai.mit.edu)
* printenv.c (main): Simplify error messages.
Sat Dec 16 15:15:50 1989 David J. MacKenzie (djm at hobbes.ai.mit.edu)
* expr.c: Indent to regularize spacing.
(cmpv, arithf): Change '#define foo (args)' to '#define foo(args)'
so they compile.
(docolon): Remove unused vars.
(multiply): Rename from times to avoid libc conflict.
(error): Include program name in message.
(xmalloc): Rename from Malloc.
(re_compiled): Rename from re_comp to avoid libc conflict.
* basename.c: Fix some weird indentation.
(main): Print a clearer usage message.
Use a simpler method for removing suffix, if given.
(fatal): Function no longer used; removed.
* sleep.c: (main): Rename `time' to `seconds'. Print usage
message if given no args.
Exit with status 0 instead of falling off end.
(error): Print to stderr, not stdout.
* tee.c: (main): Use getopt_long instead of custom parser,
and adjust usage message.
Use list of filenames in argv rather than making a copy.
(tee): New function created from the second half of main.
Fix bug where it tried to fclose a loop index instead of a stream.
(xmalloc): Ok to return 0 if 0 bytes requested.
(xrealloc): Unused function removed.
* whoami.c: Canonicalize usage message and fix error message.
* who.c: Declare some functions.
(fatal_perror): New function for printing errors after system
calls.
Global: Use it when appropriate.
(xmalloc): Return char *, not int.
(read_utmp): Ok if utmp file is empty.
Include filename in error messages.
(scan_entries): Adjust columns to line up better, particularly
when there are users with 8 character long usernames logged in.
Sat Oct 28 13:20:43 1989 David J. MacKenzie (djm at spiff)
* uname.c: Added long options.
global: changed the word `part' to the word `element'
(more precise).
(program_name, long_options): New variables.
(main): Support long options.
(usage): Add long options summary to message.
Local Variables:
mode: indented-text
left-margin: 8
version-control: never
End:

14
old/sh-utils/NEWS Normal file
View File

@ -0,0 +1,14 @@
Major changes in release 1.8:
* add echo command
* fix some incorrect warnings in pathchk
* look at the right utmp file on 386BSD
* date doesn't dump core on some systems now
Major changes in release 1.7:
* add su, who, true, false commands
* add more tests to expr
* fix printf program handling of \ escapes
* printf can re-use format string for multiple groups of arguments
* printf catches numeric conversion errors with an ANSI C library
* stty nl and -nl were backwards
* date can format an arbitrary date without setting it

78
src/basename.c Normal file
View File

@ -0,0 +1,78 @@
/* basename -- strip directory and suffix from filenames
Copyright (C) 1990, 1991 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Usage: basename name [suffix]
NAME is a pathname; SUFFIX is a suffix to strip from it.
basename /usr/foo/lossage/functions.l
=> functions.l
basename /usr/foo/lossage/functions.l .l
=> functions
basename functions.lisp p
=> functions.lis */
#include <stdio.h>
#include <sys/types.h>
#include "system.h"
char *basename ();
void remove_suffix ();
void strip_trailing_slashes ();
void
main (argc, argv)
int argc;
char **argv;
{
char *name;
if (argc == 1 || argc > 3)
{
fprintf (stderr, "Usage: %s name [suffix]\n", argv[0]);
exit (1);
}
strip_trailing_slashes (argv[1]);
name = basename (argv[1]);
if (argc == 3)
remove_suffix (name, argv[2]);
puts (name);
exit (0);
}
/* Remove SUFFIX from the end of NAME if it is there, unless NAME
consists entirely of SUFFIX. */
void
remove_suffix (name, suffix)
register char *name, *suffix;
{
register char *np, *sp;
np = name + strlen (name);
sp = suffix + strlen (suffix);
while (np > name && sp > suffix)
if (*--np != *--sp)
return;
if (np > name)
*np = '\0';
}

190
src/date.c Normal file
View File

@ -0,0 +1,190 @@
/* date - print or set the system date and time
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Options:
-d DATESTR Display the date DATESTR.
-s DATESTR Set the date to DATESTR.
-u Display or set the date in universal instead of local time.
+FORMAT Specify custom date output format, described below.
MMDDhhmm[[CC]YY][.ss] Set the date in the format described below.
If one non-option argument is given, it is used as the date to which
to set the system clock, and must have the format:
MM month (01..12)
DD day in month (01..31)
hh hour (00..23)
mm minute (00..59)
CC first 2 digits of year (optional, defaults to current) (00..99)
YY last 2 digits of year (optional, defaults to current) (00..99)
ss second (00..61)
If a non-option argument that starts with a `+' is specified, it
is used to control the format in which the date is printed; it
can contain any of the `%' substitutions allowed by the strftime
function. A newline is always added at the end of the output.
David MacKenzie <djm@gnu.ai.mit.edu> */
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include "system.h"
/* This is portable and avoids bringing in all of the ctype stuff. */
#define isdigit(c) ((c) >= '0' && (c) <= '9')
#ifdef TM_IN_SYS_TIME
#include <sys/time.h>
#else
#include <time.h>
#endif
#ifndef STDC_HEADERS
time_t mktime ();
size_t strftime ();
time_t time ();
#endif
int putenv ();
int stime ();
char *xrealloc ();
time_t get_date ();
time_t posixtime ();
void error ();
void show_date ();
void usage ();
/* putenv string to use Universal Coordinated Time.
POSIX.2 says it should be "TZ=UCT0" or "TZ=GMT0". */
#ifndef TZ_UCT
#if defined(hpux) || defined(__hpux__) || defined(ultrix) || defined(__ultrix__) || defined(USG)
#define TZ_UCT "TZ=GMT0"
#else
#define TZ_UCT "TZ="
#endif
#endif
/* The name this program was run with, for error messages. */
char *program_name;
void
main (argc, argv)
int argc;
char **argv;
{
int optc;
char *datestr = NULL;
time_t when;
int set_date = 0;
int universal_time = 0;
program_name = argv[0];
while ((optc = getopt (argc, argv, "d:s:u")) != EOF)
switch (optc)
{
case 'd':
datestr = optarg;
break;
case 's':
datestr = optarg;
set_date = 1;
break;
case 'u':
universal_time = 1;
break;
default:
usage ();
}
if (argc - optind > 1)
usage ();
if (universal_time && putenv (TZ_UCT) != 0)
error (1, 0, "virtual memory exhausted");
time (&when);
if (datestr)
when = get_date (datestr, NULL);
if (argc - optind == 1 && argv[optind][0] != '+')
{
when = posixtime (argv[optind]);
set_date = 1;
}
if (when == -1)
error (1, 0, "invalid date");
if (set_date && stime (&when) == -1)
error (0, errno, "cannot set date");
if (argc - optind == 1 && argv[optind][0] == '+')
show_date (argv[optind] + 1, when);
else
show_date ((char *) NULL, when);
exit (0);
}
/* Display the date and/or time in WHEN according to the format specified
in FORMAT, followed by a newline. If FORMAT is NULL, use the
standard output format (ctime style but with a timezone inserted). */
void
show_date (format, when)
char *format;
time_t when;
{
struct tm *tm;
char *out = NULL;
size_t out_length = 0;
tm = localtime (&when);
if (format == NULL)
/* Print the date in the default format. Vanilla ANSI C strftime
doesn't support %e, but POSIX requires it. If you don't use
a GNU strftime, make sure yours supports %e. */
format = "%a %b %e %H:%M:%S %Z %Y";
else if (*format == '\0')
{
printf ("\n");
return;
}
do
{
out_length += 200;
out = (char *) xrealloc (out, out_length);
}
while (strftime (out, out_length, format, tm) == 0);
printf ("%s\n", out);
free (out);
}
void
usage ()
{
fprintf (stderr, "\
Usage: %s [-u] [-d datestr] [-s datestr] [+FORMAT] [MMDDhhmm[[CC]YY][.ss]]\n",
program_name);
exit (1);
}

57
src/dirname.c Normal file
View File

@ -0,0 +1,57 @@
/* dirname -- strip filename suffix from pathname
Copyright (C) 1990, 1991 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by David MacKenzie and Jim Meyering. */
#include <stdio.h>
#include <sys/types.h>
#include "system.h"
void strip_trailing_slashes ();
void
main (argc, argv)
int argc;
char **argv;
{
register char *path;
register char *slash;
if (argc != 2)
{
fprintf (stderr, "Usage: %s path\n", argv[0]);
exit (1);
}
path = argv[1];
strip_trailing_slashes (path);
slash = rindex (path, '/');
if (slash == NULL)
path = ".";
else
{
/* Remove any trailing slashes and final element. */
while (slash > path && *slash == '/')
--slash;
slash[1] = 0;
}
puts (path);
exit (0);
}

179
src/echo.c Normal file
View File

@ -0,0 +1,179 @@
/* echo.c, taken from Bash.
Copyright (C) 1987, 1989, 1991, 1992 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash 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.
Bash 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 Bash; see the file COPYING. If not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include <sys/types.h>
#include "system.h"
/* echo [-neE] [arg ...]
Output the ARGs. If -n is specified, the trailing newline is
suppressed. If the -e option is given, interpretation of the
following backslash-escaped characters is turned on:
\a alert (bell)
\b backspace
\c suppress trailing newline
\f form feed
\n new line
\r carriage return
\t horizontal tab
\v vertical tab
\\ backslash
\num the character whose ASCII code is NUM (octal).
You can explicitly turn off the interpretation of the above characters
on System V systems with the -E option.
*/
#define V9_ECHO
#if defined (V9_ECHO)
# if defined (USG)
# define VALID_ECHO_OPTIONS "neE"
# else
# define VALID_ECHO_OPTIONS "ne"
# endif /* !USG */
#else /* !V9_ECHO */
# define VALID_ECHO_OPTIONS "n"
#endif /* !V9_ECHO */
/* Print the words in LIST to standard output. If the first word is
`-n', then don't print a trailing newline. We also support the
echo syntax from Version 9 unix systems. */
void
main (argc, argv)
int argc;
char **argv;
{
int display_return = 1, do_v9 = 0;
/* System V machines already have a /bin/sh with a v9 behaviour. We
use the identical behaviour for these machines so that the
existing system shell scripts won't barf. */
#if defined (V9_ECHO) && defined (USG)
do_v9 = 1;
#endif
--argc;
++argv;
while (argc > 0 && *argv[0] == '-')
{
register char *temp;
register int i;
/* If it appears that we are handling options, then make sure that
all of the options specified are actually valid. Otherwise, the
string should just be echoed. */
temp = argv[0] + 1;
for (i = 0; temp[i]; i++)
{
if (rindex (VALID_ECHO_OPTIONS, temp[i]) == 0)
goto just_echo;
}
if (!*temp)
goto just_echo;
/* All of the options in TEMP are valid options to ECHO.
Handle them. */
while (*temp)
{
if (*temp == 'n')
display_return = 0;
#if defined (V9_ECHO)
else if (*temp == 'e')
do_v9 = 1;
#if defined (USG)
else if (*temp == 'E')
do_v9 = 0;
#endif /* USG */
#endif /* V9_ECHO */
else
goto just_echo;
temp++;
}
argc--;
argv++;
}
just_echo:
if (argc > 0)
{
#if defined (V9_ECHO)
if (do_v9)
{
while (argc > 0)
{
register char *s = argv[0];
register int c;
while (c = *s++)
{
if (c == '\\' && *s)
{
switch (c = *s++)
{
case 'a': c = '\007'; break;
case 'b': c = '\b'; break;
case 'c': display_return = 0; continue;
case 'f': c = '\f'; break;
case 'n': c = '\n'; break;
case 'r': c = '\r'; break;
case 't': c = '\t'; break;
case 'v': c = (int) 0x0B; break;
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
c -= '0';
if (*s >= '0' && *s <= '7')
c = c * 8 + (*s++ - '0');
if (*s >= '0' && *s <= '7')
c = c * 8 + (*s++ - '0');
break;
case '\\': break;
default: putchar ('\\'); break;
}
}
putchar(c);
}
argc--;
argv++;
if (argc > 0)
putchar(' ');
}
}
else
#endif /* V9_ECHO */
{
while (argc > 0)
{
fputs (argv[0], stdout);
argc--;
argv++;
if (argc > 0)
putchar (' ');
}
}
}
if (display_return)
printf ("\n");
exit (0);
}

168
src/env.c Normal file
View File

@ -0,0 +1,168 @@
/* env - run a program in a modified environment
Copyright (C) 1986, 1991 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Richard Mlynarik and David MacKenzie */
/* Options:
-
-i
--ignore-environment
Construct a new environment from scratch; normally the
environment is inherited from the parent process, except as
modified by other options.
-u variable
--unset=variable
Unset variable VARIABLE (remove it from the environment).
If VARIABLE was not set, does nothing.
variable=value (an arg containing a "=" character)
Set the environment variable VARIABLE to value VALUE. VALUE
may be of zero length ("variable="). Setting a variable to a
zero-length value is different from unsetting it.
--
Indicate that the following argument is the program
to invoke. This is necessary when the program's name
begins with "-" or contains a "=".
The first remaining argument specifies a program to invoke;
it is searched for according to the specification of the PATH
environment variable. Any arguments following that are
passed as arguments to that program.
If no command name is specified following the environment
specifications, the resulting environment is printed.
This is like specifying a command name of "printenv".
Examples:
If the environment passed to "env" is
{ LOGNAME=rms EDITOR=emacs PATH=.:/gnubin:/hacks }
env - foo
runs "foo" in a null environment.
env foo
runs "foo" in the environment
{ LOGNAME=rms EDITOR=emacs PATH=.:/gnubin:/hacks }
env DISPLAY=gnu:0 nemacs
runs "nemacs" in the envionment
{ LOGNAME=rms EDITOR=emacs PATH=.:/gnubin:/hacks DISPLAY=gnu:0 }
env - LOGNAME=foo /hacks/hack bar baz
runs the "hack" program on arguments "bar" and "baz" in an
environment in which the only variable is "LOGNAME". Note that
the "-" option clears out the PATH variable, so one should be
careful to specify in which directory to find the program to
call.
env -u EDITOR LOGNAME=foo PATH=/energy -- e=mc2 bar baz
runs the program "/energy/e=mc2" with environment
{ LOGNAME=foo PATH=/energy }
*/
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include "system.h"
int putenv ();
void error ();
void usage ();
extern char **environ;
/* The name by which this program was run. */
char *program_name;
struct option longopts[] =
{
{"ignore-environment", 0, NULL, 'i'},
{"unset", 1, NULL, 'u'},
{NULL, 0, NULL, 0}
};
void
main (argc, argv, envp)
register int argc;
register char **argv;
char **envp;
{
char *dummy_environ[1];
int optc;
int ignore_environment = 0;
program_name = argv[0];
while ((optc = getopt_long (argc, argv, "+iu:", longopts, (int *) 0)) != EOF)
{
switch (optc)
{
case 'i':
ignore_environment = 1;
break;
case 'u':
break;
default:
usage ();
}
}
if (optind != argc && !strcmp (argv[optind], "-"))
ignore_environment = 1;
environ = dummy_environ;
environ[0] = NULL;
if (!ignore_environment)
for (; *envp; envp++)
putenv (*envp);
optind = 0; /* Force GNU getopt to re-initialize. */
while ((optc = getopt_long (argc, argv, "+iu:", longopts, (int *) 0)) != EOF)
if (optc == 'u')
putenv (optarg); /* Requires GNU putenv. */
if (optind != argc && !strcmp (argv[optind], "-"))
++optind;
while (optind < argc && index (argv[optind], '='))
putenv (argv[optind++]);
/* If no program is specified, print the environment and exit. */
if (optind == argc)
{
while (*environ)
puts (*environ++);
exit (0);
}
execvp (argv[optind], &argv[optind]);
error (errno == ENOENT ? 127 : 126, errno, "%s", argv[optind]);
}
void
usage ()
{
fprintf (stderr, "\
Usage: %s [-] [-i] [-u name] [--ignore-environment] [--unset=name]\n\
[name=value]... [command [args...]]\n",
program_name);
exit (2);
}

672
src/expr.c Normal file
View File

@ -0,0 +1,672 @@
/* expr -- evaluate expressions.
Copyright (C) 1986, 1991 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Author: Mike Parker.
This program evaluates expressions. Each token (operator, operand,
parenthesis) of the expression must be a seperate argument. The
parser used is a reasonably general one, though any incarnation of
it is language-specific. It is especially nice for expressions.
No parse tree is needed; a new node is evaluated immediately.
One function can handle multiple operators all of equal precedence,
provided they all associate ((x op x) op x).
Define EVAL_TRACE to print an evaluation trace. */
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <regex.h>
#include "system.h"
#if !__STDC__
#define const
#endif
#define NEW(type) ((type *) xmalloc (sizeof (type)))
#define OLD(x) free ((char *) x)
/* The kinds of value we can have. */
enum valtype
{
integer,
string
};
typedef enum valtype TYPE;
/* A value is.... */
struct valinfo
{
TYPE type; /* Which kind. */
union
{ /* The value itself. */
int i;
char *s;
} u;
};
typedef struct valinfo VALUE;
/* The arguments given to the program, minus the program name. */
char **args;
/* The name this program was run with. */
char *program_name;
VALUE *docolon ();
VALUE *eval ();
VALUE *int_value ();
VALUE *str_value ();
char *xstrdup ();
char *strstr ();
char *xmalloc ();
int isstring ();
int nextarg ();
int nomoreargs ();
int null ();
int toarith ();
void error ();
void freev ();
void printv ();
void tostring ();
void trace ();
void
main (argc, argv)
int argc;
char **argv;
{
VALUE *v;
program_name = argv[0];
if (argc == 1)
{
fprintf (stderr, "Usage: %s expression...\n", argv[0]);
exit (1);
}
args = argv + 1;
v = eval ();
if (!nomoreargs ())
error (2, 0, "syntax error");
printv (v);
exit (null (v));
}
/* Return a VALUE for I. */
VALUE *
int_value (i)
int i;
{
VALUE *v;
v = NEW (VALUE);
v->type = integer;
v->u.i = i;
return v;
}
/* Return a VALUE for S. */
VALUE *
str_value (s)
char *s;
{
VALUE *v;
v = NEW (VALUE);
v->type = string;
v->u.s = xstrdup (s);
return v;
}
/* Free VALUE V, including structure components. */
void
freev (v)
VALUE *v;
{
if (v->type == string)
free (v->u.s);
OLD (v);
}
/* Print VALUE V. */
void
printv (v)
VALUE *v;
{
switch (v->type)
{
case integer:
printf ("%d\n", v->u.i);
break;
case string:
printf ("%s\n", v->u.s);
break;
}
}
/* Return nonzero if V is a null-string or zero-number. */
int
null (v)
VALUE *v;
{
switch (v->type)
{
case integer:
return v->u.i == 0;
case string:
return v->u.s[0] == '\0';
}
}
/* Return nonzero if V is a string value. */
int
isstring (v)
VALUE *v;
{
return v->type == string;
}
/* Coerce V to a string value (can't fail). */
void
tostring (v)
VALUE *v;
{
char *temp;
switch (v->type)
{
case integer:
temp = xmalloc (4 * (sizeof (int) / sizeof (char)));
sprintf (temp, "%d", v->u.i);
v->u.s = temp;
v->type = string;
break;
case string:
break;
}
}
/* Coerce V to an integer value. Return 1 on success, 0 on failure. */
int
toarith (v)
VALUE *v;
{
int i;
int neg;
char *cp;
switch (v->type)
{
case integer:
return 1;
case string:
i = 0;
cp = v->u.s;
neg = (*cp == '-');
if (neg)
cp++;
for (; *cp; cp++)
{
if (isdigit (*cp))
i = i * 10 + *cp - '0';
else
return 0;
}
free (v->u.s);
v->u.i = i * (neg ? -1 : 1);
v->type = integer;
return 1;
}
}
/* Return nonzero if the next token matches STR exactly.
STR must not be NULL. */
int
nextarg (str)
char *str;
{
if (*args == NULL)
return 0;
return strcmp (*args, str) == 0;
}
/* Return nonzero if there no more tokens. */
int
nomoreargs ()
{
return *args == 0;
}
/* The comparison operator handling functions. */
#define cmpf(name, rel) \
int name (l, r) VALUE *l; VALUE *r; \
{ \
if (isstring (l) || isstring (r)) \
{ \
tostring (l); \
tostring (r); \
return strcmp (l->u.s, r->u.s) rel 0; \
} \
else \
return l->u.i rel r->u.i; \
}
cmpf (less_than, <)
cmpf (less_equal, <=)
cmpf (equal, ==)
cmpf (not_equal, !=)
cmpf (greater_equal, >=)
cmpf (greater_than, >)
#undef cmpf
/* The arithmetic operator handling functions. */
#define arithf(name, op) \
int name (l, r) VALUE *l; VALUE *r; \
{ \
if (!toarith (l) || !toarith (r)) \
error (2, 0, "non-numeric argument"); \
return l->u.i op r->u.i; \
}
arithf (plus, +)
arithf (minus, -)
arithf (multiply, *)
arithf (divide, /)
arithf (mod, %)
#undef arithf
#ifdef EVAL_TRACE
/* Print evaluation trace and args remaining. */
void
trace (fxn)
char *fxn;
{
char **a;
printf ("%s:", fxn);
for (a = args; *a; a++)
printf (" %s", *a);
putchar ('\n');
}
#endif
/* Do the : operator.
SV is the VALUE for the lhs (the string),
PV is the VALUE for the rhs (the pattern). */
VALUE *
docolon (sv, pv)
VALUE *sv;
VALUE *pv;
{
VALUE *v;
const char *errmsg;
struct re_pattern_buffer re_buffer;
struct re_registers re_regs;
int len;
tostring (sv);
tostring (pv);
len = strlen (pv->u.s);
re_buffer.allocated = 2 * len;
re_buffer.buffer = (unsigned char *) xmalloc (re_buffer.allocated);
re_buffer.translate = 0;
errmsg = re_compile_pattern (pv->u.s, len, &re_buffer);
if (errmsg)
error (2, 0, "%s", errmsg);
len = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
if (len >= 0)
{
/* Were \(...\) used? */
if (re_buffer.re_nsub > 0)/* was (re_regs.start[1] >= 0) */
{
sv->u.s[re_regs.end[1]] = '\0';
v = str_value (sv->u.s + re_regs.start[1]);
}
else
v = int_value (len);
}
else
{
/* Match failed -- return the right kind of null. */
if (strstr (pv->u.s, "\\("))
v = str_value ("");
else
v = int_value (0);
}
free (re_buffer.buffer);
return v;
}
/* Handle bare operands and ( expr ) syntax. */
VALUE *
eval7 ()
{
VALUE *v;
#ifdef EVAL_TRACE
trace ("eval7");
#endif
if (nomoreargs ())
error (2, 0, "syntax error");
else if (nextarg ("("))
{
args++;
v = eval ();
if (!nextarg (")"))
error (2, 0, "syntax error");
args++;
return v;
}
else if (nextarg (")"))
error (2, 0, "syntax error");
else
return str_value (*args++);
}
/* Handle match, substr, index, and length keywords. */
VALUE *
eval6 ()
{
VALUE *l;
VALUE *r;
VALUE *v;
VALUE *i1;
VALUE *i2;
#ifdef EVAL_TRACE
trace ("eval6");
#endif
if (nextarg ("length"))
{
args++;
r = eval6 ();
tostring (r);
v = int_value (strlen (r->u.s));
freev (r);
return v;
}
else if (nextarg ("match"))
{
args++;
l = eval6 ();
r = eval6 ();
v = docolon (l, r);
freev (l);
freev (r);
return v;
}
else if (nextarg ("index"))
{
args++;
l = eval6 ();
r = eval6 ();
tostring (l);
tostring (r);
v = int_value (strcspn (l->u.s, r->u.s) + 1);
if (v->u.i == strlen (l->u.s) + 1)
v->u.i = 0;
freev (l);
freev (r);
return v;
}
else if (nextarg ("substr"))
{
args++;
l = eval6 ();
i1 = eval6 ();
i2 = eval6 ();
tostring (l);
if (!toarith (i1) || !toarith (i2)
|| i1->u.i > strlen (l->u.s)
|| i1->u.i <= 0 || i2->u.i <= 0)
v = str_value ("");
else
{
v = NEW (VALUE);
v->type = string;
v->u.s = strncpy ((char *) xmalloc (i2->u.i + 1),
l->u.s + i1->u.i - 1, i2->u.i);
}
freev (l);
freev (i1);
freev (i2);
return v;
}
else
return eval7 ();
}
/* Handle : operator (pattern matching).
Calls docolon to do the real work. */
VALUE *
eval5 ()
{
VALUE *l;
VALUE *r;
VALUE *v;
#ifdef EVAL_TRACE
trace ("eval5");
#endif
l = eval6 ();
while (1)
{
if (nextarg (":"))
{
args++;
r = eval6 ();
v = docolon (l, r);
freev (l);
freev (r);
l = v;
}
else
return l;
}
}
/* Handle *, /, % operators. */
VALUE *
eval4 ()
{
VALUE *l;
VALUE *r;
int (*fxn) ();
int val;
#ifdef EVAL_TRACE
trace ("eval4");
#endif
l = eval5 ();
while (1)
{
if (nextarg ("*"))
fxn = multiply;
else if (nextarg ("/"))
fxn = divide;
else if (nextarg ("%"))
fxn = mod;
else
return l;
args++;
r = eval5 ();
val = (*fxn) (l, r);
freev (l);
freev (r);
l = int_value (val);
}
}
/* Handle +, - operators. */
VALUE *
eval3 ()
{
VALUE *l;
VALUE *r;
int (*fxn) ();
int val;
#ifdef EVAL_TRACE
trace ("eval3");
#endif
l = eval4 ();
while (1)
{
if (nextarg ("+"))
fxn = plus;
else if (nextarg ("-"))
fxn = minus;
else
return l;
args++;
r = eval4 ();
val = (*fxn) (l, r);
freev (l);
freev (r);
l = int_value (val);
}
}
/* Handle comparisons. */
VALUE *
eval2 ()
{
VALUE *l;
VALUE *r;
int (*fxn) ();
int val;
#ifdef EVAL_TRACE
trace ("eval2");
#endif
l = eval3 ();
while (1)
{
if (nextarg ("<"))
fxn = less_than;
else if (nextarg ("<="))
fxn = less_equal;
else if (nextarg ("=") || nextarg ("=="))
fxn = equal;
else if (nextarg ("!="))
fxn = not_equal;
else if (nextarg (">="))
fxn = greater_equal;
else if (nextarg (">"))
fxn = greater_than;
else
return l;
args++;
r = eval3 ();
toarith (l);
toarith (r);
val = (*fxn) (l, r);
freev (l);
freev (r);
l = int_value (val);
}
}
/* Handle &. */
VALUE *
eval1 ()
{
VALUE *l;
VALUE *r;
#ifdef EVAL_TRACE
trace ("eval1");
#endif
l = eval2 ();
while (1)
{
if (nextarg ("&"))
{
args++;
r = eval2 ();
if (null (l) || null (r))
{
freev (l);
freev (r);
l = int_value (0);
}
else
freev (r);
}
else
return l;
}
}
/* Handle |. */
VALUE *
eval ()
{
VALUE *l;
VALUE *r;
#ifdef EVAL_TRACE
trace ("eval");
#endif
l = eval1 ();
while (1)
{
if (nextarg ("|"))
{
args++;
r = eval1 ();
if (null (l))
{
freev (l);
l = r;
}
else
freev (r);
}
else
return l;
}
}

31
src/groups.sh Executable file
View File

@ -0,0 +1,31 @@
#!/bin/sh
# groups -- print the groups a user is in
# Copyright (C) 1991 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
# Written by David MacKenzie <djm@gnu.ai.mit.edu>.
# Make sure we get GNU id, if possible; also allow
# it to be somewhere else in PATH if not installed yet.
PATH=@bindir@:$PATH
if [ $# -eq 0 ]; then
id -Gn
else
for name in "$@"; do
echo $name : `id -Gn $name`
done
fi

346
src/id.c Normal file
View File

@ -0,0 +1,346 @@
/* id -- print real and effective UIDs and GIDs
Copyright (C) 1989, 1991 Free Software Foundation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by Arnold Robbins, arnold@audiofax.com.
Major rewrite by David MacKenzie, djm@gnu.ai.mit.edu. */
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include "system.h"
#ifdef _POSIX_VERSION
#include <limits.h>
#if !defined(NGROUPS_MAX) || NGROUPS_MAX < 1
#define NGROUPS_MAX sysconf (_SC_NGROUPS_MAX)
#endif /* !NGROUPS_MAX */
/* Even though SunOS 4, Ultrix 4, and 386BSD are mostly POSIX.1 compliant,
their getgroups system call (except in the `System V' environment, which
is troublesome in other ways) fills in an array of int, not gid_t
(which is `short' on those systems). Kludge, kludge. */
#if !defined(sun) && !defined(ultrix) && !defined(__386BSD__)
#define GETGROUPS_T gid_t
#else /* sun or ultrix or 386BSD */
#define GETGROUPS_T int
#endif /* sun or ultrix or 386BSD */
#else /* not _POSIX_VERSION */
struct passwd *getpwuid ();
struct group *getgrgid ();
uid_t getuid ();
gid_t getgid ();
uid_t geteuid ();
gid_t getegid ();
#include <sys/param.h>
#if !defined(NGROUPS_MAX) && defined(NGROUPS)
#define NGROUPS_MAX NGROUPS
#endif /* not NGROUPS_MAX and NGROUPS */
#define GETGROUPS_T int
#endif /* not _POSIX_VERSION */
char *xmalloc ();
int getugroups ();
void error ();
void print_user ();
void print_group ();
void print_group_list ();
void print_full_info ();
void usage ();
/* The name this program was run with. */
char *program_name;
/* If nonzero, output only the group ID(s). -g */
int just_group = 0;
/* If nonzero, output user/group name instead of ID number. -n */
int use_name = 0;
/* If nonzero, output real UID/GID instead of default effective UID/GID. -r */
int use_real = 0;
/* If nonzero, output only the user ID(s). -u */
int just_user = 0;
/* If nonzero, output only the supplementary groups. -G */
int just_group_list = 0;
/* The real and effective IDs of the user to print. */
uid_t ruid, euid;
gid_t rgid, egid;
/* The number of errors encountered so far. */
int problems = 0;
struct option longopts[] =
{
{"group", 0, NULL, 'g'},
{"name", 0, NULL, 'n'},
{"real", 0, NULL, 'r'},
{"user", 0, NULL, 'u'},
{"groups", 0, NULL, 'G'},
{NULL, 0, NULL, 0}
};
void
main (argc, argv)
int argc;
char **argv;
{
int optc;
program_name = argv[0];
while ((optc = getopt_long (argc, argv, "gnruG", longopts, (int *) 0))
!= EOF)
{
switch (optc)
{
case 'g':
just_group = 1;
break;
case 'n':
use_name = 1;
break;
case 'r':
use_real = 1;
break;
case 'u':
just_user = 1;
break;
case 'G':
just_group_list = 1;
break;
default:
usage ();
}
}
if (just_user + just_group + just_group_list > 1)
error (1, 0, "cannot print only user and only group");
if (just_user + just_group + just_group_list == 0 && (use_real || use_name))
error (1, 0, "cannot print only names or real IDs in default format");
if (argc - optind > 1)
usage ();
if (argc - optind == 1)
{
struct passwd *pwd = getpwnam (argv[optind]);
if (pwd == NULL)
error (1, 0, "%s: No such user", argv[optind]);
ruid = euid = pwd->pw_uid;
rgid = egid = pwd->pw_gid;
}
else
{
euid = geteuid ();
ruid = getuid ();
egid = getegid ();
rgid = getgid ();
}
if (just_user)
print_user (use_real ? ruid : euid);
else if (just_group)
print_group (use_real ? rgid : egid);
else if (just_group_list)
print_group_list (argv[optind]);
else
print_full_info (argv[optind]);
putchar ('\n');
exit (problems != 0);
}
/* Print the name or value of user ID UID. */
void
print_user (uid)
int uid;
{
struct passwd *pwd = NULL;
if (use_name)
{
pwd = getpwuid (uid);
if (pwd == NULL)
problems++;
}
if (pwd == NULL)
printf ("%u", (unsigned) uid);
else
printf ("%s", pwd->pw_name);
}
/* Print the name or value of group ID GID. */
void
print_group (gid)
int gid;
{
struct group *grp = NULL;
if (use_name)
{
grp = getgrgid (gid);
if (grp == NULL)
problems++;
}
if (grp == NULL)
printf ("%u", (unsigned) gid);
else
printf ("%s", grp->gr_name);
}
/* Print all of the distinct groups the user is in . */
void
print_group_list (username)
char *username;
{
print_group (rgid);
if (egid != rgid)
{
putchar (' ');
print_group (egid);
}
#ifdef NGROUPS_MAX
{
int ngroups;
GETGROUPS_T *groups;
register int i;
groups = (GETGROUPS_T *) xmalloc (NGROUPS_MAX * sizeof (GETGROUPS_T));
if (username == 0)
ngroups = getgroups (NGROUPS_MAX, groups);
else
ngroups = getugroups (NGROUPS_MAX, groups, username);
if (ngroups < 0)
{
error (0, errno, "cannot get supplemental group list");
problems++;
free (groups);
return;
}
for (i = 0; i < ngroups; i++)
if (groups[i] != rgid && groups[i] != egid)
{
putchar (' ');
print_group (groups[i]);
}
free (groups);
}
#endif
}
/* Print all of the info about the user's user and group IDs. */
void
print_full_info (username)
char *username;
{
struct passwd *pwd;
struct group *grp;
printf ("uid=%u", (unsigned) ruid);
pwd = getpwuid (ruid);
if (pwd == NULL)
problems++;
else
printf ("(%s)", pwd->pw_name);
printf (" gid=%u", (unsigned) rgid);
grp = getgrgid (rgid);
if (grp == NULL)
problems++;
else
printf ("(%s)", grp->gr_name);
if (euid != ruid)
{
printf (" euid=%u", (unsigned) euid);
pwd = getpwuid (euid);
if (pwd == NULL)
problems++;
else
printf ("(%s)", pwd->pw_name);
}
if (egid != rgid)
{
printf (" egid=%u", (unsigned) egid);
grp = getgrgid (egid);
if (grp == NULL)
problems++;
else
printf ("(%s)", grp->gr_name);
}
#ifdef NGROUPS_MAX
{
int ngroups;
GETGROUPS_T *groups;
register int i;
groups = (GETGROUPS_T *) xmalloc (NGROUPS_MAX * sizeof (GETGROUPS_T));
if (username == 0)
ngroups = getgroups (NGROUPS_MAX, groups);
else
ngroups = getugroups (NGROUPS_MAX, groups, username);
if (ngroups < 0)
{
error (0, errno, "cannot get supplemental group list");
problems++;
free (groups);
return;
}
if (ngroups > 0)
fputs (" groups=", stdout);
for (i = 0; i < ngroups; i++)
{
if (i > 0)
putchar (',');
printf ("%u", (unsigned) groups[i]);
grp = getgrgid (groups[i]);
if (grp == NULL)
problems++;
else
printf ("(%s)", grp->gr_name);
}
free (groups);
}
#endif
}
void
usage ()
{
fprintf (stderr, "\
Usage: %s [-gnruG] [--group] [--name] [--real] [--user] [--groups] [username]\n",
program_name);
exit (1);
}

43
src/logname.c Normal file
View File

@ -0,0 +1,43 @@
/* logname -- print user's login name
Copyright (C) 1990, 1991 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include <sys/types.h>
#include "system.h"
void
main (argc, argv)
int argc;
char **argv;
{
register char *cp;
if (argc != 1)
{
fprintf (stderr, "Usage: %s\n", argv[0]);
exit (1);
}
cp = getlogin ();
if (cp)
{
puts (cp);
exit (0);
}
fprintf (stderr,"%s: no login name\n", argv[0]);
exit (1);
}

150
src/nice.c Normal file
View File

@ -0,0 +1,150 @@
/* nice -- run a program with modified scheduling priority
Copyright (C) 1990, 1991 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* David MacKenzie <djm@ai.mit.edu> */
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#ifndef NICE_PRIORITY
#include <sys/time.h>
#include <sys/resource.h>
#endif
#include "system.h"
int isinteger ();
void error ();
void usage ();
/* The name this program was run with. */
char *program_name;
struct option longopts[] =
{
{"adjustment", 1, NULL, 'n'},
{NULL, 0, NULL, 0}
};
void
main (argc, argv)
int argc;
char **argv;
{
int current_priority;
int adjustment = 0;
int minusflag = 0;
int adjustment_given = 0;
int optc;
program_name = argv[0];
while ((optc = getopt_long (argc, argv, "+0123456789-n:", longopts,
(int *) 0)) != EOF)
{
switch (optc)
{
case '?':
usage ();
case 'n':
if (!isinteger (optarg))
error (1, 0, "invalid priority `%s'", optarg);
adjustment = atoi (optarg);
adjustment_given = 1;
break;
case '-':
minusflag = 1;
break;
default:
adjustment = adjustment * 10 + optc - '0';
adjustment_given = 1;
}
}
if (minusflag)
adjustment = -adjustment;
if (!adjustment_given)
adjustment = 10;
if (optind == argc)
{
if (adjustment_given)
usage ();
/* No command given; print the priority. */
errno = 0;
#ifndef NICE_PRIORITY
current_priority = getpriority (PRIO_PROCESS, 0);
#else
current_priority = nice (0);
#endif
if (current_priority == -1 && errno != 0)
error (1, errno, "cannot get priority");
printf ("%d\n", current_priority);
exit (0);
}
errno = 0;
#ifndef NICE_PRIORITY
current_priority = getpriority (PRIO_PROCESS, 0);
#else
current_priority = nice (0);
#endif
if (current_priority == -1 && errno != 0)
error (1, errno, "cannot get priority");
#ifndef NICE_PRIORITY
if (setpriority (PRIO_PROCESS, 0, current_priority + adjustment))
#else
if (nice (adjustment) == -1)
#endif
error (1, errno, "cannot set priority");
execvp (argv[optind], &argv[optind]);
error (errno == ENOENT ? 127 : 126, errno, "%s", argv[optind]);
}
/* Return nonzero if S represents a (possibly signed) decimal integer,
zero if not. */
int
isinteger (s)
char *s;
{
if (*s == '-')
++s;
if (*s == 0)
return 0;
while (*s)
{
if (*s < '0' || *s > '9')
return 0;
++s;
}
return 1;
}
void
usage ()
{
fprintf (stderr, "\
Usage: %s [-n adjustment] [-adjustment] [--adjustment=adjustment]\n\
[command [arg...]]\n",
program_name);
exit (1);
}

48
src/nohup.sh Executable file
View File

@ -0,0 +1,48 @@
#!/bin/sh
# nohup -- run a command immume to hangups, with output to a non-tty
# Copyright (C) 1991 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
# Written by David MacKenzie <djm@gnu.ai.mit.edu>.
# Make sure we get GNU nice, if possible; also allow
# it to be somewhere else in PATH if not installed yet.
PATH=@bindir@:$PATH
if [ $# -eq 0 ]; then
echo "Usage: nohup command [arg...]" 2>&1
exit 1
fi
trap "" 1
oldmask=`umask`; umask 077
# Only redirect the output if the user didn't already do it.
if [ -t 1 ]; then
# If we cannot write to the current directory, use the home directory.
if cat /dev/null >> nohup.out; then
echo "nohup: appending output to \`nohup.out'" 2>&1
umask $oldmask
exec nice -5 "$@" >> nohup.out 2>&1
else
cat /dev/null >> $HOME/nohup.out
echo "nohup: appending output to \`$HOME/nohup.out'" 2>&1
umask $oldmask
exec nice -5 "$@" >> $HOME/nohup.out 2>&1
fi
else
umask $oldmask
exec nice -5 "$@"
fi

332
src/pathchk.c Normal file
View File

@ -0,0 +1,332 @@
/* pathchk -- check whether pathnames are valid or portable
Copyright (C) 1991, 1992 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Usage: pathchk [-p] [--portability] path...
For each PATH, print a message if any of these conditions are false:
* all existing leading directories in PATH have search (execute) permission
* strlen (PATH) <= PATH_MAX
* strlen (each_directory_in_PATH) <= NAME_MAX
Exit status:
0 All PATH names passed all of the tests.
1 An error occurred.
Options:
-p, --portability Instead of performing length checks on the
underlying filesystem, test the length of the
pathname and its components against the POSIX.1
minimum limits for portability, _POSIX_NAME_MAX
and _POSIX_PATH_MAX in 2.9.2. Also check that
the pathname contains no characters not in the
portable filename character set.
David MacKenzie <djm@gnu.ai.mit.edu>
and Jim Meyering <meyering@cs.utexas.edu> */
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include "system.h"
#ifdef _POSIX_VERSION
#include <limits.h>
#ifndef PATH_MAX
#define PATH_MAX_FOR(p) pathconf ((p), _PC_PATH_MAX)
#endif /* not PATH_MAX */
#ifndef NAME_MAX
#define NAME_MAX_FOR(p) pathconf ((p), _PC_NAME_MAX);
#endif /* not NAME_MAX */
#else /* not _POSIX_VERSION */
#include <sys/param.h>
#ifndef PATH_MAX
#ifdef MAXPATHLEN
#define PATH_MAX MAXPATHLEN
#else /* not MAXPATHLEN */
#define PATH_MAX _POSIX_PATH_MAX
#endif /* not MAXPATHLEN */
#endif /* not PATH_MAX */
#ifndef NAME_MAX
#ifdef MAXNAMLEN
#define NAME_MAX MAXNAMLEN
#else /* not MAXNAMLEN */
#define NAME_MAX _POSIX_NAME_MAX
#endif /* not MAXNAMLEN */
#endif /* not NAME_MAX */
#endif /* not _POSIX_VERSION */
#ifndef _POSIX_PATH_MAX
#define _POSIX_PATH_MAX 255
#endif
#ifndef _POSIX_NAME_MAX
#define _POSIX_NAME_MAX 14
#endif
#ifndef PATH_MAX_FOR
#define PATH_MAX_FOR(p) PATH_MAX
#endif
#ifndef NAME_MAX_FOR
#define NAME_MAX_FOR(p) NAME_MAX
#endif
char *xstrdup();
int validate_path ();
void error ();
void usage ();
/* The name this program was run with. */
char *program_name;
struct option longopts[] =
{
{"portability", 0, NULL, 'p'},
{NULL, 0, NULL, 0}
};
void
main (argc, argv)
int argc;
char **argv;
{
int exit_status = 0;
int check_portability = 0;
int optc;
program_name = argv[0];
while ((optc = getopt_long (argc, argv, "p", longopts, (int *) 0)) != EOF)
{
switch (optc)
{
case 'p':
check_portability = 1;
break;
default:
usage ();
}
}
if (optind == argc)
usage ();
for (; optind < argc; ++optind)
exit_status |= validate_path (argv[optind], check_portability);
exit (exit_status);
}
/* Each element is nonzero if the corresponding ASCII character is
in the POSIX portable character set, and zero if it is not.
In addition, the entry for `/' is nonzero to simplify checking. */
char portable_chars[] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0-15 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16-31 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, /* 32-47 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 48-63 */
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 64-79 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 80-95 */
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 96-111 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 112-127 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/* If PATH contains only portable characters, return 1, else 0. */
int
portable_chars_only (path)
char *path;
{
char *p;
for (p = path; *p; ++p)
if (portable_chars[*p] == 0)
{
error (0, 0, "path `%s' contains nonportable character `%c'",
path, *p);
return 0;
}
return 1;
}
/* Return 1 if PATH is a usable leading directory, 0 if not,
2 if it doesn't exist. */
int
dir_ok (path)
char *path;
{
struct stat stats;
if (stat (path, &stats))
return 2;
if (!S_ISDIR (stats.st_mode))
{
error (0, 0, "`%s' is not a directory", path);
return 0;
}
/* Use access to test for search permission because
testing permission bits of st_mode can lose with new
access control mechanisms. Of course, access loses if you're
running setuid. */
if (access (path, X_OK) != 0)
{
if (errno == EACCES)
error (0, 0, "directory `%s' is not searchable", path);
else
error (0, errno, "%s", path);
return 0;
}
return 1;
}
/* Make sure that
strlen (PATH) <= PATH_MAX
&& strlen (each-existing-directory-in-PATH) <= NAME_MAX
If PORTABILITY is nonzero, compare against _POSIX_PATH_MAX and
_POSIX_NAME_MAX instead, and make sure that PATH contains no
characters not in the POSIX portable filename character set, which
consists of A-Z, a-z, 0-9, ., _, -.
Make sure that all leading directories along PATH that exist have
`x' permission.
Return 0 if all of these tests are successful, 1 if any fail. */
int
validate_path (path, portability)
char *path;
int portability;
{
int path_max;
int last_elem; /* Nonzero if checking last element of path. */
int exists; /* 2 if the path element exists. */
char *slash;
char *parent; /* Last existing leading directory so far. */
if (portability && !portable_chars_only (path))
return 1;
if (*path == '\0')
return 0;
/* Figure out the parent of the first element in PATH. */
parent = xstrdup (*path == '/' ? "/" : ".");
slash = path;
last_elem = 0;
while (1)
{
int name_max;
int length; /* Length of partial path being checked. */
char *start; /* Start of path element being checked. */
/* Find the end of this element of the path.
Then chop off the rest of the path after this element. */
while (*slash == '/')
slash++;
start = slash;
slash = index (slash, '/');
if (slash != NULL)
*slash = '\0';
else
{
last_elem = 1;
slash = index (start, '\0');
}
if (!last_elem)
{
exists = dir_ok (path);
if (dir_ok == 0)
{
free (parent);
return 1;
}
}
length = slash - start;
/* Since we know that `parent' is a directory, it's ok to call
pathconf with it as the argument. (If `parent' isn't a directory
or doesn't exist, the behavior of pathconf is undefined.)
But if `parent' is a directory and is on a remote file system,
it's likely that pathconf can't give us a reasonable value
and will return -1. (NFS and tempfs are not POSIX . . .)
In that case, we have no choice but to assume the pessimal
POSIX minimums. */
name_max = portability ? _POSIX_NAME_MAX : NAME_MAX_FOR (parent);
if (name_max < 0)
name_max = _POSIX_NAME_MAX;
if (length > name_max)
{
error (0, 0, "name `%s' has length %d; exceeds limit of %d",
start, length, name_max);
free (parent);
return 1;
}
if (last_elem)
break;
if (exists == 1)
{
free (parent);
parent = xstrdup (path);
}
*slash++ = '/';
}
/* `parent' is now the last existing leading directory in the whole path,
so it's ok to call pathconf with it as the argument. */
path_max = portability ? _POSIX_PATH_MAX : PATH_MAX_FOR (parent);
if (path_max < 0)
path_max = _POSIX_PATH_MAX;
free (parent);
if (strlen (path) > path_max)
{
error (0, 0, "path `%s' has length %d; exceeds limit of %d",
path, strlen (path), path_max);
return 1;
}
return 0;
}
void
usage ()
{
fprintf (stderr, "\
Usage: %s [-p] [--portability] path...\n",
program_name);
exit (1);
}

69
src/printenv.c Normal file
View File

@ -0,0 +1,69 @@
/* printenv -- print all or part of environment
Copyright (C) 1989, 1991 Free Software Foundation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Usage: printenv [variable...]
If no arguments are given, print the entire environment.
If one or more variable names are given, print the value of
each one that is set, and nothing for ones that are not set.
Exit status:
0 if all variables specified were found
1 if not
David MacKenzie and Richard Mlynarik */
#include <stdio.h>
#include <sys/types.h>
#include "system.h"
extern char **environ;
void
main (argc, argv)
int argc;
char **argv;
{
char **env;
char *ep, *ap;
int i;
int matches = 0;
if (argc == 1)
{
for (env = environ; *env; ++env)
puts (*env);
exit (0);
}
for (i = 1; i < argc; ++i)
{
for (env = environ; *env; ++env)
{
ep = *env;
ap = argv[i];
while (*ep != '\0' && *ap != '\0' && *ep++ == *ap++)
if (*ep == '=' && *ap == '\0')
{
puts (ep + 1);
++matches;
break;
}
}
}
exit (matches != argc - 1);
}

481
src/printf.c Normal file
View File

@ -0,0 +1,481 @@
/* printf - format and print data
Copyright (C) 1990, 1991 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Usage: printf format [argument...]
A front end to the printf function that lets it be used from the shell.
Backslash escapes:
\" = double quote
\\ = backslash
\a = alert (bell)
\b = backspace
\c = produce no further output
\f = form feed
\n = new line
\r = carriage return
\t = horizontal tab
\v = vertical tab
\0ooo = octal number (ooo is 0 to 3 digits)
\xhhh = hexadecimal number (hhh is 1 to 3 digits)
Additional directive:
%b = print an argument string, interpreting backslash escapes
The `format' argument is re-used as many times as necessary
to convert all of the given arguments.
David MacKenzie <djm@gnu.ai.mit.edu> */
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include "system.h"
#ifndef STDC_HEADERS
double strtod ();
long strtol ();
unsigned long strtoul ();
#endif
#define isodigit(c) ((c) >= '0' && (c) <= '7')
#define hextobin(c) ((c)>='a'&&(c)<='f' ? (c)-'a'+10 : (c)>='A'&&(c)<='F' ? (c)-'A'+10 : (c)-'0')
#define octtobin(c) ((c) - '0')
char *xmalloc ();
double xstrtod ();
int print_esc ();
int print_formatted ();
long xstrtol ();
unsigned long xstrtoul ();
void error ();
void print_direc ();
void print_esc_char ();
void print_esc_string ();
void verify ();
/* The name this program was run with. */
char *program_name;
/* The value to return to the calling program. */
int exit_status;
void
main (argc, argv)
int argc;
char **argv;
{
char *format;
int args_used;
program_name = argv[0];
exit_status = 0;
if (argc == 1)
{
fprintf (stderr, "Usage: %s format [argument...]\n", program_name);
exit (1);
}
format = argv[1];
argc -= 2;
argv += 2;
do
{
args_used = print_formatted (format, argc, argv);
argc -= args_used;
argv += args_used;
}
while (args_used > 0 && argc > 0);
exit (exit_status);
}
/* Print the text in FORMAT, using ARGV (with ARGC elements) for
arguments to any `%' directives.
Return the number of elements of ARGV used. */
int
print_formatted (format, argc, argv)
char *format;
int argc;
char **argv;
{
int save_argc = argc; /* Preserve original value. */
char *f; /* Pointer into `format'. */
char *direc_start; /* Start of % directive. */
int direc_length; /* Length of % directive. */
int field_width; /* Arg to first '*', or -1 if none. */
int precision; /* Arg to second '*', or -1 if none. */
for (f = format; *f; ++f)
{
switch (*f)
{
case '%':
direc_start = f++;
direc_length = 1;
field_width = precision = -1;
if (*f == '%')
{
putchar ('%');
break;
}
if (*f == 'b')
{
if (argc > 0)
{
print_esc_string (*argv);
++argv;
--argc;
}
break;
}
if (index ("-+ #", *f))
{
++f;
++direc_length;
}
if (*f == '*')
{
++f;
++direc_length;
if (argc > 0)
{
field_width = xstrtoul (*argv);
++argv;
--argc;
}
else
field_width = 0;
}
else
while (isdigit (*f))
{
++f;
++direc_length;
}
if (*f == '.')
{
++f;
++direc_length;
if (*f == '*')
{
++f;
++direc_length;
if (argc > 0)
{
precision = xstrtoul (*argv);
++argv;
--argc;
}
else
precision = 0;
}
else
while (isdigit (*f))
{
++f;
++direc_length;
}
}
if (*f == 'l' || *f == 'L' || *f == 'h')
{
++f;
++direc_length;
}
if (!index ("diouxXfeEgGcs", *f))
error (1, 0, "%%%c: invalid directive", *f);
++direc_length;
if (argc > 0)
{
print_direc (direc_start, direc_length, field_width,
precision, *argv);
++argv;
--argc;
}
else
print_direc (direc_start, direc_length, field_width,
precision, "");
break;
case '\\':
f += print_esc (f);
break;
default:
putchar (*f);
}
}
return save_argc - argc;
}
/* Print a \ escape sequence starting at ESCSTART.
Return the number of characters in the escape sequence
besides the backslash. */
int
print_esc (escstart)
char *escstart;
{
register char *p = escstart + 1;
int esc_value = 0; /* Value of \nnn escape. */
int esc_length; /* Length of \nnn escape. */
/* \0ooo and \xhhh escapes have maximum length of 3 chars. */
if (*p == 'x')
{
for (esc_length = 0, ++p;
esc_length < 3 && isxdigit (*p);
++esc_length, ++p)
esc_value = esc_value * 16 + hextobin (*p);
if (esc_length == 0)
error (1, 0, "missing hexadecimal number in escape");
putchar (esc_value);
}
else if (*p == '0')
{
for (esc_length = 0, ++p;
esc_length < 3 && isodigit (*p);
++esc_length, ++p)
esc_value = esc_value * 8 + octtobin (*p);
putchar (esc_value);
}
else if (index ("\"\\abcfnrtv", *p))
print_esc_char (*p++);
else
error (1, 0, "\\%c: invalid escape", *p);
return p - escstart - 1;
}
/* Output a single-character \ escape. */
void
print_esc_char (c)
char c;
{
switch (c)
{
case 'a': /* Alert. */
putchar (7);
break;
case 'b': /* Backspace. */
putchar (8);
break;
case 'c': /* Cancel the rest of the output. */
exit (0);
break;
case 'f': /* Form feed. */
putchar (12);
break;
case 'n': /* New line. */
putchar (10);
break;
case 'r': /* Carriage return. */
putchar (13);
break;
case 't': /* Horizontal tab. */
putchar (9);
break;
case 'v': /* Vertical tab. */
putchar (11);
break;
default:
putchar (c);
break;
}
}
/* Print string STR, evaluating \ escapes. */
void
print_esc_string (str)
char *str;
{
for (; *str; str++)
if (*str == '\\')
str += print_esc (str);
else
putchar (*str);
}
/* Output a % directive. START is the start of the directive,
LENGTH is its length, and ARGUMENT is its argument.
If FIELD_WIDTH or PRECISION is non-negative, they are args for
'*' values in those fields. */
void
print_direc (start, length, field_width, precision, argument)
char *start;
int length;
int field_width;
int precision;
char *argument;
{
char *p; /* Null-terminated copy of % directive. */
p = xmalloc ((unsigned) (length + 1));
strncpy (p, start, length);
p[length] = 0;
switch (p[length - 1])
{
case 'd':
case 'i':
if (field_width < 0)
{
if (precision < 0)
printf (p, xstrtol (argument));
else
printf (p, precision, xstrtol (argument));
}
else
{
if (precision < 0)
printf (p, field_width, xstrtol (argument));
else
printf (p, field_width, precision, xstrtol (argument));
}
break;
case 'o':
case 'u':
case 'x':
case 'X':
if (field_width < 0)
{
if (precision < 0)
printf (p, xstrtoul (argument));
else
printf (p, precision, xstrtoul (argument));
}
else
{
if (precision < 0)
printf (p, field_width, xstrtoul (argument));
else
printf (p, field_width, precision, xstrtoul (argument));
}
break;
case 'f':
case 'e':
case 'E':
case 'g':
case 'G':
if (field_width < 0)
{
if (precision < 0)
printf (p, xstrtod (argument));
else
printf (p, precision, xstrtod (argument));
}
else
{
if (precision < 0)
printf (p, field_width, xstrtod (argument));
else
printf (p, field_width, precision, xstrtod (argument));
}
break;
case 'c':
printf (p, *argument);
break;
case 's':
if (field_width < 0)
{
if (precision < 0)
printf (p, argument);
else
printf (p, precision, argument);
}
else
{
if (precision < 0)
printf (p, field_width, argument);
else
printf (p, field_width, precision, argument);
}
break;
}
free (p);
}
unsigned long
xstrtoul (s)
char *s;
{
char *end;
unsigned long val;
errno = 0;
val = strtoul (s, &end, 0);
verify (s, end);
return val;
}
long
xstrtol (s)
char *s;
{
char *end;
long val;
errno = 0;
val = strtol (s, &end, 0);
verify (s, end);
return val;
}
double
xstrtod (s)
char *s;
{
char *end;
double val;
errno = 0;
val = strtod (s, &end);
verify (s, end);
return val;
}
void
verify (s, end)
char *s, *end;
{
if (errno)
{
error (0, errno, "%s", s);
exit_status = 1;
}
else if (*end)
{
if (s == end)
error (0, 0, "%s: expected a numeric value", s);
else
error (0, 0, "%s: value not completely converted", s);
exit_status = 1;
}
}

84
src/sleep.c Normal file
View File

@ -0,0 +1,84 @@
/* sleep - delay for a specified amount of time.
Copyright (C) 1984, 1991 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include <sys/types.h>
#include "system.h"
long argdecode ();
void error ();
/* The name by which this program was run. */
char *program_name;
void
main (argc, argv)
int argc;
char **argv;
{
int i;
unsigned seconds = 0;
program_name = argv[0];
if (argc == 1)
{
fprintf (stderr, "Usage: %s number[smhd]...\n", argv[0]);
exit (1);
}
for (i = 1; i < argc; i++)
seconds += argdecode (argv[i]);
sleep (seconds);
exit (0);
}
long
argdecode (s)
char *s;
{
long value;
register char *p = s;
register char c;
value = 0;
while ((c = *p++) >= '0' && c <= '9')
value = value * 10 + c - '0';
switch (c)
{
case 's':
break;
case 'm':
value *= 60;
break;
case 'h':
value *= 60 * 60;
break;
case 'd':
value *= 60 * 60 * 24;
break;
default:
p--;
}
if (*p)
error (1, 0, "invalid time interval `%s'", s);
return value;
}

1241
src/stty.c Normal file

File diff suppressed because it is too large Load Diff

519
src/su.c Normal file
View File

@ -0,0 +1,519 @@
/* su for GNU. Run a shell with substitute user and group IDs.
Copyright (C) 1992 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Run a shell with the real and effective UID and GID and groups
of USER, default `root'.
The shell run is taken from USER's password entry, /bin/sh if
none is specified there. If the account has a password, su
prompts for a password unless run by a user with real UID 0.
Does not change the current directory.
Sets `HOME' and `SHELL' from the password entry for USER, and if
USER is not root, sets `USER' and `LOGNAME' to USER.
The subshell is not a login shell.
If one or more ARGs are given, they are passed as additional
arguments to the subshell.
Does not handle /bin/sh or other shells specially
(setting argv[0] to "-su", passing -c only to certain shells, etc.).
I don't see the point in doing that, and it's ugly.
This program intentionally does not support a "wheel group" that
restricts who can su to UID 0 accounts. RMS considers that to
be fascist.
Options:
-, -l, --login Make the subshell a login shell.
Unset all environment variables except
TERM, HOME and SHELL (set as above), and USER
and LOGNAME (set unconditionally as above), and
set PATH to a default value.
Change to USER's home directory.
Prepend "-" to the shell's name.
-c, --commmand=COMMAND
Pass COMMAND to the subshell with a -c option
instead of starting an interactive shell.
-f, --fast Pass the -f option to the subshell.
-m, -p, --preserve-environment
Do not change HOME, USER, LOGNAME, SHELL.
Run $SHELL instead of USER's shell from /etc/passwd
unless not the superuser and USER's shell is
restricted.
Overridden by --login and --shell.
-s, --shell=shell Run SHELL instead of USER's shell from /etc/passwd
unless not the superuser and USER's shell is
restricted.
Compile-time options:
-DSYSLOG_SUCCESS Log successful su's (by default, to root) with syslog.
-DSYSLOG_FAILURE Log failed su's (by default, to root) with syslog.
-DSYSLOG_NON_ROOT Log all su's, not just those to root (UID 0).
Never logs attempted su's to nonexistent accounts.
Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include <pwd.h>
#include "system.h"
#ifdef HAVE_SYSLOG_H
#include <syslog.h>
void log_su ();
#else
#ifdef SYSLOG_SUCCESS
#undef SYSLOG_SUCCESS
#endif
#ifdef SYSLOG_FAILURE
#undef SYSLOG_FAILURE
#endif
#ifdef SYSLOG_NON_ROOT
#undef SYSLOG_NON_ROOT
#endif
#endif
#ifdef _POSIX_VERSION
#include <limits.h>
#ifdef NGROUPS_MAX
#undef NGROUPS_MAX
#endif
#define NGROUPS_MAX sysconf (_SC_NGROUPS_MAX)
#else /* not _POSIX_VERSION */
struct passwd *getpwuid ();
struct group *getgrgid ();
uid_t getuid ();
#include <sys/param.h>
#if !defined(NGROUPS_MAX) && defined(NGROUPS)
#define NGROUPS_MAX NGROUPS
#endif
#endif /* not _POSIX_VERSION */
#ifdef _POSIX_SOURCE
#define endgrent()
#define endpwent()
#endif
#ifdef HAVE_SHADOW_H
#include <shadow.h>
#endif
/* The default PATH for simulated logins to non-superuser accounts. */
#define DEFAULT_LOGIN_PATH ":/usr/ucb:/bin:/usr/bin"
/* The default PATH for simulated logins to superuser accounts. */
#define DEFAULT_ROOT_LOGIN_PATH "/usr/ucb:/bin:/usr/bin:/etc"
/* The shell to run if none is given in the user's passwd entry. */
#define DEFAULT_SHELL "/bin/sh"
/* The user to become if none is specified. */
#define DEFAULT_USER "root"
char *crypt ();
char *getpass ();
char *getusershell ();
void endusershell ();
void setusershell ();
char *basename ();
char *concat ();
char *xmalloc ();
char *xrealloc ();
int correct_password ();
int elements ();
int restricted_shell ();
void change_identity ();
void error ();
void modify_environment ();
void run_shell ();
void usage ();
void xputenv ();
extern char **environ;
/* The name this program was run with. */
char *program_name;
/* If nonzero, pass the `-f' option to the subshell. */
int fast_startup;
/* If nonzero, simulate a login instead of just starting a shell. */
int simulate_login;
/* If nonzero, change some environment vars to indicate the user su'd to. */
int change_environment;
struct option longopts[] =
{
{"command", 1, 0, 'c'},
{"fast", 0, &fast_startup, 1},
{"login", 0, &simulate_login, 1},
{"preserve-environment", 0, &change_environment, 0},
{"shell", 1, 0, 's'},
{0, 0, 0, 0}
};
void
main (argc, argv)
int argc;
char **argv;
{
int optc;
char *new_user = DEFAULT_USER;
char *command = 0;
char **additional_args = 0;
char *shell = 0;
struct passwd *pw;
program_name = argv[0];
fast_startup = 0;
simulate_login = 0;
change_environment = 1;
while ((optc = getopt_long (argc, argv, "c:flmps:", longopts, (int *) 0))
!= EOF)
{
switch (optc)
{
case 0:
break;
case 'c':
command = optarg;
break;
case 'f':
fast_startup = 1;
break;
case 'l':
simulate_login = 1;
break;
case 'm':
case 'p':
change_environment = 0;
break;
case 's':
shell = optarg;
break;
default:
usage ();
}
}
if (optind < argc && !strcmp (argv[optind], "-"))
{
simulate_login = 1;
++optind;
}
if (optind < argc)
new_user = argv[optind++];
if (optind < argc)
additional_args = argv + optind;
pw = getpwnam (new_user);
if (pw == 0)
error (1, 0, "user %s does not exist", new_user);
endpwent ();
if (!correct_password (pw))
{
#ifdef SYSLOG_FAILURE
log_su (pw, 0);
#endif
error (1, 0, "incorrect password");
}
#ifdef SYSLOG_SUCCESS
else
{
log_su (pw, 1);
}
#endif
if (pw->pw_shell == 0 || pw->pw_shell[0] == 0)
pw->pw_shell = DEFAULT_SHELL;
if (shell == 0 && change_environment == 0)
shell = getenv ("SHELL");
if (shell != 0 && getuid () && restricted_shell (pw->pw_shell))
{
/* The user being su'd to has a nonstandard shell, and so is
probably a uucp account or has restricted access. Don't
compromise the account by allowing access with a standard
shell. */
error (0, 0, "using restricted shell %s", pw->pw_shell);
shell = 0;
}
if (shell == 0)
shell = pw->pw_shell;
shell = strcpy (xmalloc (strlen (shell) + 1), shell);
modify_environment (pw, shell);
change_identity (pw);
if (simulate_login && chdir (pw->pw_dir))
error (0, errno, "warning: cannot change directory to %s", pw->pw_dir);
run_shell (shell, command, additional_args);
}
/* Ask the user for a password.
Return 1 if the user gives the correct password for entry PW,
0 if not. Return 1 without asking for a password if run by UID 0
or if PW has an empty password. */
int
correct_password (pw)
struct passwd *pw;
{
char *unencrypted, *encrypted, *correct;
#ifdef HAVE_SHADOW_H
/* Shadow passwd stuff for SVR3 and maybe other systems. */
struct spwd *sp = getspnam (pw->pw_name);
endspent ();
if (sp)
correct = sp->sp_pwdp;
else
#endif
correct = pw->pw_passwd;
if (getuid () == 0 || correct == 0 || correct[0] == '\0')
return 1;
unencrypted = getpass ("Password:");
encrypted = crypt (unencrypted, correct);
bzero (unencrypted, strlen (unencrypted));
return strcmp (encrypted, correct) == 0;
}
/* Update `environ' for the new shell based on PW, with SHELL being
the value for the SHELL environment variable. */
void
modify_environment (pw, shell)
struct passwd *pw;
char *shell;
{
char *term;
if (simulate_login)
{
/* Leave TERM unchanged. Set HOME, SHELL, USER, LOGNAME, PATH.
Unset all other environment variables. */
term = getenv ("TERM");
environ = (char **) xmalloc (2 * sizeof (char *));
environ[0] = 0;
if (term)
xputenv (concat ("TERM", "=", term));
xputenv (concat ("HOME", "=", pw->pw_dir));
xputenv (concat ("SHELL", "=", shell));
xputenv (concat ("USER", "=", pw->pw_name));
xputenv (concat ("LOGNAME", "=", pw->pw_name));
xputenv (concat ("PATH", "=", pw->pw_uid
? DEFAULT_LOGIN_PATH : DEFAULT_ROOT_LOGIN_PATH));
}
else
{
/* Set HOME, SHELL, and if not becoming a super-user,
USER and LOGNAME. */
if (change_environment)
{
xputenv (concat ("HOME", "=", pw->pw_dir));
xputenv (concat ("SHELL", "=", shell));
if (pw->pw_uid)
{
xputenv (concat ("USER", "=", pw->pw_name));
xputenv (concat ("LOGNAME", "=", pw->pw_name));
}
}
}
}
/* Become the user and group(s) specified by PW. */
void
change_identity (pw)
struct passwd *pw;
{
#ifdef NGROUPS_MAX
errno = 0;
if (initgroups (pw->pw_name, pw->pw_gid) == -1)
error (1, errno, "cannot set groups");
endgrent ();
#endif
if (setgid (pw->pw_gid))
error (1, errno, "cannot set group id");
if (setuid (pw->pw_uid))
error (1, errno, "cannot set user id");
}
/* Run SHELL, or DEFAULT_SHELL if SHELL is empty.
If COMMAND is nonzero, pass it to the shell with the -c option.
If ADDITIONAL_ARGS is nonzero, pass it to the shell as more
arguments. */
void
run_shell (shell, command, additional_args)
char *shell;
char *command;
char **additional_args;
{
char **args;
int argno = 1;
if (additional_args)
args = (char **) xmalloc (sizeof (char *)
* (10 + elements (additional_args)));
else
args = (char **) xmalloc (sizeof (char *) * 10);
if (simulate_login)
{
args[0] = xmalloc (strlen (shell) + 2);
args[0][0] = '-';
strcpy (args[0] + 1, basename (shell));
}
else
args[0] = basename (shell);
if (fast_startup)
args[argno++] = "-f";
if (command)
{
args[argno++] = "-c";
args[argno++] = command;
}
if (additional_args)
for (; *additional_args; ++additional_args)
args[argno++] = *additional_args;
args[argno] = 0;
execv (shell, args);
error (1, errno, "cannot run %s", shell);
}
#if defined (SYSLOG_SUCCESS) || defined (SYSLOG_FAILURE)
/* Log the fact that someone has run su to the user given by PW;
if SUCCESSFUL is nonzero, they gave the correct password, etc. */
void
log_su (pw, successful)
struct passwd *pw;
int successful;
{
char *new_user, *old_user, *tty;
#ifndef SYSLOG_NON_ROOT
if (pw->pw_uid)
return;
#endif
new_user = pw->pw_name;
/* The utmp entry (via getlogin) is probably the best way to identify
the user, especially if someone su's from a su-shell. */
old_user = getlogin ();
if (old_user == 0)
old_user = "";
tty = ttyname (2);
if (tty == 0)
tty = "";
/* 4.2BSD openlog doesn't have the third parameter. */
openlog (basename (program_name), 0
#ifdef LOG_AUTH
, LOG_AUTH
#endif
);
syslog (LOG_NOTICE,
#ifdef SYSLOG_NON_ROOT
"%s(to %s) %s on %s",
#else
"%s%s on %s",
#endif
successful ? "" : "FAILED SU ",
#ifdef SYSLOG_NON_ROOT
new_user,
#endif
old_user, tty);
closelog ();
}
#endif
/* Return 1 if SHELL is a restricted shell (one not returned by
getusershell), else 0, meaning it is a standard shell. */
int
restricted_shell (shell)
char *shell;
{
char *line;
setusershell ();
while (line = getusershell ())
{
if (*line != '#' && strcmp (line, shell) == 0)
{
endusershell ();
return 0;
}
}
endusershell ();
return 1;
}
/* Return the number of elements in ARR, a null-terminated array. */
int
elements (arr)
char **arr;
{
int n = 0;
for (n = 0; *arr; ++arr)
++n;
return n;
}
/* Add VAL to the environment, checking for out of memory errors. */
void
xputenv (val)
char *val;
{
if (putenv (val))
error (1, 0, "virtual memory exhausted");
}
/* Return a newly-allocated string whose contents concatenate
those of S1, S2, S3. */
char *
concat (s1, s2, s3)
char *s1, *s2, *s3;
{
int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
strcpy (result, s1);
strcpy (result + len1, s2);
strcpy (result + len1 + len2, s3);
result[len1 + len2 + len3] = 0;
return result;
}
void
usage ()
{
fprintf (stderr, "\
Usage: %s [-flmp] [-c command] [-s shell] [--login] [--fast]\n\
[--preserve-environment] [--command=command] [--shell=shell] [-]\n\
[user [arg...]]\n", program_name);
exit (1);
}

155
src/tee.c Normal file
View File

@ -0,0 +1,155 @@
/* tee - read from standard input and write to standard output and files.
Copyright (C) 1985, 1990, 1991 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Mike Parker, Richard M. Stallman, and David MacKenzie */
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <getopt.h>
#include "system.h"
char *xmalloc ();
int tee ();
void error ();
void xwrite ();
/* If nonzero, append to output files rather than truncating them. */
int append;
/* If nonzero, ignore interrupts. */
int ignore_interrupts;
/* The name that this program was run with. */
char *program_name;
struct option long_options[] =
{
{"append", 0, NULL, 'a'},
{"ignore-interrupts", 0, NULL, 'i'},
{NULL, 0, NULL, 0}
};
void
main (argc, argv)
int argc;
char **argv;
{
int errs;
int optc;
program_name = argv[0];
append = 0;
ignore_interrupts = 0;
while ((optc = getopt_long (argc, argv, "ai", long_options, (int *) 0))
!= EOF)
{
switch (optc)
{
case 'a':
append = 1;
break;
case 'i':
ignore_interrupts = 1;
break;
default:
fprintf (stderr, "\
Usage: %s [-ai] [--append] [--ignore-interrupts] [file...]\n",
program_name);
exit (1);
}
}
if (ignore_interrupts)
#ifdef _POSIX_VERSION
{
struct sigaction sigact;
sigact.sa_handler = SIG_IGN;
sigemptyset (&sigact.sa_mask);
sigact.sa_flags = 0;
sigaction (SIGINT, &sigact, NULL);
}
#else /* !_POSIX_VERSION */
signal (SIGINT, SIG_IGN);
#endif /* _POSIX_VERSION */
errs = tee (argc - optind, &argv[optind]);
if (close (0) == -1)
error (1, errno, "standard input");
if (close (1) == -1)
error (1, errno, "standard output");
exit (errs);
}
/* Copy the standard input into each of the NFILES files in FILES
and into the standard output.
Return 0 if successful, 1 if any errors occur. */
int
tee (nfiles, files)
int nfiles;
char **files;
{
int *descriptors;
char buffer[BUFSIZ];
register int bytes_read, i, ret = 0, mode;
if (nfiles)
descriptors = (int *) xmalloc (nfiles * sizeof (int));
mode = O_WRONLY | O_CREAT;
if (append)
mode |= O_APPEND;
else
mode |= O_TRUNC;
for (i = 0; i < nfiles; i++)
{
descriptors[i] = open (files[i], mode, 0666);
if (descriptors[i] == -1)
{
error (0, errno, "%s", files[i]);
ret = 1;
}
}
while ((bytes_read = read (0, buffer, sizeof buffer)) > 0)
{
xwrite (1, buffer, bytes_read);
for (i = 0; i < nfiles; i++)
if (descriptors[i] != -1)
xwrite (descriptors[i], buffer, bytes_read);
}
if (bytes_read == -1)
{
error (0, errno, "read error");
ret = 1;
}
for (i = 0; i < nfiles; i++)
if (descriptors[i] != -1 && close (descriptors[i]) == -1)
{
error (0, errno, "%s", files[i]);
ret = 1;
}
if (nfiles)
free (descriptors);
return ret;
}

1054
src/test.c Normal file

File diff suppressed because it is too large Load Diff

88
src/tty.c Normal file
View File

@ -0,0 +1,88 @@
/* tty -- print the path of the terminal connected to standard input
Copyright (C) 1990, 1991 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Displays "not a tty" if stdin is not a terminal.
Displays nothing if -s option is given.
Exit status 0 if stdin is a tty, 1 if not, 2 if usage error.
Written by David MacKenzie (djm@ai.mit.edu). */
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include "system.h"
void usage ();
/* The name under which this program was run. */
char *program_name;
/* If nonzero, return an exit status but produce no output. */
int silent;
struct option longopts[] =
{
{"silent", 0, NULL, 's'},
{"quiet", 0, NULL, 's'},
{NULL, 0, NULL, 0}
};
void
main (argc, argv)
int argc;
char **argv;
{
char *tty;
int optc;
program_name = argv[0];
silent = 0;
while ((optc = getopt_long (argc, argv, "s", longopts, (int *) 0)) != EOF)
{
switch (optc)
{
case 's':
silent = 1;
break;
default:
usage ();
}
}
if (optind != argc)
usage ();
tty = ttyname (0);
if (!silent)
{
if (tty)
puts (tty);
else
puts ("not a tty");
}
exit (tty == NULL);
}
void
usage ()
{
fprintf (stderr, "\
Usage: %s [-s] [--silent] [--quiet]\n", program_name);
exit (2);
}

155
src/uname.c Normal file
View File

@ -0,0 +1,155 @@
/* uname -- print system information
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Option Example
-s, --sysname SunOS
-n, --nodename rocky8
-r, --release 4.0
-v, --version
-m, --machine sun
-a, --all SunOS rocky8 4.0 sun
The default behavior is equivalent to `-s'.
David MacKenzie <djm@ai.mit.edu> */
#include <stdio.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <getopt.h>
#include "system.h"
void error ();
void print_element ();
void usage ();
/* Values that are bitwise or'd into `toprint'. */
/* Operating system name. */
#define PRINT_SYSNAME 1
/* Node name on a communications network. */
#define PRINT_NODENAME 2
/* Operating system release. */
#define PRINT_RELEASE 4
/* Operating system version. */
#define PRINT_VERSION 8
/* Machine hardware name. */
#define PRINT_MACHINE 16
/* Mask indicating which elements of the name to print. */
unsigned char toprint;
/* The name this program was run with, for error messages. */
char *program_name;
struct option long_options[] =
{
{"sysname", 0, NULL, 's'},
{"nodename", 0, NULL, 'n'},
{"release", 0, NULL, 'r'},
{"version", 0, NULL, 'v'},
{"machine", 0, NULL, 'm'},
{"all", 0, NULL, 'a'},
{NULL, 0, NULL, 0}
};
void
main (argc, argv)
int argc;
char **argv;
{
struct utsname name;
int c;
program_name = argv[0];
toprint = 0;
while ((c = getopt_long (argc, argv, "snrvma", long_options, (int *) 0))
!= EOF)
{
switch (c)
{
case 's':
toprint |= PRINT_SYSNAME;
break;
case 'n':
toprint |= PRINT_NODENAME;
break;
case 'r':
toprint |= PRINT_RELEASE;
break;
case 'v':
toprint |= PRINT_VERSION;
break;
case 'm':
toprint |= PRINT_MACHINE;
break;
case 'a':
toprint = PRINT_SYSNAME | PRINT_NODENAME | PRINT_RELEASE |
PRINT_VERSION | PRINT_MACHINE;
break;
default:
usage ();
}
}
if (optind != argc)
usage ();
if (toprint == 0)
toprint = PRINT_SYSNAME;
if (uname (&name) == -1)
error (1, errno, "cannot get system name");
print_element (PRINT_SYSNAME, name.sysname);
print_element (PRINT_NODENAME, name.nodename);
print_element (PRINT_RELEASE, name.release);
print_element (PRINT_VERSION, name.version);
print_element (PRINT_MACHINE, name.machine);
exit (0);
}
/* If the name element set in MASK is selected for printing in `toprint',
print ELEMENT; then print a space unless it is the last element to
be printed, in which case print a newline. */
void
print_element (mask, element)
unsigned char mask;
char *element;
{
if (toprint & mask)
{
toprint &= ~mask;
printf ("%s%c", element, toprint ? ' ' : '\n');
}
}
void
usage ()
{
fprintf (stderr, "\
Usage: %s [-snrvma] [--sysname] [--nodename] [--release] [--version]\n\
[--machine] [--all]\n", program_name);
exit (1);
}

434
src/who.c Normal file
View File

@ -0,0 +1,434 @@
/* GNU's who.
Copyright (C) 1992 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by jla; revised by djm */
/* Output format:
name [state] line time [idle] host
state: -T
name, line, time: not -q
idle: -u
Options:
-m Same as 'who am i', for POSIX.
-q Only user names and # logged on; overrides all other options.
-s Name, line, time (default).
-i, -u Idle hours and minutes; '.' means active in last minute;
'old' means idle for >24 hours.
-H Print column headings at top.
-w, -T -s plus mesg (+ or -, or ? if bad line). */
#include <stdio.h>
#include <sys/types.h>
#include <utmp.h>
#include <time.h>
#include <getopt.h>
#ifndef _POSIX_SOURCE
#include <sys/param.h>
#endif
#include "system.h"
#ifndef UTMP_FILE
#ifdef _PATH_UTMP /* 4.4BSD. */
#define UTMP_FILE _PATH_UTMP
#else /* !_PATH_UTMP */
#define UTMP_FILE "/etc/utmp"
#endif /* !_PATH_UTMP */
#endif /* !UTMP_FILE */
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 64
#endif
#define MESG_BIT 020 /* Group write bit. */
char *ttyname ();
char *idle_string ();
char *xmalloc ();
struct utmp *search_entries ();
void error ();
void list_entries ();
void print_entry ();
void print_heading ();
void scan_entries ();
void usage ();
void who ();
void who_am_i ();
/* The name this program was run with. */
char *program_name;
/* If nonzero, display only a list of usernames and count of
the users logged on.
Ignored for `who am i'. */
int short_list;
/* If nonzero, display the hours:minutes since each user has touched
the keyboard, or "." if within the last minute, or "old" if
not within the last day. */
int include_idle;
/* If nonzero, display a line at the top describing each field. */
int include_heading;
/* If nonzero, display a `+' for each user if mesg y, a `-' if mesg n,
or a `?' if their tty cannot be statted. */
int include_mesg;
struct option longopts[] =
{
{"count", 0, NULL, 'q'},
{"idle", 0, NULL, 'u'},
{"heading", 0, NULL, 'H'},
{"message", 0, NULL, 'T'},
{"mesg", 0, NULL, 'T'},
{"writable", 0, NULL, 'T'},
{NULL, 0, NULL, 0}
};
void
main (argc, argv)
int argc;
char **argv;
{
int optc, longind;
int my_line_only = 0;
program_name = argv[0];
while ((optc = getopt_long (argc, argv, "imqsuwHT", longopts, &longind))
!= EOF)
{
switch (optc)
{
case 'm':
my_line_only = 1;
break;
case 'q':
short_list = 1;
break;
case 's':
break;
case 'i':
case 'u':
include_idle = 1;
break;
case 'H':
include_heading = 1;
break;
case 'w':
case 'T':
include_mesg = 1;
break;
default:
usage ();
}
}
if (chdir ("/dev"))
error (1, errno, "cannot change directory to /dev");
switch (argc - optind)
{
case 0: /* who */
if (my_line_only)
who_am_i (UTMP_FILE);
else
who (UTMP_FILE);
break;
case 1: /* who <utmp file> */
if (my_line_only)
who_am_i (argv[optind]);
else
who (argv[optind]);
break;
case 2: /* who <blurf> <glop> */
who_am_i (UTMP_FILE);
break;
default: /* lose */
usage ();
}
exit (0);
}
static struct utmp *utmp_contents;
/* Display a list of who is on the system, according to utmp file FILENAME. */
void
who (filename)
char *filename;
{
int users;
users = read_utmp (filename);
if (short_list)
list_entries (users);
else
scan_entries (users);
}
/* Read the utmp file FILENAME into UTMP_CONTENTS and return the
number of entries it contains. */
int
read_utmp (filename)
char *filename;
{
register int desc;
struct stat file_stats;
desc = open (filename, O_RDONLY, 0);
if (desc < 0)
error (1, errno, "%s", filename);
fstat (desc, &file_stats);
if (file_stats.st_size > 0)
utmp_contents = (struct utmp *) xmalloc ((unsigned) file_stats.st_size);
else
{
close (desc);
return 0;
}
/* Use < instead of != in case the utmp just grew. */
if (read (desc, utmp_contents, file_stats.st_size) < file_stats.st_size)
error (1, errno, "%s", filename);
if (close (desc))
error (1, errno, "%s", filename);
return file_stats.st_size / sizeof (struct utmp);
}
/* Display a line of information about entry THIS. */
void
print_entry (this)
struct utmp *this;
{
struct stat stats;
time_t last_change;
char mesg;
char line[sizeof (this->ut_line) + 1];
strncpy (line, this->ut_line, sizeof (this->ut_line));
line[sizeof (this->ut_line)] = 0;
if (stat (line, &stats) == 0)
{
mesg = (stats.st_mode & MESG_BIT) ? '+' : '-';
last_change = stats.st_atime;
}
else
{
mesg = '?';
last_change = 0;
}
printf ("%-*.*s",
sizeof (this->ut_name), sizeof (this->ut_name),
this->ut_name);
if (include_mesg)
printf (" %c ", mesg);
printf (" %-*.*s",
sizeof (this->ut_line), sizeof (this->ut_line),
this->ut_line);
printf (" %-12.12s", ctime (&this->ut_time) + 4);
if (include_idle)
{
if (last_change)
printf (" %s", idle_string (last_change));
else
printf (" . ");
}
#ifdef HAVE_UT_HOST
if (this->ut_host[0])
printf (" (%-.*s)", sizeof (this->ut_host), this->ut_host);
#endif
putchar ('\n');
}
/* Print the username of each valid entry and the number of valid entries
in `utmp_contents', which should have N elements. */
void
list_entries (n)
int n;
{
register struct utmp *this = utmp_contents;
register int entries = 0;
while (n--)
{
if (this->ut_name[0]
#ifdef USER_PROCESS
&& this->ut_type == USER_PROCESS
#endif
)
{
printf ("%s ", this->ut_name);
entries++;
}
this++;
}
printf ("\n# users=%u\n", entries);
}
void
print_heading ()
{
struct utmp *ut;
printf ("%-*s ", sizeof (ut->ut_name), "USER");
if (include_mesg)
printf ("MESG ");
printf ("%-*s ", sizeof (ut->ut_line), "LINE");
printf ("LOGIN-TIME ");
if (include_idle)
printf ("IDLE ");
printf ("FROM\n");
}
/* Display `utmp_contents', which should have N entries. */
void
scan_entries (n)
int n;
{
register struct utmp *this = utmp_contents;
if (include_heading)
print_heading ();
while (n--)
{
if (this->ut_name[0]
#ifdef USER_PROCESS
&& this->ut_type == USER_PROCESS
#endif
)
print_entry (this);
this++;
}
}
/* Search `utmp_contents', which should have N entries, for
an entry with a `ut_line' field identical to LINE.
Return the first matching entry found, or NULL if there
is no matching entry. */
struct utmp *
search_entries (n, line)
int n;
char *line;
{
register struct utmp *this = utmp_contents;
while (n--)
{
if (this->ut_name[0]
#ifdef USER_PROCESS
&& this->ut_type == USER_PROCESS
#endif
&& !strncmp (line, this->ut_line, sizeof (this->ut_line)))
return this;
this++;
}
return NULL;
}
/* Display the entry in utmp file FILENAME for this tty on standard input,
or nothing if there is no entry for it. */
void
who_am_i (filename)
char *filename;
{
register struct utmp *utmp_entry;
char hostname[MAXHOSTNAMELEN + 1];
char *tty;
if (gethostname (hostname, MAXHOSTNAMELEN + 1))
*hostname = 0;
if (include_heading)
{
printf ("%*s ", strlen (hostname), " ");
print_heading ();
}
tty = ttyname (0);
if (tty == NULL)
return;
tty += 5; /* Remove "/dev/". */
utmp_entry = search_entries (read_utmp (filename), tty);
if (utmp_entry == NULL)
return;
printf ("%s!", hostname);
print_entry (utmp_entry);
}
/* Return a string representing the time between WHEN and the time
that this function is first run. */
char *
idle_string (when)
time_t when;
{
static time_t now = 0;
static char idle[10];
time_t seconds_idle;
if (now == 0)
time (&now);
seconds_idle = now - when;
if (seconds_idle < 60) /* One minute. */
return " . ";
if (seconds_idle < (24 * 60 * 60)) /* One day. */
{
sprintf (idle, "%02d:%02d",
seconds_idle / (60 * 60),
(seconds_idle % (60 * 60)) / 60);
return idle;
}
return " old ";
}
void
usage ()
{
fprintf (stderr, "\
Usage: %s [-imqsuwHT] [--count] [--idle] [--heading] [--message] [--mesg]\n\
[--writable] [file] [am i]\n",
program_name);
exit (1);
}

49
src/whoami.c Normal file
View File

@ -0,0 +1,49 @@
/* whoami -- print effective userid
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Equivalent to `id -un'. */
/* Written by Richard Mlynarik. */
#include <stdio.h>
#include <sys/types.h>
#include <pwd.h>
#include "system.h"
void
main (argc, argv)
int argc;
char *argv[];
{
register struct passwd *pw;
register uid_t uid;
if (argc != 1)
{
fprintf (stderr, "Usage: %s\n", argv[0]);
exit (1);
}
uid = geteuid ();
pw = getpwuid (uid);
if (pw)
{
puts (pw->pw_name);
exit (0);
}
fprintf (stderr,"%s: cannot find username for UID %u\n", argv[0], uid);
exit (1);
}

39
src/yes.c Normal file
View File

@ -0,0 +1,39 @@
/* yes - output a string repeatedly until killed
Copyright (C) 1991 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* David MacKenzie <djm@ai.mit.edu> */
#include <stdio.h>
void
main (argc, argv)
int argc;
char **argv;
{
int i;
if (argc == 1)
while (1)
puts ("y");
while (1)
for (i = 1; i < argc; i++)
{
fputs (argv[i], stdout);
putchar (i == argc - 1 ? '\n' : ' ');
}
}