diff options
Diffstat (limited to 'mit-pthreads/gen')
-rwxr-xr-x | mit-pthreads/gen/GNUmakefile.inc | 9 | ||||
-rw-r--r-- | mit-pthreads/gen/Makefile.inc | 24 | ||||
-rw-r--r-- | mit-pthreads/gen/ctime.c | 1315 | ||||
-rw-r--r-- | mit-pthreads/gen/difftime.c | 46 | ||||
-rw-r--r-- | mit-pthreads/gen/directory.c | 322 | ||||
-rw-r--r-- | mit-pthreads/gen/eprintf.c | 18 | ||||
-rw-r--r-- | mit-pthreads/gen/getcwd.c | 248 | ||||
-rw-r--r-- | mit-pthreads/gen/getpwent.c | 109 | ||||
-rw-r--r-- | mit-pthreads/gen/getpwnamuid.c | 138 | ||||
-rw-r--r-- | mit-pthreads/gen/getwd.c | 57 | ||||
-rw-r--r-- | mit-pthreads/gen/isatty.c | 95 | ||||
-rw-r--r-- | mit-pthreads/gen/popen.c | 117 | ||||
-rw-r--r-- | mit-pthreads/gen/pwd_internal.c | 97 | ||||
-rw-r--r-- | mit-pthreads/gen/pwd_internal.h | 29 | ||||
-rw-r--r-- | mit-pthreads/gen/syslog.c | 216 | ||||
-rw-r--r-- | mit-pthreads/gen/time.c | 51 | ||||
-rw-r--r-- | mit-pthreads/gen/ttyname.c | 147 |
17 files changed, 3038 insertions, 0 deletions
diff --git a/mit-pthreads/gen/GNUmakefile.inc b/mit-pthreads/gen/GNUmakefile.inc new file mode 100755 index 00000000000..a5025860b85 --- /dev/null +++ b/mit-pthreads/gen/GNUmakefile.inc @@ -0,0 +1,9 @@ +# from: @(#)Makefile.inc 5.21 (Berkeley) 5/24/91 +# $Id$ + +# gen sources +VPATH:= ${VPATH}:${srcdir}/gen + +SRCS:= ttyname.c directory.c popen.c time.c ctime.c difftime.c syslog.c \ + eprintf.c getpwent.c getpwnamuid.c pwd_internal.c \ + getcwd.c getwd.c isatty.c $(SRCS) diff --git a/mit-pthreads/gen/Makefile.inc b/mit-pthreads/gen/Makefile.inc new file mode 100644 index 00000000000..6e2c3d44f43 --- /dev/null +++ b/mit-pthreads/gen/Makefile.inc @@ -0,0 +1,24 @@ +# from: @(#)Makefile.inc 5.21 (Berkeley) 5/24/91 +# $Id$ + +# gen sources +.PATH: ${srcdir}/gen + +SRCS+= ttyname.c isatty.c directory.c popen.c time.c ctime.c difftime.c \ + syslog.c eprintf.c getpwent.c getpwnamuid.c pwd_internal.c + +#SRCS+= alarm.c assert.c clock.c crypt.c ctermid.c ctype_.c \ +# disklabel.c err.c errlst.c exec.c fnmatch.c frexp.c \ +# fstab.c fts.c getcap.c getcwd.c getgrent.c getlogin.c getmntinfo.c \ +# getpass.c getpwent.c getsubopt.c getttyent.c getusershell.c glob.c \ +# infinity.c initgroups.c isatty.c isctype.c isinf.c mktemp.c nice.c \ +# nlist.c pause.c psignal.c raise.c \ +# scandir.c setjmperr.c \ +# setmode.c setrgid.c setruid.c siginterrupt.c \ +# siglist.c signal.c sigsetops.c syslog.c \ +# termios.c time.c times.c timezone.c ttyslot.c \ +# ualarm.c unvis.c utime.c valloc.c vis.c +# +# gen/regexp sources +#SRCS+= regerror.c regexp.c regsub.c + diff --git a/mit-pthreads/gen/ctime.c b/mit-pthreads/gen/ctime.c new file mode 100644 index 00000000000..e7980296e50 --- /dev/null +++ b/mit-pthreads/gen/ctime.c @@ -0,0 +1,1315 @@ +/* + * Copyright (c) 1987, 1989 Regents of the University of California. + * Copyright (c) 1994 Chris Provenzano, proven@mit.edu + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Arthur David Olson of the National Cancer Institute. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)ctime.c 5.26 (Berkeley) 2/23/91"; +#endif /* LIBC_SCCS and not lint */ + +/* +** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu). +** POSIX-style TZ environment variable handling from Guy Harris +** (guy@auspex.com). +*/ + +/*LINTLIBRARY*/ +#include "config.h" +#include <pthread.h> +#include <sys/param.h> +#include <fcntl.h> +#include <time.h> +#include <tzfile.h> +#include <string.h> +#include <ctype.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> + +#ifndef WILDABBR +/* +** Someone might make incorrect use of a time zone abbreviation: +** 1. They might reference tzname[0] before calling tzset (explicitly +** or implicitly). +** 2. They might reference tzname[1] before calling tzset (explicitly +** or implicitly). +** 3. They might reference tzname[1] after setting to a time zone +** in which Daylight Saving Time is never observed. +** 4. They might reference tzname[0] after setting to a time zone +** in which Standard Time is never observed. +** 5. They might reference tm.TM_ZONE after calling offtime. +** What's best to do in the above cases is open to debate; +** for now, we just set things up so that in any of the five cases +** WILDABBR is used. Another possibility: initialize tzname[0] to the +** string "tzname[0] used before set", and similarly for the other cases. +** And another: initialize tzname[0] to "ERA", with an explanation in the +** manual page of what this "time zone abbreviation" means (doing this so +** that tzname[0] has the "normal" length of three characters). +*/ +#define WILDABBR " " +#endif /* !defined WILDABBR */ + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif /* !defined TRUE */ + +static const char GMT[] = "GMT"; + +struct ttinfo { /* time type information */ + long tt_gmtoff; /* GMT offset in seconds */ + int tt_isdst; /* used to set tm_isdst */ + int tt_abbrind; /* abbreviation list index */ + int tt_ttisstd; /* TRUE if transition is std time */ +}; + +struct lsinfo { /* leap second information */ + time_t ls_trans; /* transition time */ + long ls_corr; /* correction to apply */ +}; + +struct state { + int leapcnt; + int timecnt; + int typecnt; + int charcnt; + time_t ats[TZ_MAX_TIMES]; + unsigned char types[TZ_MAX_TIMES]; + struct ttinfo ttis[TZ_MAX_TYPES]; + char chars[(TZ_MAX_CHARS + 1 > sizeof GMT) ? + TZ_MAX_CHARS + 1 : sizeof GMT]; + struct lsinfo lsis[TZ_MAX_LEAPS]; +}; + +struct rule { + int r_type; /* type of rule--see below */ + int r_day; /* day number of rule */ + int r_week; /* week number of rule */ + int r_mon; /* month number of rule */ + long r_time; /* transition time of rule */ +}; + +#define JULIAN_DAY 0 /* Jn - Julian day */ +#define DAY_OF_YEAR 1 /* n - day of year */ +#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */ + +/* +** Prototypes for static functions. +*/ + +static long detzcode __P_((const char *)); +static const char * getnum __P_((const char *, int *, int, int)); +static const char * getsecs __P_((const char *, long *)); +static const char * getoffset __P_((const char *, long *)); +static const char * getrule __P_((const char *, struct rule *)); +static const char * getzname __P_((const char *)); +static void gmtload __P_((struct state *)); +static void gmtsub __P_((const time_t *, long, struct tm *)); +static void localsub __P_((const time_t *, long, struct tm *)); +static void normalize __P_((int *, int *, int)); +static void settzname __P_((struct state *)); +static time_t time1 __P_((struct tm *, long)); +static time_t time2 __P_((struct tm *, long, int *)); +static void timesub __P_((const time_t *, long, const struct state *, + struct tm *)); +static int tmcomp __P_((const struct tm *, const struct tm *)); +static time_t transtime __P_((time_t, int, const struct rule *, long)); +static int tzload __P_((const char *, struct state *)); +static int tzparse __P_((const char *, struct state *, int)); +static void tzset_basic __P_((void)); +static void tzsetwall_basic __P_((void)); + +static pthread_mutex_t lcl_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t gmt_mutex = PTHREAD_MUTEX_INITIALIZER; +static int lcl_is_set = FALSE; +static int gmt_is_set = FALSE; +static struct state lclmem; +static struct state gmtmem; + +#define lclptr (&lclmem) +#define gmtptr (&gmtmem) + +char * tzname[2] = { + WILDABBR, + WILDABBR +}; + +#ifdef USG_COMPAT +time_t timezone = 0; +int daylight = 0; +#endif /* defined USG_COMPAT */ + +#ifdef ALTZONE +time_t altzone = 0; +#endif /* defined ALTZONE */ + +static long detzcode(const char * codep) +{ + long result; + int i; + + result = 0; + for (i = 0; i < 4; ++i) + result = (result << 8) | (codep[i] & 0xff); + return result; +} + +static void settzname(struct state * sp) +{ + register int i; + + tzname[0] = WILDABBR; + tzname[1] = WILDABBR; +#ifdef USG_COMPAT + daylight = 0; + timezone = 0; +#endif /* defined USG_COMPAT */ +#ifdef ALTZONE + altzone = 0; +#endif /* defined ALTZONE */ + for (i = 0; i < sp->typecnt; ++i) { + register const struct ttinfo * const ttisp = &sp->ttis[i]; + + tzname[ttisp->tt_isdst] = + (char *) &sp->chars[ttisp->tt_abbrind]; +#ifdef USG_COMPAT + if (ttisp->tt_isdst) + daylight = 1; + if (i == 0 || !ttisp->tt_isdst) + timezone = -(ttisp->tt_gmtoff); +#endif /* defined USG_COMPAT */ +#ifdef ALTZONE + if (i == 0 || ttisp->tt_isdst) + altzone = -(ttisp->tt_gmtoff); +#endif /* defined ALTZONE */ + } + /* + ** And to get the latest zone names into tzname. . . + */ + for (i = 0; i < sp->timecnt; ++i) { + register const struct ttinfo * const ttisp = + &sp->ttis[sp->types[i]]; + + tzname[ttisp->tt_isdst] = + (char *) &sp->chars[ttisp->tt_abbrind]; + } +} + +static int tzload(const char * name, struct state * sp) +{ + register const char * p; + register int i; + register int fid; + + if (name == NULL && (name = TZDEFAULT) == NULL) + return -1; + { + char fullname[FILENAME_MAX + 1]; + + if (name[0] == ':') + ++name; + if (name[0] != '/') { + if ((p = TZDIR) == NULL) + return -1; + if ((strlen(p) + strlen(name) + 1) >= sizeof fullname) + return -1; + (void) strcpy(fullname, p); + (void) strcat(fullname, "/"); + (void) strcat(fullname, name); + name = fullname; + } + if ((fid = open(name, O_RDONLY)) == -1) + return -1; + } + { + register const struct tzhead * tzhp; + char buf[sizeof *sp + sizeof *tzhp]; + int ttisstdcnt; + + i = read(fid, buf, sizeof buf); + if (close(fid) != 0 || i < sizeof *tzhp) + return -1; + tzhp = (struct tzhead *) buf; + ttisstdcnt = (int) detzcode(tzhp->tzh_ttisstdcnt); + sp->leapcnt = (int) detzcode(tzhp->tzh_leapcnt); + sp->timecnt = (int) detzcode(tzhp->tzh_timecnt); + sp->typecnt = (int) detzcode(tzhp->tzh_typecnt); + sp->charcnt = (int) detzcode(tzhp->tzh_charcnt); + if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS || + sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES || + sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES || + sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS || + (ttisstdcnt != sp->typecnt && ttisstdcnt != 0)) + return -1; + if (i < sizeof *tzhp + + sp->timecnt * (4 + sizeof (char)) + + sp->typecnt * (4 + 2 * sizeof (char)) + + sp->charcnt * sizeof (char) + + sp->leapcnt * 2 * 4 + + ttisstdcnt * sizeof (char)) + return -1; + p = buf + sizeof *tzhp; + for (i = 0; i < sp->timecnt; ++i) { + sp->ats[i] = detzcode(p); + p += 4; + } + for (i = 0; i < sp->timecnt; ++i) { + sp->types[i] = (unsigned char) *p++; + if (sp->types[i] >= sp->typecnt) + return -1; + } + for (i = 0; i < sp->typecnt; ++i) { + register struct ttinfo * ttisp; + + ttisp = &sp->ttis[i]; + ttisp->tt_gmtoff = detzcode(p); + p += 4; + ttisp->tt_isdst = (unsigned char) *p++; + if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1) + return -1; + ttisp->tt_abbrind = (unsigned char) *p++; + if (ttisp->tt_abbrind < 0 || + ttisp->tt_abbrind > sp->charcnt) + return -1; + } + for (i = 0; i < sp->charcnt; ++i) + sp->chars[i] = *p++; + sp->chars[i] = '\0'; /* ensure '\0' at end */ + for (i = 0; i < sp->leapcnt; ++i) { + register struct lsinfo * lsisp; + + lsisp = &sp->lsis[i]; + lsisp->ls_trans = detzcode(p); + p += 4; + lsisp->ls_corr = detzcode(p); + p += 4; + } + for (i = 0; i < sp->typecnt; ++i) { + register struct ttinfo * ttisp; + + ttisp = &sp->ttis[i]; + if (ttisstdcnt == 0) + ttisp->tt_ttisstd = FALSE; + else { + ttisp->tt_ttisstd = *p++; + if (ttisp->tt_ttisstd != TRUE && + ttisp->tt_ttisstd != FALSE) + return -1; + } + } + } + return 0; +} + +static const int mon_lengths[2][MONSPERYEAR] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, + 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +static const int year_lengths[2] = { + DAYSPERNYEAR, DAYSPERLYEAR +}; + +/* +** Given a pointer into a time zone string, scan until a character that is not +** a valid character in a zone name is found. Return a pointer to that +** character. +*/ +static const char * getzname(const char * strp) +{ + register char c; + + while ((c = *strp) != '\0' && !isdigit(c) && c != ',' && c != '-' && + c != '+') + ++strp; + return strp; +} + +/* +** Given a pointer into a time zone string, extract a number from that string. +** Check that the number is within a specified range; if it is not, return +** NULL. +** Otherwise, return a pointer to the first character not part of the number. +*/ + +static const char *getnum(const char * strp, int * nump, int min, int max) +{ + char c; + int num; + + if (strp == NULL || !isdigit(*strp)) + return NULL; + num = 0; + while ((c = *strp) != '\0' && isdigit(c)) { + num = num * 10 + (c - '0'); + if (num > max) + return NULL; /* illegal value */ + ++strp; + } + if (num < min) + return NULL; /* illegal value */ + *nump = num; + return strp; +} + +/* +** Given a pointer into a time zone string, extract a number of seconds, +** in hh[:mm[:ss]] form, from the string. +** If any error occurs, return NULL. +** Otherwise, return a pointer to the first character not part of the number +** of seconds. +*/ +static const char * getsecs(const char * strp, long * secsp) +{ + int num; + + strp = getnum(strp, &num, 0, HOURSPERDAY); + if (strp == NULL) + return NULL; + *secsp = num * SECSPERHOUR; + if (*strp == ':') { + ++strp; + strp = getnum(strp, &num, 0, MINSPERHOUR - 1); + if (strp == NULL) + return NULL; + *secsp += num * SECSPERMIN; + if (*strp == ':') { + ++strp; + strp = getnum(strp, &num, 0, SECSPERMIN - 1); + if (strp == NULL) + return NULL; + *secsp += num; + } + } + return strp; +} + +/* +** Given a pointer into a time zone string, extract an offset, in +** [+-]hh[:mm[:ss]] form, from the string. +** If any error occurs, return NULL. +** Otherwise, return a pointer to the first character not part of the time. +*/ +static const char * getoffset(const char * strp, long * offsetp) +{ + int neg; + + if (*strp == '-') { + neg = 1; + ++strp; + } else if (isdigit(*strp) || *strp++ == '+') + neg = 0; + else return NULL; /* illegal offset */ + strp = getsecs(strp, offsetp); + if (strp == NULL) + return NULL; /* illegal time */ + if (neg) + *offsetp = -*offsetp; + return strp; +} + +/* +** Given a pointer into a time zone string, extract a rule in the form +** date[/time]. See POSIX section 8 for the format of "date" and "time". +** If a valid rule is not found, return NULL. +** Otherwise, return a pointer to the first character not part of the rule. +*/ +static const char * getrule(const char * strp, struct rule * rulep) +{ + if (*strp == 'J') { + /* + ** Julian day. + */ + rulep->r_type = JULIAN_DAY; + ++strp; + strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR); + } else if (*strp == 'M') { + /* + ** Month, week, day. + */ + rulep->r_type = MONTH_NTH_DAY_OF_WEEK; + ++strp; + strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR); + if (strp == NULL) + return NULL; + if (*strp++ != '.') + return NULL; + strp = getnum(strp, &rulep->r_week, 1, 5); + if (strp == NULL) + return NULL; + if (*strp++ != '.') + return NULL; + strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1); + } else if (isdigit(*strp)) { + /* + ** Day of year. + */ + rulep->r_type = DAY_OF_YEAR; + strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1); + } else return NULL; /* invalid format */ + if (strp == NULL) + return NULL; + if (*strp == '/') { + /* + ** Time specified. + */ + ++strp; + strp = getsecs(strp, &rulep->r_time); + } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */ + return strp; +} + +/* +** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the +** year, a rule, and the offset from GMT at the time that rule takes effect, +** calculate the Epoch-relative time that rule takes effect. +*/ +static time_t transtime(time_t janfirst, int year, + const struct rule * rulep, long offset) +{ + register int leapyear; + register time_t value; + register int i; + int d, m1, yy0, yy1, yy2, dow; + + leapyear = isleap(year); + switch (rulep->r_type) { + + case JULIAN_DAY: + /* + ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap + ** years. + ** In non-leap years, or if the day number is 59 or less, just + ** add SECSPERDAY times the day number-1 to the time of + ** January 1, midnight, to get the day. + */ + value = janfirst + (rulep->r_day - 1) * SECSPERDAY; + if (leapyear && rulep->r_day >= 60) + value += SECSPERDAY; + break; + + case DAY_OF_YEAR: + /* + ** n - day of year. + ** Just add SECSPERDAY times the day number to the time of + ** January 1, midnight, to get the day. + */ + value = janfirst + rulep->r_day * SECSPERDAY; + break; + + case MONTH_NTH_DAY_OF_WEEK: + /* + ** Mm.n.d - nth "dth day" of month m. + */ + value = janfirst; + for (i = 0; i < rulep->r_mon - 1; ++i) + value += mon_lengths[leapyear][i] * SECSPERDAY; + + /* + ** Use Zeller's Congruence to get day-of-week of first day of + ** month. + */ + m1 = (rulep->r_mon + 9) % 12 + 1; + yy0 = (rulep->r_mon <= 2) ? (year - 1) : year; + yy1 = yy0 / 100; + yy2 = yy0 % 100; + dow = ((26 * m1 - 2) / 10 + + 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7; + if (dow < 0) + dow += DAYSPERWEEK; + + /* + ** "dow" is the day-of-week of the first day of the month. Get + ** the day-of-month (zero-origin) of the first "dow" day of the + ** month. + */ + d = rulep->r_day - dow; + if (d < 0) + d += DAYSPERWEEK; + for (i = 1; i < rulep->r_week; ++i) { + if (d + DAYSPERWEEK >= + mon_lengths[leapyear][rulep->r_mon - 1]) + break; + d += DAYSPERWEEK; + } + + /* + ** "d" is the day-of-month (zero-origin) of the day we want. + */ + value += d * SECSPERDAY; + break; + } + + /* + ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in + ** question. To get the Epoch-relative time of the specified local + ** time on that day, add the transition time and the current offset + ** from GMT. + */ + return value + rulep->r_time + offset; +} + +/* +** Given a POSIX section 8-style TZ string, fill in the rule tables as +** appropriate. +*/ +static int tzparse(const char * name, struct state * sp, int lastditch) +{ + const char * stdname; + const char * dstname; + int stdlen; + int dstlen; + long stdoffset; + long dstoffset; + register time_t * atp; + register unsigned char * typep; + register char * cp; + register int load_result; + + stdname = name; + if (lastditch) { + stdlen = strlen(name); /* length of standard zone name */ + name += stdlen; + if (stdlen >= sizeof sp->chars) + stdlen = (sizeof sp->chars) - 1; + } else { + name = getzname(name); + stdlen = name - stdname; + if (stdlen < 3) + return -1; + } + if (*name == '\0') + return -1; + else { + name = getoffset(name, &stdoffset); + if (name == NULL) + return -1; + } + load_result = tzload(TZDEFRULES, sp); + if (load_result != 0) + sp->leapcnt = 0; /* so, we're off a little */ + if (*name != '\0') { + dstname = name; + name = getzname(name); + dstlen = name - dstname; /* length of DST zone name */ + if (dstlen < 3) + return -1; + if (*name != '\0' && *name != ',' && *name != ';') { + name = getoffset(name, &dstoffset); + if (name == NULL) + return -1; + } else dstoffset = stdoffset - SECSPERHOUR; + if (*name == ',' || *name == ';') { + struct rule start; + struct rule end; + register int year; + register time_t janfirst; + time_t starttime; + time_t endtime; + + ++name; + if ((name = getrule(name, &start)) == NULL) + return -1; + if (*name++ != ',') + return -1; + if ((name = getrule(name, &end)) == NULL) + return -1; + if (*name != '\0') + return -1; + sp->typecnt = 2; /* standard time and DST */ + /* + ** Two transitions per year, from EPOCH_YEAR to 2037. + */ + sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1); + if (sp->timecnt > TZ_MAX_TIMES) + return -1; + sp->ttis[0].tt_gmtoff = -dstoffset; + sp->ttis[0].tt_isdst = 1; + sp->ttis[0].tt_abbrind = stdlen + 1; + sp->ttis[1].tt_gmtoff = -stdoffset; + sp->ttis[1].tt_isdst = 0; + sp->ttis[1].tt_abbrind = 0; + atp = sp->ats; + typep = sp->types; + janfirst = 0; + for (year = EPOCH_YEAR; year <= 2037; ++year) { + starttime = transtime(janfirst, year, &start, + stdoffset); + endtime = transtime(janfirst, year, &end, + dstoffset); + if (starttime > endtime) { + *atp++ = endtime; + *typep++ = 1; /* DST ends */ + *atp++ = starttime; + *typep++ = 0; /* DST begins */ + } else { + *atp++ = starttime; + *typep++ = 0; /* DST begins */ + *atp++ = endtime; + *typep++ = 1; /* DST ends */ + } + janfirst += + year_lengths[isleap(year)] * SECSPERDAY; + } + } else { + int sawstd; + int sawdst; + long stdfix; + long dstfix; + long oldfix; + int isdst; + register int i; + + if (*name != '\0') + return -1; + if (load_result != 0) + return -1; + /* + ** Compute the difference between the real and + ** prototype standard and summer time offsets + ** from GMT, and put the real standard and summer + ** time offsets into the rules in place of the + ** prototype offsets. + */ + sawstd = FALSE; + sawdst = FALSE; + stdfix = 0; + dstfix = 0; + for (i = 0; i < sp->typecnt; ++i) { + if (sp->ttis[i].tt_isdst) { + oldfix = dstfix; + dstfix = + sp->ttis[i].tt_gmtoff + dstoffset; + if (sawdst && (oldfix != dstfix)) + return -1; + sp->ttis[i].tt_gmtoff = -dstoffset; + sp->ttis[i].tt_abbrind = stdlen + 1; + sawdst = TRUE; + } else { + oldfix = stdfix; + stdfix = + sp->ttis[i].tt_gmtoff + stdoffset; + if (sawstd && (oldfix != stdfix)) + return -1; + sp->ttis[i].tt_gmtoff = -stdoffset; + sp->ttis[i].tt_abbrind = 0; + sawstd = TRUE; + } + } + /* + ** Make sure we have both standard and summer time. + */ + if (!sawdst || !sawstd) + return -1; + /* + ** Now correct the transition times by shifting + ** them by the difference between the real and + ** prototype offsets. Note that this difference + ** can be different in standard and summer time; + ** the prototype probably has a 1-hour difference + ** between standard and summer time, but a different + ** difference can be specified in TZ. + */ + isdst = FALSE; /* we start in standard time */ + for (i = 0; i < sp->timecnt; ++i) { + register const struct ttinfo * ttisp; + + /* + ** If summer time is in effect, and the + ** transition time was not specified as + ** standard time, add the summer time + ** offset to the transition time; + ** otherwise, add the standard time offset + ** to the transition time. + */ + ttisp = &sp->ttis[sp->types[i]]; + sp->ats[i] += + (isdst && !ttisp->tt_ttisstd) ? + dstfix : stdfix; + isdst = ttisp->tt_isdst; + } + } + } else { + dstlen = 0; + sp->typecnt = 1; /* only standard time */ + sp->timecnt = 0; + sp->ttis[0].tt_gmtoff = -stdoffset; + sp->ttis[0].tt_isdst = 0; + sp->ttis[0].tt_abbrind = 0; + } + sp->charcnt = stdlen + 1; + if (dstlen != 0) + sp->charcnt += dstlen + 1; + if (sp->charcnt > sizeof sp->chars) + return -1; + cp = sp->chars; + (void) strncpy(cp, stdname, stdlen); + cp += stdlen; + *cp++ = '\0'; + if (dstlen != 0) { + (void) strncpy(cp, dstname, dstlen); + *(cp + dstlen) = '\0'; + } + return 0; +} + +static void gmtload(struct state * sp) +{ + if (tzload(GMT, sp) != 0) + (void) tzparse(GMT, sp, TRUE); +} + +static void tzset_basic() +{ + const char * name; + if ((name = getenv("TZ")) == NULL) { + tzsetwall_basic(); + return; + } + + if (*name == '\0') { + /* + ** User wants it fast rather than right. + */ + lclptr->leapcnt = 0; /* so, we're off a little */ + lclptr->timecnt = 0; + lclptr->ttis[0].tt_gmtoff = 0; + lclptr->ttis[0].tt_abbrind = 0; + (void) strcpy(lclptr->chars, GMT); + } else { + if (tzload(name, lclptr) != 0) + if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0) + (void) gmtload(lclptr); + } + lcl_is_set = TRUE; + settzname(lclptr); +} + +void tzset() +{ + pthread_mutex_lock(&lcl_mutex); + tzset_basic(); + pthread_mutex_unlock(&lcl_mutex); +} + +static void tzsetwall_basic() +{ + if (tzload((char *) NULL, lclptr) != 0) + gmtload(lclptr); + settzname(lclptr); + lcl_is_set = TRUE; +} + +void tzsetwall() +{ + pthread_mutex_lock(&lcl_mutex); + tzsetwall_basic(); + pthread_mutex_unlock(&lcl_mutex); +} + +/* +** The easy way to behave "as if no library function calls" localtime +** is to not call it--so we drop its guts into "localsub", which can be +** freely called. (And no, the PANS doesn't require the above behavior-- +** but it *is* desirable.) +** +** The unused offset argument is for the benefit of mktime variants. +*/ + +static void localsub(const time_t * timep, long offset, struct tm * tmp) +{ + const struct ttinfo * ttisp; + const time_t t = *timep; + struct state * sp; + int i; + + if (!lcl_is_set) + tzset_basic(); + sp = lclptr; + if (sp->timecnt == 0 || t < sp->ats[0]) { + i = 0; + while (sp->ttis[i].tt_isdst) + if (++i >= sp->typecnt) { + i = 0; + break; + } + } else { + for (i = 1; i < sp->timecnt; ++i) + if (t < sp->ats[i]) + break; + i = sp->types[i - 1]; + } + ttisp = &sp->ttis[i]; + /* + ** To get (wrong) behavior that's compatible with System V Release 2.0 + ** you'd replace the statement below with + ** t += ttisp->tt_gmtoff; + ** timesub(&t, 0L, sp, tmp); + */ + timesub(&t, ttisp->tt_gmtoff, sp, tmp); + tzname[tmp->tm_isdst] = (char *) &sp->chars[ttisp->tt_abbrind]; +#ifdef BSD_TM + tmp->tm_zone = &sp->chars[ttisp->tt_abbrind]; +#endif + tmp->tm_isdst = ttisp->tt_isdst; + + pthread_mutex_unlock(&lcl_mutex); +} + +struct tm * localtime_r(const time_t * timep, struct tm * tm) +{ + pthread_mutex_lock(&lcl_mutex); + localsub(timep, 0L, tm); + pthread_mutex_unlock(&lcl_mutex); + return(tm); +} + +struct tm * localtime(const time_t * timep) +{ + static pthread_mutex_t localtime_mutex = PTHREAD_MUTEX_INITIALIZER; + static pthread_key_t localtime_key = -1; + struct tm * tm; + + pthread_mutex_lock(&localtime_mutex); + if (localtime_key < 0) { + if (pthread_key_create(&localtime_key, free) < 0) { + pthread_mutex_unlock(&localtime_mutex); + return(NULL); + } + } + pthread_mutex_unlock(&localtime_mutex); + if ((tm = pthread_getspecific(localtime_key)) == NULL) { + if ((tm = (struct tm *)malloc(sizeof(struct tm))) == NULL) { + return(NULL); + } + pthread_setspecific(localtime_key, tm); + } + + pthread_mutex_lock(&lcl_mutex); + localsub(timep, 0L, tm); + pthread_mutex_unlock(&lcl_mutex); + return tm; +} + + +/* + * gmtsub is to gmtime as localsub is to localtime. + * + * Once set there is no need to lock the gmt_mutex to view gmtptr + */ +static void gmtsub(const time_t * timep, long offset, struct tm * tmp) +{ + pthread_mutex_lock(&gmt_mutex); + if (gmt_is_set == FALSE) { + gmt_is_set = TRUE; + gmtload(gmtptr); + } + pthread_mutex_unlock(&gmt_mutex); + + timesub(timep, offset, gmtptr, tmp); + /* + ** Could get fancy here and deliver something such as + ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero, + ** but this is no time for a treasure hunt. + */ +#ifdef BSD_TM + if (offset != 0) { + tmp->tm_zone = WILDABBR; + } else { + tmp->tm_zone = gmtptr->chars; + } +#endif +} + +struct tm * gmtime_r(const time_t * timep, struct tm * tm) +{ + gmtsub(timep, 0L, tm); + return(tm); +} + +struct tm * gmtime(const time_t * timep) +{ + static pthread_mutex_t gmtime_mutex = PTHREAD_MUTEX_INITIALIZER; + static pthread_key_t gmtime_key = -1; + struct tm * tm; + + pthread_mutex_lock(&gmtime_mutex); + if (gmtime_key < 0) { + if (pthread_key_create(&gmtime_key, free) < 0) { + pthread_mutex_unlock(&gmtime_mutex); + return(NULL); + } + } + pthread_mutex_unlock(&gmtime_mutex); + if ((tm = pthread_getspecific(gmtime_key)) == NULL) { + if ((tm = (struct tm *)malloc(sizeof(struct tm))) == NULL) { + return(NULL); + } + pthread_setspecific(gmtime_key, tm); + } + + gmtsub(timep, 0L, tm); + return(tm); +} + +static void timesub(const time_t * timep, long offset, + const struct state * sp, struct tm * tmp) +{ + register const struct lsinfo * lp; + register long days; + register long rem; + register int y; + register int yleap; + register const int * ip; + register long corr; + register int hit; + register int i; + + corr = 0; + hit = FALSE; + i = sp->leapcnt; + while (--i >= 0) { + lp = &sp->lsis[i]; + if (*timep >= lp->ls_trans) { + if (*timep == lp->ls_trans) + hit = ((i == 0 && lp->ls_corr > 0) || + lp->ls_corr > sp->lsis[i - 1].ls_corr); + corr = lp->ls_corr; + break; + } + } + days = *timep / SECSPERDAY; + rem = *timep % SECSPERDAY; +#ifdef mc68k + if (*timep == 0x80000000) { + /* + ** A 3B1 muffs the division on the most negative number. + */ + days = -24855; + rem = -11648; + } +#endif /* mc68k */ + rem += (offset - corr); + while (rem < 0) { + rem += SECSPERDAY; + --days; + } + while (rem >= SECSPERDAY) { + rem -= SECSPERDAY; + ++days; + } + tmp->tm_hour = (int) (rem / SECSPERHOUR); + rem = rem % SECSPERHOUR; + tmp->tm_min = (int) (rem / SECSPERMIN); + tmp->tm_sec = (int) (rem % SECSPERMIN); + if (hit) + /* + ** A positive leap second requires a special + ** representation. This uses "... ??:59:60". + */ + ++(tmp->tm_sec); + tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK); + if (tmp->tm_wday < 0) + tmp->tm_wday += DAYSPERWEEK; + y = EPOCH_YEAR; + if (days >= 0) + for ( ; ; ) { + yleap = isleap(y); + if (days < (long) year_lengths[yleap]) + break; + ++y; + days = days - (long) year_lengths[yleap]; + } + else do { + --y; + yleap = isleap(y); + days = days + (long) year_lengths[yleap]; + } while (days < 0); + tmp->tm_year = y - TM_YEAR_BASE; + tmp->tm_yday = (int) days; + ip = mon_lengths[yleap]; + for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon)) + days = days - (long) ip[tmp->tm_mon]; + tmp->tm_mday = (int) (days + 1); + tmp->tm_isdst = 0; +#ifdef BSD_TM + tmp->tm_gmtoff = offset; +#endif +} + +/* + * A la X3J11 + * + * Made thread safe by using thread specific data + */ +char * asctime_r(const struct tm * timeptr, char * result) +{ + static const char wday_name[DAYSPERWEEK][3] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" + }; + static const char mon_name[MONSPERYEAR][3] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; + (void) sprintf(result, "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %d\n", + wday_name[timeptr->tm_wday], + mon_name[timeptr->tm_mon], + timeptr->tm_mday, timeptr->tm_hour, + timeptr->tm_min, timeptr->tm_sec, + TM_YEAR_BASE + timeptr->tm_year); + return(result); +} + +char * asctime(const struct tm * timeptr) +{ + static pthread_mutex_t asctime_mutex = PTHREAD_MUTEX_INITIALIZER; + static pthread_key_t asctime_key = -1; + char * result; + + pthread_mutex_lock(&asctime_mutex); + if (asctime_key < 0) { + if (pthread_key_create(&asctime_key, free) < 0) { + pthread_mutex_unlock(&asctime_mutex); + return(NULL); + } + } + pthread_mutex_unlock(&asctime_mutex); + if ((result = pthread_getspecific(asctime_key)) == NULL) { + if ((result = malloc(26)) == NULL) { + return(NULL); + } + pthread_setspecific(asctime_key, result); + } + + return(asctime_r(timeptr, result)); +} + +char * ctime_r(const time_t * timep, char * buf) +{ + struct tm tm; + return asctime_r(localtime_r(timep, &tm), buf); +} + +char * ctime(const time_t * timep) +{ + struct tm tm; + return asctime(localtime_r(timep, &tm)); +} + +/* +** Adapted from code provided by Robert Elz, who writes: +** The "best" way to do mktime I think is based on an idea of Bob +** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now). +** It does a binary search of the time_t space. Since time_t's are +** just 32 bits, its a max of 32 iterations (even at 64 bits it +** would still be very reasonable). +*/ +static void normalize(int * tensptr,int * unitsptr, int base) +{ + if (*unitsptr >= base) { + *tensptr += *unitsptr / base; + *unitsptr %= base; + } else if (*unitsptr < 0) { + --*tensptr; + *unitsptr += base; + if (*unitsptr < 0) { + *tensptr -= 1 + (-*unitsptr) / base; + *unitsptr = base - (-*unitsptr) % base; + } + } +} + +static int tmcomp(const struct tm * atmp, const struct tm * btmp) +{ + register int result; + + if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && + (result = (atmp->tm_mon - btmp->tm_mon)) == 0 && + (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && + (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && + (result = (atmp->tm_min - btmp->tm_min)) == 0) + result = atmp->tm_sec - btmp->tm_sec; + return result; +} + +static time_t time2(struct tm * tmp, long offset, int * okayp) +{ + register const struct state * sp; + register int dir; + register int bits; + register int i, j ; + register int saved_seconds; + time_t newt; + time_t t; + struct tm yourtm, mytm; + + *okayp = FALSE; + yourtm = *tmp; + if (yourtm.tm_sec >= SECSPERMIN + 2 || yourtm.tm_sec < 0) + normalize(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN); + normalize(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR); + normalize(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY); + normalize(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR); + while (yourtm.tm_mday <= 0) { + --yourtm.tm_year; + yourtm.tm_mday += + year_lengths[isleap(yourtm.tm_year + TM_YEAR_BASE)]; + } + for ( ; ; ) { + i = mon_lengths[isleap(yourtm.tm_year + + TM_YEAR_BASE)][yourtm.tm_mon]; + if (yourtm.tm_mday <= i) + break; + yourtm.tm_mday -= i; + if (++yourtm.tm_mon >= MONSPERYEAR) { + yourtm.tm_mon = 0; + ++yourtm.tm_year; + } + } + saved_seconds = yourtm.tm_sec; + yourtm.tm_sec = 0; + /* + ** Calculate the number of magnitude bits in a time_t + ** (this works regardless of whether time_t is + ** signed or unsigned, though lint complains if unsigned). + */ + for (bits = 0, t = 1; t > 0; ++bits, t <<= 1) + ; + /* + ** If time_t is signed, then 0 is the median value, + ** if time_t is unsigned, then 1 << bits is median. + */ + t = (t < 0) ? 0 : ((time_t) 1 << bits); + for ( ; ; ) { + localsub(&t, offset, &mytm); + dir = tmcomp(&mytm, &yourtm); + if (dir != 0) { + if (bits-- < 0) + return NOTOK; + if (bits < 0) + --t; + else if (dir > 0) + t -= (time_t) 1 << bits; + else t += (time_t) 1 << bits; + continue; + } + if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) + break; + /* + ** Right time, wrong type. + ** Hunt for right time, right type. + ** It's okay to guess wrong since the guess + ** gets checked. + */ + sp = lclptr; + for (i = 0; i < sp->typecnt; ++i) { + if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) + continue; + for (j = 0; j < sp->typecnt; ++j) { + if (sp->ttis[j].tt_isdst == yourtm.tm_isdst) + continue; + newt = t + sp->ttis[j].tt_gmtoff - + sp->ttis[i].tt_gmtoff; + localsub(&newt, offset, &mytm); + if (tmcomp(&mytm, &yourtm) != 0) + continue; + if (mytm.tm_isdst != yourtm.tm_isdst) + continue; + /* + ** We have a match. + */ + t = newt; + goto label; + } + } + return NOTOK; + } +label: + t += saved_seconds; + localsub(&t, offset, tmp); + *okayp = TRUE; + return t; +} + +static time_t time1(struct tm * tmp, long offset) +{ + const struct state * sp; + int samei, otheri, okay; + time_t t; + + if (tmp->tm_isdst > 1) + tmp->tm_isdst = 1; + t = time2(tmp, offset, &okay); + if (okay || tmp->tm_isdst < 0) + return t; + /* + ** We're supposed to assume that somebody took a time of one type + ** and did some math on it that yielded a "struct tm" that's bad. + ** We try to divine the type they started from and adjust to the + ** type they need. + */ + sp = lclptr; + for (samei = 0; samei < sp->typecnt; ++samei) { + if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) + continue; + for (otheri = 0; otheri < sp->typecnt; ++otheri) { + if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst) + continue; + tmp->tm_sec += sp->ttis[otheri].tt_gmtoff - + sp->ttis[samei].tt_gmtoff; + tmp->tm_isdst = !tmp->tm_isdst; + t = time2(tmp, offset, &okay); + if (okay) + return t; + tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff - + sp->ttis[samei].tt_gmtoff; + tmp->tm_isdst = !tmp->tm_isdst; + } + } + return NOTOK; +} + +time_t mktime(struct tm * tmp) +{ + time_t mktime_return_value; + + pthread_mutex_lock(&lcl_mutex); + if (lcl_is_set == FALSE) { + tzset_basic(); + } + mktime_return_value = time1(tmp, 0L); + pthread_mutex_unlock(&lcl_mutex); + return(mktime_return_value); +} diff --git a/mit-pthreads/gen/difftime.c b/mit-pthreads/gen/difftime.c new file mode 100644 index 00000000000..cddd896e04a --- /dev/null +++ b/mit-pthreads/gen/difftime.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)difftime.c 5.2 (Berkeley) 6/1/90"; +#endif /* LIBC_SCCS and not lint */ + +#include <pthread.h> +#include <sys/types.h> + +double +difftime(time1, time0) + time_t time1, time0; +{ + return(time1 - time0); +} diff --git a/mit-pthreads/gen/directory.c b/mit-pthreads/gen/directory.c new file mode 100644 index 00000000000..d189280fc1f --- /dev/null +++ b/mit-pthreads/gen/directory.c @@ -0,0 +1,322 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)closedir.c 5.9 (Berkeley) 2/23/91"; +#endif /* LIBC_SCCS and not lint */ + +/* + * One of these structures is malloced to describe the current directory + * position each time telldir is called. It records the current magic + * cookie returned by getdirentries and the offset within the buffer + * associated with that return value. + */ +struct ddloc { + struct ddloc *loc_next;/* next structure in list */ + long loc_index; /* key associated with structure */ + long loc_seek; /* magic cookie returned by getdirentries */ + long loc_loc; /* offset of entry in buffer */ +}; + +static long dd_loccnt = 0; /* Index of entry for sequential telldir's */ + +#include <errno.h> +#include <pthread.h> +#include <sys/types.h> +#include <sys/param.h> +#include <dirent.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> + + +/* + * close a directory. + */ +int closedir(DIR * dirp) +{ + void *ptr, *nextptr; + int fd; + + pthread_mutex_lock (dirp->dd_lock); + fd = dirp->dd_fd; + dirp->dd_fd = -1; + dirp->dd_loc = 0; + for (ptr = (void *)dirp->dd_ddloc; ptr; ptr = nextptr) { + nextptr = (void *)(((struct ddloc *)ptr)->loc_next); + free(ptr); + } + for (ptr = (void *)dirp->dd_dp; ptr; ptr = nextptr) { + nextptr = (void *)(((struct __dirent *)ptr)->next); + free(ptr); + } + free((void *)dirp->dd_buf); + free (dirp->dd_lock); + free((void *)dirp); + return(machdep_sys_close(fd)); +} + +/* + * open a directory. + */ +DIR * opendir(const char * name) +{ + DIR *dirp; + int fd; + + if ((fd = machdep_sys_open(name, 0)) < 0) + return NULL; + if (machdep_sys_fcntl(fd, F_SETFD, 1) < 0 || + (dirp = (DIR *)malloc(sizeof(DIR))) == NULL) { + machdep_sys_close (fd); + return NULL; + } + dirp->dd_lock = (pthread_mutex_t*) malloc (sizeof (pthread_mutex_t)); + pthread_mutex_init (dirp->dd_lock, 0); + /* + * If CLSIZE is an exact multiple of DIRBLKSIZ, use a CLSIZE + * buffer that it cluster boundary aligned. + * Hopefully this can be a big win someday by allowing page trades + * to user space to be done by getdirentries() + */ +#ifndef CLSIZE +#define CLSIZE 1 +#endif + if ((CLSIZE % DIRBLKSIZ) == 0) { + dirp->dd_buf = malloc(CLSIZE); + dirp->dd_len = CLSIZE; + } else { + dirp->dd_buf = malloc(DIRBLKSIZ); + dirp->dd_len = DIRBLKSIZ; + } + if (dirp->dd_buf == NULL) { + machdep_sys_close (fd); + free((void *)dirp); + return NULL; + } + + dirp->dd_ddloc = NULL; + dirp->dd_dp = NULL; + dirp->dd_seek = 0; + dirp->dd_loc = 0; + dirp->dd_fd = fd; + return(dirp); +} + +/* + * The real work in gettint the next entry in a directory. + * Return + * NULL on End of directory + * &ERR on Error + * dp on valid directory; + */ +static struct dirent ERR; +static struct dirent * readdir_basic(DIR * dirp) +{ + register struct dirent *dp; + + for (;;) { + if (dirp->dd_loc == 0) { + dirp->dd_size = machdep_sys_getdirentries(dirp->dd_fd, + dirp->dd_buf, dirp->dd_len, &dirp->dd_seek); + if (dirp->dd_size < 0) + return(&ERR); + if (dirp->dd_size == 0) + return(NULL); + } + if (dirp->dd_loc >= dirp->dd_size) { + dirp->dd_loc = 0; + continue; + } + dp = (struct dirent *)(dirp->dd_buf + dirp->dd_loc); + if ((long)dp & 03) /* bogus pointer check */ + return(&ERR); + if (dp->d_reclen <= 0 || + dp->d_reclen > dirp->dd_len + 1 - dirp->dd_loc) + return(&ERR); + dirp->dd_loc += dp->d_reclen; + if (dp->d_ino == 0) + continue; + return(dp); + } +} + +/* + * POSIX.1 version of getting the next entry in a directory. + */ +struct dirent * readdir(DIR * dirp) +{ + register struct dirent * rp; + struct __dirent * my__dp; + pthread_t self; + + pthread_mutex_lock (dirp->dd_lock); + + self = pthread_self(); + /* Allocate space and return */ + for (my__dp = dirp->dd_dp; my__dp; my__dp = my__dp->next) { + if (pthread_equal(my__dp->owner, self)) { + break; + } + } + if (my__dp == NULL) { + if (my__dp = (struct __dirent *)(malloc(sizeof(struct __dirent)))) { + my__dp->next = dirp->dd_dp; + dirp->dd_dp = my__dp; + my__dp->owner = self; + } else { + pthread_mutex_unlock (dirp->dd_lock); + return(NULL); + } + } + if (rp = readdir_basic(dirp)) { + if (rp != &ERR) { + memcpy(& (my__dp->data), rp, sizeof(struct dirent)); + rp = & (my__dp->data); + } else { + rp = NULL; + } + } + pthread_mutex_unlock (dirp->dd_lock); + return(rp); +} + +/* + * POSIX.4a version of getting the next entry in a directory. + */ +int readdir_r(DIR * dirp, struct dirent * entry, struct dirent ** result) +{ + register struct dirent * rp; + int ret; + + pthread_mutex_lock (dirp->dd_lock); + rp = readdir_basic(dirp); + if (rp != &ERR) { + if (rp) { + memcpy(entry, rp, sizeof(struct dirent)); + *result = entry; + ret = 0; + } else { + *result = NULL; + ret = 0; + } + } else { + /* Should get it from errno */ + ret = EBADF; + } + pthread_mutex_unlock (dirp->dd_lock); + return(ret); +} + +void rewinddir(DIR * dirp) +{ + pthread_mutex_lock (dirp->dd_lock); + (void)machdep_sys_lseek(dirp->dd_fd, 0, 0); + dirp->dd_seek = 0; + dirp->dd_loc = 0; + pthread_mutex_unlock (dirp->dd_lock); +} + +/* + * Seek to an entry in a directory. + * _seekdir is in telldir.c so that it can share opaque data structures. + * + * Use the POSIX reentrant safe readdir_r to simplify varifying POSIX + * thread-safe compliance. + */ +void seekdir(DIR * dirp, long loc) +{ + register struct ddloc ** prevlp; + register struct ddloc * lp; + struct dirent * dp; + struct dirent de; + + pthread_mutex_lock (dirp->dd_lock); + prevlp = (struct ddloc **)&(dirp->dd_ddloc); + lp = *prevlp; + while (lp != NULL) { + if (lp->loc_index == loc) + break; + prevlp = &lp->loc_next; + lp = lp->loc_next; + } + if (lp) { + if (lp->loc_seek != dirp->dd_seek) { + if (machdep_sys_lseek(dirp->dd_fd, lp->loc_seek, 0) < 0) { + *prevlp = lp->loc_next; + pthread_mutex_unlock (dirp->dd_lock); + return; + } + dirp->dd_seek = lp->loc_seek; + dirp->dd_loc = 0; + while (dirp->dd_loc < lp->loc_loc) { + if (readdir_r(dirp, &de, &dp)) { + *prevlp = lp->loc_next; + break; + } + } + } + } + pthread_mutex_unlock (dirp->dd_lock); +} + +/* + * return a pointer into a directory + */ +long telldir(DIR *dirp) +{ + struct ddloc *lp, **fakeout; + int ret; + + pthread_mutex_lock (dirp->dd_lock); + if (lp = (struct ddloc *)malloc(sizeof(struct ddloc))) { + lp->loc_index = dd_loccnt++; + lp->loc_seek = dirp->dd_seek; + lp->loc_loc = dirp->dd_loc; + lp->loc_next = dirp->dd_ddloc; + + /* Compiler won't let us change anything pointed to by db directly */ + /* So we fake to the left and do it anyway */ + /* Wonder if the compile optomizes it to the correct solution */ + fakeout = (struct ddloc **)&(dirp->dd_ddloc); + *fakeout = lp; + + ret = lp->loc_index; + } else { + ret = -1; + } + pthread_mutex_unlock (dirp->dd_lock); + return(ret); +} + diff --git a/mit-pthreads/gen/eprintf.c b/mit-pthreads/gen/eprintf.c new file mode 100644 index 00000000000..bcc65757bd4 --- /dev/null +++ b/mit-pthreads/gen/eprintf.c @@ -0,0 +1,18 @@ +/* This function is a replacement for the version in libgcc.a. This + is needed because typically libgcc.a won't have been compiled + against the threads library, so its references to "stderr" will + come out wrong. */ + +#include <stdio.h> + +void __eprintf (const char *fmt, const char *expr, int line, const char *file) +{ + /* Considering the very special circumstances where this function + would be called, perhaps we might want to disable the thread + scheduler and break any existing locks on stderr? Well, maybe if + we could be sure that stderr was in a useable state... */ + fprintf (stderr, fmt, expr, line, file); + fflush (stderr); + + abort (); +} diff --git a/mit-pthreads/gen/getcwd.c b/mit-pthreads/gen/getcwd.c new file mode 100644 index 00000000000..9c1b089f26e --- /dev/null +++ b/mit-pthreads/gen/getcwd.c @@ -0,0 +1,248 @@ +/* + * Copyright (c) 1989, 1991 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +/*static char *sccsid = "from: @(#)getcwd.c 5.11 (Berkeley) 2/24/91";*/ +static char *rcsid = "$Id$"; +#endif /* LIBC_SCCS and not lint */ + +#include <pthread.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <errno.h> +#include <dirent.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#define ISDOT(dp) \ + (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \ + dp->d_name[1] == '.' && dp->d_name[2] == '\0')) + + +/* Only use reentrant safe routines to simplify varifying POSIX thread-safe + * compliance. (mevans). + */ + +char * +getcwd(pt, size) + char *pt; + size_t size; +{ + register DIR *dir; + register dev_t dev; + register ino_t ino; + register int first; + register char *bpt, *bup; + struct stat s; + struct dirent *dp; + struct dirent de; + dev_t root_dev; + ino_t root_ino; + size_t ptsize, upsize; + int save_errno; + char *ept, *eup, *up; + int namelen; + + /* + * If no buffer specified by the user, allocate one as necessary. + * If a buffer is specified, the size has to be non-zero. The path + * is built from the end of the buffer backwards. + */ + if (pt) { + ptsize = 0; + if (!size) { + errno = EINVAL; + return((char *)NULL); + } + ept = pt + size; + } else { + if (!(pt = (char *)malloc(ptsize = 1024 - 4))) + return((char *)NULL); + ept = pt + ptsize; + } + bpt = ept - 1; + *bpt = '\0'; + + /* + * Allocate bytes (1024 - malloc space) for the string of "../"'s. + * Should always be enough (it's 340 levels). If it's not, allocate + * as necessary. Special * case the first stat, it's ".", not "..". + */ + if (!(up = (char *)malloc(upsize = 1024 - 4))) + goto err; + eup = up + MAXPATHLEN; + bup = up; + up[0] = '.'; + up[1] = '\0'; + + /* Save root values, so know when to stop. */ + if (stat("/", &s)) + goto err; + root_dev = s.st_dev; + root_ino = s.st_ino; + + SET_ERRNO(0); + + for (first = 1;; first = 0) { + /* Stat the current level. */ + if (lstat(up, &s)) + goto err; + + /* Save current node values. */ + ino = s.st_ino; + dev = s.st_dev; + + /* Check for reaching root. */ + if (root_dev == dev && root_ino == ino) { + *--bpt = '/'; + /* + * It's unclear that it's a requirement to copy the + * path to the beginning of the buffer, but it's always + * been that way and stuff would probably break. + */ + /* XXX was bcopy */ + (void)memcpy(pt, bpt, ept - bpt); + free(up); + return(pt); + } + + /* + * Build pointer to the parent directory, allocating memory + * as necessary. Max length is 3 for "../", the largest + * possible component name, plus a trailing NULL. + */ + if (bup + 3 + MAXNAMLEN + 1 >= eup) { + if (!(up = (char *)realloc(up, upsize *= 2))) + goto err; + eup = up + upsize; + } + *bup++ = '.'; + *bup++ = '.'; + *bup = '\0'; + + /* Open and stat parent directory. */ + /* XXX opendir() returns kernel fd's instead of + pthread fd's for some odd reason, so we must + break the abstraction boundry here as well or + fix everything in opendir et al. SNL */ + if (!(dir = opendir(up)) || + machdep_sys_fstat(dirfd(dir), &s)) + goto err; + + /* Add trailing slash for next directory. */ + *bup++ = '/'; + + /* + * If it's a mount point, have to stat each element because + * the inode number in the directory is for the entry in the + * parent directory, not the inode number of the mounted file. + */ + save_errno = 0; + if (s.st_dev == dev) { + for (;;) { + if (readdir_r(dir, &de, &dp)) + goto notfound; + if (dp->d_fileno == ino) + break; + } + } else + for (;;) { + if (readdir_r(dir, &de, &dp)) + goto notfound; + if (ISDOT(dp)) + continue; + memcpy(bup, dp->d_name, strlen(dp->d_name) + 1); + + /* Save the first error for later. */ + if (lstat(up, &s)) { + if (!save_errno) + save_errno = errno; + SET_ERRNO(0); + continue; + } + if (s.st_dev == dev && s.st_ino == ino) + break; + } + + /* + * Check for length of the current name, preceding slash, + * leading slash. + */ + namelen = strlen(dp->d_name); + if (bpt - pt <= namelen + (first ? 1 : 2)) { + size_t len, off; + + if (!ptsize) { + SET_ERRNO(ERANGE); + goto err; + } + off = bpt - pt; + len = ept - bpt; + if (!(pt = (char *)realloc(pt, ptsize *= 2))) + goto err; + bpt = pt + off; + ept = pt + ptsize; + /* XXX was bcopy */ + (void)memcpy(ept - len, bpt, len); + bpt = ept - len; + } + if (!first) + *--bpt = '/'; + bpt -= namelen; + memcpy(bpt, dp->d_name, namelen); + (void)closedir(dir); + + /* Truncate any file name. */ + *bup = '\0'; + } + +notfound: + /* + * If readdir set errno, use it, not any saved error; otherwise, + * didn't find the current directory in its parent directory, set + * errno to ENOENT. + */ + if (!errno) { + if (!save_errno) + save_errno = ENOENT; + SET_ERRNO(save_errno); + } + /* FALLTHROUGH */ +err: + if (ptsize) + free(pt); + free(up); + return((char *)NULL); +} diff --git a/mit-pthreads/gen/getpwent.c b/mit-pthreads/gen/getpwent.c new file mode 100644 index 00000000000..7bcb2cbd610 --- /dev/null +++ b/mit-pthreads/gen/getpwent.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 1984 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getpwent.c 5.2 (Berkeley) 3/9/86"; +#endif + +#include <pthread.h> +#include <stdio.h> +#include <pwd.h> +#include "pwd_internal.h" + +void +setpwent() +{ + pwf_context_t *_data; + + _data = _pw_get_data(); + + if (_data) { + if (_data->pwf == NULL) + _data->pwf = fopen(_data->pw_file, "r"); + else + rewind(_data->pwf); + } +} + +void +endpwent() +{ + pwf_context_t *_data; + + _data = _pw_get_data(); + + if (_data) { + if (_data->pwf != NULL) { + fclose(_data->pwf); + _data->pwf = NULL; + } +#ifdef DBM_PWD_SUPPORT + if (_data->pw_db != (DBM *)0) { + dbm_close(_data->pw_db); + _data->pw_db = (DBM *)0; + _data->pw_stayopen = 0; + } +#endif /* DBM_PWD_SUPPORT */ + } +} + +static char * +pwskip(p) + char *p; +{ + while (*p && *p != ':' && *p != '\n') + ++p; + if (*p) + *p++ = 0; + return(p); +} + +struct passwd * +getpwent() +{ + pwf_context_t *_data; + char *p; + + _data = _pw_get_data(); + if (!_data) + return 0; + + if (_data->pwf == NULL) { + if ((_data->pwf = fopen(_data->pw_file, "r" )) == NULL) + return(0); + } + p = fgets(_data->line, BUFSIZ, _data->pwf); + if (p == NULL) + return(0); + _data->passwd.pw_name = p; + p = pwskip(p); + _data->passwd.pw_passwd = p; + p = pwskip(p); + _data->passwd.pw_uid = atoi(p); + p = pwskip(p); + _data->passwd.pw_gid = atoi(p); + p = pwskip(p); + _data->passwd.pw_gecos = p; + p = pwskip(p); + _data->passwd.pw_dir = p; + p = pwskip(p); + _data->passwd.pw_shell = p; + while (*p && *p != '\n') + p++; + *p = '\0'; + return(&_data->passwd); +} + +void +setpwfile(file) + char *file; +{ + pwf_context_t *_data; + + _data = _pw_get_data(); + if (_data) + _data->pw_file = file; +} diff --git a/mit-pthreads/gen/getpwnamuid.c b/mit-pthreads/gen/getpwnamuid.c new file mode 100644 index 00000000000..0e87081b7a9 --- /dev/null +++ b/mit-pthreads/gen/getpwnamuid.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getpwnamuid.c 5.3 (Berkeley) 12/21/87"; +#endif + +#include <stdio.h> +#include <pwd.h> +#include <sys/file.h> +#include "pwd_internal.h" + +/* + * The following are shared with getpwent.c + */ + +#ifdef DBM_PWD_SUPPORT +static struct passwd * +fetchpw(key) + datum key; +{ + char *cp, *tp; + pwf_context_t *_data; + + _data = _pw_get_data(); + if (!_data) + return 0; + if (key.dptr == 0) + return ((struct passwd *)NULL); + key = dbm_fetch(_data->pw_db, key); + if (key.dptr == 0) + return ((struct passwd *)NULL); + cp = key.dptr; + tp = _data->line; + +#define EXPAND(e) _data->passwd.e = tp; while (*tp++ = *cp++); + EXPAND(pw_name); + EXPAND(pw_passwd); + memcpy((char *)&_data->passwd.pw_uid, cp, sizeof (int)); + cp += sizeof (int); + memcpy((char *)&_data->passwd.pw_gid, cp, sizeof (int)); + cp += sizeof (int); + EXPAND(pw_gecos); + EXPAND(pw_dir); + EXPAND(pw_shell); + return (&_data->passwd); +} +#endif /* DBM_PWD_SUPPORT */ + +struct passwd * +getpwnam(nam) + const char *nam; +{ +#ifdef DBM_PWD_SUPPORT + datum key; +#endif + struct passwd *pw, *getpwent(); + pwf_context_t *_data; + + _data = _pw_get_data(); + if (!_data) + return 0; + +#ifdef DBM_PWD_SUPPORT + if (_data->pw_db == (DBM *)0 && + (_data->pw_db = dbm_open(_data->pw_file, O_RDONLY)) == (DBM *)0) { + oldcode: +#endif + setpwent(); + while ((pw = getpwent()) && strcmp(nam, pw->pw_name)) + ; + if (!_data->pw_stayopen) + endpwent(); + return (pw); +#ifdef DBM_PWD_SUPPORT + } + if (flock(dbm_dirfno(_data->pw_db), LOCK_SH) < 0) { + dbm_close(_data->pw_db); + _data->pw_db = (DBM *)0; + goto oldcode; + } + key.dptr = nam; + key.dsize = strlen(nam); + pw = fetchpw(key); + (void) flock(dbm_dirfno(_data->pw_db), LOCK_UN); + if (!_data->pw_stayopen) { + dbm_close(_data->pw_db); + _data->pw_db = (DBM *)0; + } + return (pw); +#endif +} + +struct passwd * +getpwuid(uid) + uid_t uid; +{ +#ifdef DBM_PWD_SUPPORT + datum key; +#endif + struct passwd *pw, *getpwent(); + pwf_context_t *_data; + + _data = _pw_get_data(); + if (!_data) + return 0; +#ifdef DBM_PWD_SUPPORT + if (_data->pw_db == (DBM *)0 && + (_data->pw_db = dbm_open(_data->pw_file, O_RDONLY)) == (DBM *)0) { + oldcode: +#endif + setpwent(); + while ((pw = getpwent()) && pw->pw_uid != uid) + ; + if (!_data->pw_stayopen) + endpwent(); + return (pw); +#ifdef DBM_PWD_SUPPORT + } + if (flock(dbm_dirfno(_data->pw_db), LOCK_SH) < 0) { + dbm_close(_data->pw_db); + _data->pw_db = (DBM *)0; + goto oldcode; + } + key.dptr = (char *) &uid; + key.dsize = sizeof uid; + pw = fetchpw(key); + (void) flock(dbm_dirfno(_data->pw_db), LOCK_UN); + if (!_data->pw_stayopen) { + dbm_close(_data->pw_db); + _data->pw_db = (DBM *)0; + } + return (pw); +#endif +} diff --git a/mit-pthreads/gen/getwd.c b/mit-pthreads/gen/getwd.c new file mode 100644 index 00000000000..7fdceda0f45 --- /dev/null +++ b/mit-pthreads/gen/getwd.c @@ -0,0 +1,57 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +/*static char *sccsid = "from: @(#)getwd.c 5.1 (Berkeley) 2/20/91";*/ +static char *rcsid = "$Id$"; +#endif /* LIBC_SCCS and not lint */ + +#include <pthread.h> +#include <sys/param.h> +#include <unistd.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> + +char * +getwd(buf) + char *buf; +{ + char *p; + char *strerror(); + + if (p = getcwd(buf, MAXPATHLEN)) + return(p); + (void)strcpy(buf, strerror(errno)); + return((char *)NULL); +} diff --git a/mit-pthreads/gen/isatty.c b/mit-pthreads/gen/isatty.c new file mode 100644 index 00000000000..a22f13015d9 --- /dev/null +++ b/mit-pthreads/gen/isatty.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 1988 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +/*static char *sccsid = "from: @(#)isatty.c 5.6 (Berkeley) 2/23/91";*/ +static char *rcsid = "$Id$"; +#endif /* LIBC_SCCS and not lint */ + +#include <pthread.h> +#ifdef sunos4 +#include <sys/termio.h> +#else +#include <termios.h> +#endif +#include <unistd.h> + +/* + * If TIOCGETA is not defined try TCGETATTR + * If TCGETATTR is not defined try TCGETA + * If that doesn't work try getting it from termio.h + */ +#ifndef TIOCGETA +#ifdef TCGETATTR +#define TIOCGETA TCGETATTR +#else +#ifndef TCGETA +#include <termio.h> +#endif +#ifndef TIOCGETA +#define TIOCGETA TCGETA +#endif +#endif +#endif + +/* fd is the real fd to pass to the kernel */ +int isatty_basic(int fd) +{ +#ifdef sunos4 + struct termio t; +#else /* !sunos4 */ + struct termios t; +#endif /* sunos4 */ + return (machdep_sys_ioctl(fd, +#ifdef sunos4 + TCGETA, +#else /* !sunos4 */ + TIOCGETA, +#endif /* sunos4 */ + &t) ? 0 : 1); +} + +int isatty(int fd) +{ + int ret; + + if ((ret = fd_lock(fd, FD_READ, NULL)) == OK) { + ret = isatty_basic(fd_table[fd]->fd.i); + fd_unlock(fd, FD_READ); + } else { + /* Return 0 or 1 */ + ret = 0; + } + return(ret); +} + diff --git a/mit-pthreads/gen/popen.c b/mit-pthreads/gen/popen.c new file mode 100644 index 00000000000..c15fbdce1fe --- /dev/null +++ b/mit-pthreads/gen/popen.c @@ -0,0 +1,117 @@ +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/wait.h> + +static pid_t *pids = NULL; +static int pids_size = 0; +static int pids_top = 0; +static pthread_mutex_t pids_lock = PTHREAD_MUTEX_INITIALIZER; + +FILE *popen(const char *cmd, const char *mode) +{ + int fds[2], parent_fd, child_fd, child_target, new_size, i; + pid_t pid, *new_pids; + + /* Verify the mode. */ + if ((*mode != 'r' && *mode != 'w') || mode[1] != 0) + return NULL; + + /* Generate fds, and choose the parent and child fds. */ + if (pipe(fds) < 0) + return NULL; + parent_fd = (*mode == 'r') ? fds[0] : fds[1]; + child_fd = (*mode == 'r') ? fds[1] : fds[0]; + + /* Ensure that there is space in the pid table. */ + pthread_mutex_lock(&pids_lock); + if (pids_size <= parent_fd) { + new_size = parent_fd + 1; + if ((new_pids = malloc(new_size * sizeof(pid_t))) == NULL) { + pthread_mutex_unlock(&pids_lock); + close(parent_fd); + close(child_fd); + return NULL; + } + if (pids) { + memcpy(new_pids, pids, pids_size * sizeof(pid_t)); + free(pids); + } + while (pids_size < new_size) + new_pids[pids_size++] = -1; + pids = new_pids; + } + pthread_mutex_unlock(&pids_lock); + + /* Fork off a child process. */ + switch (pid = fork()) { + case -1: /* Failed to fork. */ + close(parent_fd); + close(child_fd); + return NULL; + break; + case 0: /* Child */ + /* + * Set the child fd to stdout or stdin as appropriate, + * and close the parent fd. + */ + child_target = (*mode == 'r') ? STDOUT_FILENO : STDIN_FILENO; + if (child_fd != child_target) { + dup2(child_fd, child_target); + close(child_fd); + } + close(parent_fd); + + /* Close all parent fds from previous popens(). */ + for (i = 0; i < pids_top; i++) { + if (pids[i] != -1) + close(i); + } + + execl("/bin/sh", "sh", "-c", cmd, NULL); + exit(1); + default: + break; + } + + /* Record the parent fd in the pids table. */ + pthread_mutex_lock(&pids_lock); + pids[parent_fd] = pid; + if (pids_top < parent_fd + 1) + pids_top = parent_fd + 1; + pthread_mutex_unlock(&pids_lock); + + /* Close the child fd and return a stdio buffer for the parent fd. */ + close(child_fd); + return fdopen(parent_fd, mode); +} + +int pclose(fp) + FILE *fp; +{ + pid_t pid, result; + int fd, pstat; + + fd = fileno(fp); + pthread_mutex_lock(&pids_lock); + /* Make sure this is a popened file. */ + if ((pids_top <= fd) || ((pid = pids[fd]) == -1)) { + pthread_mutex_unlock(&pids_lock); + return -1; + } + pids[fd] = -1; + while (pids_top > 0 && pids[pids_top - 1] == -1) + pids_top--; + pthread_mutex_unlock(&pids_lock); + + fclose(fp); + + /* Wait for the subprocess to quit. */ + return (((result = waitpid(pid, &pstat, 0)) == -1) ? -1 : pstat); +} + diff --git a/mit-pthreads/gen/pwd_internal.c b/mit-pthreads/gen/pwd_internal.c new file mode 100644 index 00000000000..b0ebc27b5c6 --- /dev/null +++ b/mit-pthreads/gen/pwd_internal.c @@ -0,0 +1,97 @@ +/* ==== pwd_internal.c ============================================================ + * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Chris Provenzano. + * 4. The name of Chris Provenzano may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Description : Thread-safe password hacking functions. + * + * 1.00 95/02/08 snl + * -Started coding this file. + */ + +#include <pthread.h> +#include <stdlib.h> +#include <stdio.h> +#include <pwd.h> +#include <unistd.h> +#include "pwd_internal.h" + +static pthread_once_t __pw_init = PTHREAD_ONCE_INIT; +static pthread_key_t __pw_key; + +void +_pw_null_cleanup(void *junkola) +{ + pwf_context_t *x = (pwf_context_t *)junkola; + + if (x) { + if (x->pwf) { + fclose(x->pwf); + x->pwf = 0; + } +#ifdef DBM_PWD_SUPPORT + if (x->pw_db) { + dbm_close(x->pw_db); + x->pw_db = 0; + } +#endif /* DBM_PWD_SUPPORT */ + free((void *)x); + } +} + +void +_pw_create_key() +{ + if (pthread_key_create(&__pw_key, _pw_null_cleanup)) { + PANIC(); + } +} + +pwf_context_t * +_pw_get_data() +{ + pwf_context_t *_data; + + pthread_once(&__pw_init, _pw_create_key); + _data = (pwf_context_t *)pthread_getspecific(__pw_key); + if (!_data) { + _data = (pwf_context_t *)malloc(sizeof(pwf_context_t)); + if (_data) { + _data->pwf = 0; + _data->line[0] = '\0'; + _data->pw_stayopen = 0; + _data->pw_file = "/etc/passwd"; +#ifdef DBM_PWD_SUPPORT + _data->pw_db = 0; +#endif /* DBM_PWD_SUPPORT */ + pthread_setspecific(__pw_key, (void *)_data); + } + } + return _data; +} diff --git a/mit-pthreads/gen/pwd_internal.h b/mit-pthreads/gen/pwd_internal.h new file mode 100644 index 00000000000..10fdab6cc4e --- /dev/null +++ b/mit-pthreads/gen/pwd_internal.h @@ -0,0 +1,29 @@ +#ifndef _PWD_INTERNAL_H_ +#define _PWD_INTERNAL_H_ + +#if 0 /* Turn this off for now until we suck in ndbm or use gdbm -- SNL */ +#ifndef DBM_PWD_SUPPORT +#if !defined(__alpha) && !defined(linux) && !defined(hpux) +#define DBM_PWD_SUPPORT 1 +#endif /* !alpha && !linux && !hpux */ +#endif /* !DBM_PWD_SUPPORT */ +#endif + +#ifdef DBM_PWD_SUPPORT +#include <ndbm.h> +#endif /* DBM_PWD_SUPPORT */ + +typedef struct pwf_context { + FILE *pwf; + char line[BUFSIZ+1]; + struct passwd passwd; + int pw_stayopen; + char *pw_file; +#ifdef DBM_PWD_SUPPORT + DBM *pw_db; +#endif /* DBM_PWD_SUPPORT */ +} pwf_context_t; + +pwf_context_t *_pw_get_data __P_((void)); + +#endif /* _PWD_INTERNAL_H_ */ diff --git a/mit-pthreads/gen/syslog.c b/mit-pthreads/gen/syslog.c new file mode 100644 index 00000000000..e49795ecb69 --- /dev/null +++ b/mit-pthreads/gen/syslog.c @@ -0,0 +1,216 @@ +/* + * Copyright (c) 1983, 1988 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and that due credit is given + * to the University of California at Berkeley. The name of the University + * may not be used to endorse or promote products derived from this + * software without specific prior written permission. This software + * is provided ``as is'' without express or implied warranty. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)syslog.c 5.14 (Berkeley) 5/20/88"; +#endif /* LIBC_SCCS and not lint */ + + +/* + * SYSLOG -- print message on log file + * + * This routine looks a lot like printf, except that it + * outputs to the log file instead of the standard output. + * Also: + * adds a timestamp, + * prints the module name in front of the message, + * has some other formatting types (or will sometime), + * adds a newline on the end of the message. + * + * The output of this routine is intended to be read by /etc/syslogd. + * + * Author: Eric Allman + * Modified to use UNIX domain IPC by Ralph Campbell + * Modified for pthreads and made more POSIX-compliant by Greg Hudson + */ + +#include <pthread.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <signal.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <fcntl.h> +#include <netdb.h> +#include <unistd.h> +#include <errno.h> +#include <syslog.h> + +int socket(); +char *strerror(int); /* For systems that don't prototype it */ + +#define MAXLINE 1024 /* max message size */ + +#define PRIFAC(p) (((p) & LOG_FACMASK) >> 3) + /* XXX should be in <syslog.h> */ +#define IMPORTANT LOG_ERR + +static void basic_init(void); + +static char _log_name[] = "/dev/log"; +static char ctty[] = "/dev/console"; + +static int LogFile = -1; /* fd for log */ +static int LogStat = 0; /* status bits, set by openlog() */ +static char *LogTag = "syslog"; /* string to tag the entry with */ +static int LogMask = 0xff; /* mask of priorities to be logged */ +static int LogFacility = LOG_USER; /* default facility code */ + +static pthread_mutex_t basic_init_lock = PTHREAD_MUTEX_INITIALIZER; + +static struct sockaddr SyslogAddr; /* AF_UNIX address of local logger */ + +static void basic_init() +{ + pthread_mutex_lock(&basic_init_lock); + if (LogFile < 0) + openlog(LogTag, LogStat | LOG_NDELAY, 0); + pthread_mutex_unlock(&basic_init_lock); +} + +void syslog(int pri, char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vsyslog(pri, fmt, args); + va_end(args); +} + +void vsyslog(int pri, char *fmt, va_list args) +{ + char buf[MAXLINE + 1], outline[MAXLINE + 1]; + register char *b, *f, *o; + register int c; + time_t now; + int olderrno = errno, fd; + + /* Do a basic initialization if user didn't call openlog(). */ + if (LogFile < 0) + basic_init(); + + /* see if we should just throw out this message */ + if ((unsigned) PRIFAC(pri) >= LOG_NFACILITIES || + (LOG_MASK(pri & LOG_PRIMASK) & LogMask) == 0 || + (pri &~ (LOG_PRIMASK|LOG_FACMASK)) != 0) + return; + + /* set default facility if none specified */ + if ((pri & LOG_FACMASK) == 0) + pri |= LogFacility; + + /* build the message */ + o = outline; + (void)sprintf(o, "<%d>", pri); + o += strlen(o); + time(&now); + (void)sprintf(o, "%.15s ", ctime(&now) + 4); + o += strlen(o); + if (LogTag) { + strcpy(o, LogTag); + o += strlen(o); + } + if (LogStat & LOG_PID) { + (void)sprintf(o, "[%d]", getpid()); + o += strlen(o); + } + if (LogTag) { + strcpy(o, ": "); + o += 2; + } + + b = buf; + f = fmt; + while ((c = *f++) != '\0' && c != '\n' && b < &buf[MAXLINE]) { + char *strerror(); + + if (c != '%') { + *b++ = c; + continue; + } + if ((c = *f++) != 'm') { + *b++ = '%'; + *b++ = c; + continue; + } + strcpy(b, strerror(olderrno)); + b += strlen(b); + } + *b++ = '\n'; + *b = '\0'; + vsprintf(o, buf, args); + c = strlen(outline); + if (c > MAXLINE) + c = MAXLINE; + + /* output the message to the local logger */ + if (sendto(LogFile, outline, c, 0, &SyslogAddr, sizeof SyslogAddr) >= 0) + return; + if (!(LogStat & LOG_CONS)) + return; + + /* output the message to the console */ + fd = open(ctty, O_WRONLY); + alarm(0); + strcat(o, "\r"); + o = strchr(outline, '>') + 1; + write(fd, o, c + 1 - (o - outline)); + close(fd); +} + +/* + * OPENLOG -- open system log + */ + +void openlog(char *ident, int logstat, int logfac) +{ + int flags; + + if (ident != NULL) + LogTag = ident; + LogStat = logstat; + if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0) + LogFacility = logfac; + if (LogFile >= 0) + return; + SyslogAddr.sa_family = AF_UNIX; + strncpy(SyslogAddr.sa_data, _log_name, sizeof SyslogAddr.sa_data); + if (LogStat & LOG_NDELAY) { + LogFile = socket(AF_UNIX, SOCK_DGRAM, 0); + flags = fcntl(LogFile, F_GETFD); + fcntl(LogFile, F_SETFD, flags & O_NONBLOCK); + } +} + +/* + * CLOSELOG -- close the system log + */ + +void closelog() +{ + (void) close(LogFile); + LogFile = -1; +} + +/* + * SETLOGMASK -- set the log mask level + */ +int setlogmask(int pmask) +{ + int omask; + + omask = LogMask; + if (pmask != 0) + LogMask = pmask; + return (omask); +} diff --git a/mit-pthreads/gen/time.c b/mit-pthreads/gen/time.c new file mode 100644 index 00000000000..82eec7edc1e --- /dev/null +++ b/mit-pthreads/gen/time.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)time.c 5.6 (Berkeley) 6/1/90"; +#endif /* LIBC_SCCS and not lint */ + +#include <pthread.h> +#include <sys/types.h> +#include <sys/time.h> + +time_t time(time_t * t) +{ + struct timeval tt; + + if (gettimeofday(&tt, (struct timezone *)0) < 0) + return(-1); + if (t) + *t = tt.tv_sec; + return(tt.tv_sec); +} diff --git a/mit-pthreads/gen/ttyname.c b/mit-pthreads/gen/ttyname.c new file mode 100644 index 00000000000..b7a04485f79 --- /dev/null +++ b/mit-pthreads/gen/ttyname.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 1988 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)ttyname.c 5.10 (Berkeley) 5/6/91"; +#endif /* LIBC_SCCS and not lint */ + +#include "config.h" +#include <pthread.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <dirent.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> + +static pthread_mutex_t ttyname_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_key_t ttyname_key; +static int ttyname_init = 0; +extern void free(); + +char * __ttyname_r_basic(int fd, char * buf, size_t len) +{ + register struct dirent *dirp; + register DIR *dp; + struct stat dsb; + struct stat sb; + char * rval; + int minlen; + + rval = NULL; + + /* Must be a terminal. */ + if (! isatty_basic(fd)) + return(rval); + /* Must be a character device. */ + if (machdep_sys_fstat(fd, &sb) || !S_ISCHR(sb.st_mode)) + return(rval); + /* Must have enough room */ + if (len <= sizeof(_PATH_PTY)) + return(rval); + + if ((dp = opendir(_PATH_PTY)) != NULL) { + memcpy(buf, _PATH_PTY, sizeof(_PATH_PTY)); + for (rval = NULL; dirp = readdir(dp);) { + if (dirp->d_fileno != sb.st_ino) + continue; + minlen = (len - (sizeof(_PATH_PTY) - 1)) < (dirp->d_namlen + 1) ? + (len - (sizeof(_PATH_PTY) - 1)) : (dirp->d_namlen + 1); + memcpy (buf + sizeof(_PATH_PTY) - 1, dirp->d_name, minlen); + if (stat(buf, &dsb) || sb.st_dev != dsb.st_dev || + sb.st_ino != dsb.st_ino) + continue; + rval = buf; + break; + } + (void)closedir(dp); + } + return(rval); +} + +char * __ttyname_basic(int fd) +{ + char *buf; + + pthread_mutex_lock (&ttyname_lock); + if (ttyname_init == 0) { + if (pthread_key_create(&ttyname_key, free)) { + pthread_mutex_unlock (&ttyname_lock); + return(NULL); + } + ttyname_init = 1; + } + pthread_mutex_unlock (&ttyname_lock); + + /* Must have thread specific data field to put data */ + if ((buf = pthread_getspecific(ttyname_key)) == NULL) { + if (buf = malloc(sizeof(_PATH_PTY) + MAXNAMLEN)) { + if (pthread_setspecific(ttyname_key, buf) != OK) { + free(buf); + return(NULL); + } + } else { + return(NULL); + } + } + return(__ttyname_r_basic(fd, buf, sizeof(_PATH_PTY) + MAXNAMLEN)); +} + +char * ttyname_r(int fd, char * buf, size_t len) +{ + char * ret; + + if (fd_lock(fd, FD_READ) == OK) { + ret = __ttyname_r_basic(fd_table[fd]->fd.i, buf, len); + fd_unlock(fd, FD_READ); + } else { + ret = NULL; + } + return(ret); +} + +char * ttyname(int fd) +{ + char * ret; + + if (fd_lock(fd, FD_READ) == OK) { + ret = __ttyname_basic(fd_table[fd]->fd.i); + fd_unlock(fd, FD_READ); + } else { + ret = NULL; + } + return(ret); +} + + |