mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-22 11:17:19 +00:00
1587 lines
36 KiB
C
1587 lines
36 KiB
C
/* $Header: /p/tcsh/cvsroot/tcsh/tc.os.c,v 3.69 2006/08/24 20:56:31 christos Exp $ */
|
|
/*
|
|
* tc.os.c: OS Dependent builtin functions
|
|
*/
|
|
/*-
|
|
* Copyright (c) 1980, 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. 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.
|
|
*/
|
|
#include "sh.h"
|
|
|
|
RCSID("$tcsh: tc.os.c,v 3.69 2006/08/24 20:56:31 christos Exp $")
|
|
|
|
#include "tw.h"
|
|
#include "ed.h"
|
|
#include "ed.defns.h" /* for the function names */
|
|
#include "sh.decls.h"
|
|
|
|
#ifdef _UWIN
|
|
#define TIOCGPGRP TIOCGETPGRP
|
|
#define TIOCSPGRP TIOCSETPGRP
|
|
#endif
|
|
|
|
/***
|
|
*** MACH
|
|
***/
|
|
|
|
#ifdef MACH
|
|
/* dosetpath -- setpath built-in command
|
|
*
|
|
**********************************************************************
|
|
* HISTORY
|
|
* 08-May-88 Richard Draves (rpd) at Carnegie-Mellon University
|
|
* Major changes to remove artificial limits on sizes and numbers
|
|
* of paths.
|
|
*
|
|
**********************************************************************
|
|
*/
|
|
|
|
#ifdef MACH
|
|
static Char STRCPATH[] = {'C', 'P', 'A', 'T', 'H', '\0'};
|
|
static Char STRLPATH[] = {'L', 'P', 'A', 'T', 'H', '\0'};
|
|
static Char STRMPATH[] = {'M', 'P', 'A', 'T', 'H', '\0'};
|
|
# if EPATH
|
|
static Char STREPATH[] = {'E', 'P', 'A', 'T', 'H', '\0'};
|
|
# endif
|
|
#endif /* MACH */
|
|
static Char *syspaths[] = {STRKPATH, STRCPATH, STRLPATH, STRMPATH,
|
|
|
|
#if EPATH
|
|
STREPATH,
|
|
#endif
|
|
0};
|
|
#define LOCALSYSPATH "/usr/local"
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
dosetpath(Char **arglist, struct command *c)
|
|
{
|
|
extern char *getenv();
|
|
Char **pathvars, **cmdargs;
|
|
char **spaths, **cpaths, **cmds;
|
|
char *tcp;
|
|
unsigned int npaths, ncmds;
|
|
int i, sysflag;
|
|
|
|
pintr_disabled++;
|
|
cleanup_push(&pintr_disabled, disabled_cleanup);
|
|
|
|
/*
|
|
* setpath(3) uses stdio and we want 0, 1, 2 to work...
|
|
*/
|
|
if (!didfds) {
|
|
(void) dcopy(SHIN, 0);
|
|
(void) dcopy(SHOUT, 1);
|
|
(void) dcopy(SHDIAG, 2);
|
|
didfds = 1;
|
|
}
|
|
|
|
for (i = 1; arglist[i] && (arglist[i][0] != '-'); i++);
|
|
npaths = i - 1;
|
|
|
|
cmdargs = &arglist[i];
|
|
for (; arglist[i]; i++);
|
|
ncmds = i - npaths - 1;
|
|
|
|
if (npaths) {
|
|
sysflag = 0;
|
|
pathvars = &arglist[1];
|
|
}
|
|
else {
|
|
sysflag = 1;
|
|
npaths = (sizeof syspaths / sizeof *syspaths) - 1;
|
|
pathvars = syspaths;
|
|
}
|
|
|
|
/* note that npaths != 0 */
|
|
|
|
spaths = xmalloc(npaths * sizeof *spaths);
|
|
setzero(spaths, npaths * sizeof *spaths);
|
|
cpaths = xmalloc((npaths + 1) * sizeof *cpaths);
|
|
setzero(cpaths, (npaths + 1) * sizeof *cpaths);
|
|
cmds = xmalloc((ncmds + 1) * sizeof *cmds);
|
|
setzero(cmds, (ncmds + 1) * sizeof *cmds);
|
|
for (i = 0; i < npaths; i++) {
|
|
char *val = getenv(short2str(pathvars[i]));
|
|
|
|
if (val == NULL)
|
|
val = "";
|
|
|
|
spaths[i] = xmalloc((Strlen(pathvars[i]) + strlen(val) + 2) *
|
|
sizeof **spaths);
|
|
(void) strcpy(spaths[i], short2str(pathvars[i]));
|
|
(void) strcat(spaths[i], "=");
|
|
(void) strcat(spaths[i], val);
|
|
cpaths[i] = spaths[i];
|
|
}
|
|
|
|
for (i = 0; i < ncmds; i++) {
|
|
Char *val = globone(cmdargs[i], G_ERROR);/*FIXRESET*/
|
|
|
|
if (val == NULL)
|
|
goto abortpath;
|
|
cmds[i] = strsave(short2str(val));
|
|
}
|
|
|
|
|
|
if (setpath(cpaths, cmds, LOCALSYSPATH, sysflag, 1) < 0) {
|
|
abortpath:
|
|
if (spaths) {
|
|
for (i = 0; i < npaths; i++)
|
|
xfree(spaths[i]);
|
|
xfree(spaths);
|
|
}
|
|
xfree(cpaths);
|
|
if (cmds) {
|
|
for (i = 0; i < ncmds; i++)
|
|
xfree(cmds[i]);
|
|
xfree(cmds);
|
|
}
|
|
|
|
cleanup_until(&pintr_disabled);
|
|
donefds();
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < npaths; i++) {
|
|
Char *val, *name;
|
|
|
|
name = str2short(cpaths[i]);
|
|
for (val = str2short(cpaths[i]); val && *val && *val != '='; val++);
|
|
if (val && *val == '=') {
|
|
*val++ = '\0';
|
|
|
|
tsetenv(name, val);/*FIXRESET*/
|
|
if (Strcmp(name, STRKPATH) == 0) {
|
|
importpath(val);/*FIXRESET*/
|
|
if (havhash)
|
|
dohash(NULL, NULL);/*FIXRESET*/
|
|
}
|
|
*--val = '=';
|
|
}
|
|
}
|
|
cleanup_until(&pintr_disabled);
|
|
donefds();
|
|
}
|
|
#endif /* MACH */
|
|
|
|
/***
|
|
*** AIX
|
|
***/
|
|
#ifdef TCF
|
|
/* ARGSUSED */
|
|
void
|
|
dogetxvers(Char **v, struct command *c)
|
|
{
|
|
char xvers[MAXPATHLEN];
|
|
|
|
if (getxvers(xvers, MAXPATHLEN) == -1)
|
|
stderror(ERR_SYSTEM, "getxvers", strerror(errno));
|
|
xprintf("%s\n", xvers);
|
|
flush();
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
dosetxvers(Char **v, struct command *c)
|
|
{
|
|
char *xvers;
|
|
|
|
++v;
|
|
if (!*v || *v[0] == '\0')
|
|
xvers = "";
|
|
else
|
|
xvers = short2str(*v);
|
|
if (setxvers(xvers) == -1)
|
|
stderror(ERR_SYSTEM, "setxvers", strerror(errno));
|
|
}
|
|
|
|
#include <sf.h>
|
|
#ifdef _AIXPS2
|
|
# define XC_PDP11 0x01
|
|
# define XC_23 0x02
|
|
# define XC_Z8K 0x03
|
|
# define XC_8086 0x04
|
|
# define XC_68K 0x05
|
|
# define XC_Z80 0x06
|
|
# define XC_VAX 0x07
|
|
# define XC_16032 0x08
|
|
# define XC_286 0x09
|
|
# define XC_386 0x0a
|
|
# define XC_S370 0x0b
|
|
#else
|
|
# include <sys/x.out.h>
|
|
#endif /* _AIXPS2 */
|
|
|
|
static struct xc_cpu_t {
|
|
short xc_id;
|
|
char *xc_name;
|
|
} xcpu[] =
|
|
{
|
|
{ XC_PDP11, "pdp11" },
|
|
{ XC_23, "i370" },
|
|
{ XC_Z8K, "z8000" },
|
|
{ XC_8086, "i86" },
|
|
{ XC_68K, "mc68000" },
|
|
{ XC_Z80, "x80" },
|
|
{ XC_VAX, "vax" },
|
|
{ XC_16032, "ns16032" },
|
|
{ XC_286, "i286" },
|
|
{ XC_386, "i386" },
|
|
{ XC_S370, "xa370" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
/*
|
|
* our local hack table, stolen from x.out.h
|
|
*/
|
|
static char *
|
|
getxcode(short xcid)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; xcpu[i].xc_name != NULL; i++)
|
|
if (xcpu[i].xc_id == xcid)
|
|
return (xcpu[i].xc_name);
|
|
return (NULL);
|
|
}
|
|
|
|
static short
|
|
getxid(char *xcname)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; xcpu[i].xc_name != NULL; i++)
|
|
if (strcmp(xcpu[i].xc_name, xcname) == 0)
|
|
return (xcpu[i].xc_id);
|
|
return ((short) -1);
|
|
}
|
|
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
dogetspath(Char **v, struct command *c)
|
|
{
|
|
int i, j;
|
|
sitepath_t p[MAXSITE];
|
|
struct sf *st;
|
|
static char *local = "LOCAL ";
|
|
|
|
if ((j = getspath(p, MAXSITE)) == -1)
|
|
stderror(ERR_SYSTEM, "getspath", strerror(errno));
|
|
for (i = 0; i < j && (p[i] & SPATH_CPU) != NOSITE; i++) {
|
|
if (p[i] & SPATH_CPU) {
|
|
if ((p[i] & SPATH_MASK) == NULLSITE)
|
|
xprintf(local);
|
|
else if ((st = sfxcode((short) (p[i] & SPATH_MASK))) != NULL)
|
|
xprintf("%s ", st->sf_ctype);
|
|
else {
|
|
char *xc = getxcode(p[i] & SPATH_MASK);
|
|
|
|
if (xc != NULL)
|
|
xprintf("%s ", xc);
|
|
else
|
|
xprintf("*cpu %d* ", (int) (p[i] & SPATH_MASK));
|
|
/*
|
|
* BUG in the aix code... needs that cause if
|
|
* sfxcode fails once it fails for ever
|
|
*/
|
|
endsf();
|
|
}
|
|
}
|
|
else {
|
|
if (p[i] == NULLSITE)
|
|
xprintf(local);
|
|
else if ((st = sfnum(p[i])) != NULL)
|
|
xprintf("%s ", st->sf_sname);
|
|
else
|
|
xprintf("*site %d* ", (int) (p[i] & SPATH_MASK));
|
|
}
|
|
}
|
|
xputchar('\n');
|
|
flush();
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
dosetspath(Char **v, struct command *c)
|
|
{
|
|
int i;
|
|
short j;
|
|
char *s;
|
|
sitepath_t p[MAXSITE];
|
|
struct sf *st;
|
|
|
|
/*
|
|
* sfname() on AIX G9.9 at least, mallocs too pointers p, q
|
|
* then does the equivalent of while (*p++ == *q++) continue;
|
|
* and then tries to free(p,q) them! Congrats to the wizard who
|
|
* wrote that one. I bet he tested it really well too.
|
|
* Sooo, we set dont_free :-)
|
|
*/
|
|
dont_free = 1;
|
|
for (i = 0, v++; *v && *v[0] != '\0'; v++, i++) {
|
|
s = short2str(*v);
|
|
if (isdigit(*s))
|
|
p[i] = atoi(s);
|
|
else if (strcmp(s, "LOCAL") == 0)
|
|
p[i] = NULLSITE;
|
|
else if ((st = sfctype(s)) != NULL)
|
|
p[i] = SPATH_CPU | st->sf_ccode;
|
|
else if ((j = getxid(s)) != -1)
|
|
p[i] = SPATH_CPU | j;
|
|
else if ((st = sfname(s)) != NULL)
|
|
p[i] = st->sf_id;
|
|
else {
|
|
setname(s);
|
|
stderror(ERR_NAME | ERR_STRING, CGETS(23, 1, "Bad cpu/site name"));
|
|
}
|
|
if (i == MAXSITE - 1)
|
|
stderror(ERR_NAME | ERR_STRING, CGETS(23, 2, "Site path too long"));
|
|
}
|
|
if (setspath(p, i) == -1)
|
|
stderror(ERR_SYSTEM, "setspath", strerror(errno));
|
|
dont_free = 0;
|
|
}
|
|
|
|
/* sitename():
|
|
* Return the site name where the process is running
|
|
*/
|
|
char *
|
|
sitename(pid_t pid)
|
|
{
|
|
siteno_t ss;
|
|
struct sf *st;
|
|
|
|
if ((ss = site(pid)) == -1 || (st = sfnum(ss)) == NULL)
|
|
return CGETS(23, 3, "unknown");
|
|
else
|
|
return st->sf_sname;
|
|
}
|
|
|
|
static int
|
|
migratepid(pit_t pid, siteno_t new_site)
|
|
{
|
|
struct sf *st;
|
|
int need_local;
|
|
|
|
need_local = (pid == 0) || (pid == getpid());
|
|
|
|
if (kill3(pid, SIGMIGRATE, new_site) < 0) {
|
|
xprintf("%d: %s\n", pid, strerror(errno));
|
|
return (-1);
|
|
}
|
|
|
|
if (need_local) {
|
|
if ((new_site = site(0)) == -1) {
|
|
xprintf(CGETS(23, 4, "site: %s\n"), strerror(errno));
|
|
return (-1);
|
|
}
|
|
if ((st = sfnum(new_site)) == NULL) {
|
|
xprintf(CGETS(23, 5, "%d: Site not found\n"), new_site);
|
|
return (-1);
|
|
}
|
|
if (setlocal(st->sf_local, strlen(st->sf_local)) == -1) {
|
|
xprintf(CGETS(23, 6, "setlocal: %s: %s\n"),
|
|
st->sf_local, strerror(errno));
|
|
return (-1);
|
|
}
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
domigrate(Char **v, struct command *c)
|
|
{
|
|
struct sf *st;
|
|
char *s;
|
|
Char *cp;
|
|
struct process *pp;
|
|
int err1 = 0;
|
|
int pid = 0;
|
|
siteno_t new_site = 0;
|
|
|
|
pchild_disabled++;
|
|
cleanup_push(&pchild_disabled, disabled_cleanup);
|
|
if (setintr) {
|
|
pintr_disabled++;
|
|
cleanup_push(&pintr_disabled, disabled_cleanup);
|
|
}
|
|
|
|
++v;
|
|
if (*v[0] == '-') {
|
|
/*
|
|
* Do the -site.
|
|
*/
|
|
s = short2str(&v[0][1]);
|
|
/*
|
|
* see comment in setspath()
|
|
*/
|
|
dont_free = 1;
|
|
if ((st = sfname(s)) == NULL) {
|
|
dont_free = 0;
|
|
setname(s);
|
|
stderror(ERR_NAME | ERR_STRING, CGETS(23, 7, "Site not found"));
|
|
}
|
|
dont_free = 0;
|
|
new_site = st->sf_id;
|
|
++v;
|
|
}
|
|
|
|
if (!*v || *v[0] == '\0') {
|
|
if (migratepid(0, new_site) == -1)
|
|
err1++;
|
|
}
|
|
else {
|
|
Char **globbed;
|
|
|
|
v = glob_all_or_error(v);
|
|
globbed = v;
|
|
cleanup_push(globbed, blk_cleanup);
|
|
|
|
while (v && (cp = *v)) {
|
|
if (*cp == '%') {
|
|
pp = pfind(cp);
|
|
if (kill3(- pp->p_jobid, SIGMIGRATE, new_site) < 0) {
|
|
xprintf("%S: %s\n", cp, strerror(errno));
|
|
err1++;
|
|
}
|
|
}
|
|
else if (!(Isdigit(*cp) || *cp == '-'))
|
|
stderror(ERR_NAME | ERR_JOBARGS);
|
|
else {
|
|
pid = atoi(short2str(cp));
|
|
if (migratepid(pid, new_site) == -1)
|
|
err1++;
|
|
}
|
|
v++;
|
|
}
|
|
cleanup_until(globbed);
|
|
}
|
|
|
|
done:
|
|
cleanup_until(&pchild_disabled);
|
|
if (err1)
|
|
stderror(ERR_SILENT);
|
|
}
|
|
|
|
#endif /* TCF */
|
|
|
|
/***
|
|
*** CRAY ddmode <velo@sesun3.epfl.ch> (Martin Ouwehand EPFL-SIC/SE)
|
|
***/
|
|
#if defined(_CRAY) && !defined(_CRAYMPP)
|
|
void
|
|
dodmmode(Char **v, struct command *c)
|
|
{
|
|
Char *cp = v[1];
|
|
|
|
USE(c);
|
|
|
|
if ( !cp ) {
|
|
int mode;
|
|
|
|
mode = dmmode(0);
|
|
dmmode(mode);
|
|
xprintf("%d\n",mode);
|
|
}
|
|
else {
|
|
if (cp[1] != '\0')
|
|
stderror(ERR_NAME | ERR_STRING,
|
|
CGETS(23, 30, "Too many arguments"));
|
|
else
|
|
switch(*cp) {
|
|
case '0':
|
|
dmmode(0);
|
|
break;
|
|
case '1':
|
|
dmmode(1);
|
|
break;
|
|
default:
|
|
stderror(ERR_NAME | ERR_STRING,
|
|
CGETS(23, 31, "Invalid argument"));
|
|
}
|
|
}
|
|
}
|
|
#endif /* _CRAY && !_CRAYMPP */
|
|
|
|
|
|
/***
|
|
*** CONVEX Warps.
|
|
***/
|
|
|
|
#ifdef WARP
|
|
/*
|
|
* handle the funky warping of symlinks
|
|
*/
|
|
#include <warpdb.h>
|
|
#include <sys/warp.h>
|
|
|
|
static jmp_buf sigsys_buf;
|
|
|
|
static void
|
|
catch_sigsys(void)
|
|
{
|
|
sigset_t set;
|
|
sigemptyset(&set, SIGSYS);
|
|
(void)sigprocmask(SIG_UNBLOCK, &set, NULL);
|
|
longjmp(sigsys_buf, 1);
|
|
}
|
|
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
dowarp(Char **v, struct command *c)
|
|
{
|
|
int warp, oldwarp;
|
|
struct warpent *we;
|
|
volatile struct sigaction old_sigsys_handler;
|
|
char *newwarp;
|
|
|
|
if (setjmp(sigsys_buf)) {
|
|
sigaction(SIGSYS, &old_sigsys_handler, NULL);
|
|
stderror(ERR_NAME | ERR_STRING,
|
|
CGETS(23, 8, "You're trapped in a universe you never made"));
|
|
return;
|
|
}
|
|
sigaction(SIGSYS, NULL, &old_sigsys_handler);
|
|
signal(SIGSYS, catch_sigsys);
|
|
|
|
warp = getwarp();
|
|
|
|
v++;
|
|
if (*v == 0) { /* display warp value */
|
|
if (warp < 0)
|
|
stderror(ERR_NAME | ERR_STRING, CGETS(23, 9, "Getwarp failed"));
|
|
we = getwarpbyvalue(warp);
|
|
if (we)
|
|
printf("%s\n", we->w_name);
|
|
else
|
|
printf("%d\n", warp);
|
|
}
|
|
else { /* set warp value */
|
|
oldwarp = warp;
|
|
newwarp = short2str(*v);
|
|
if (Isdigit(*v[0]))
|
|
warp = atoi(newwarp);
|
|
else {
|
|
we = getwarpbyname(newwarp);
|
|
if (we)
|
|
warp = we->w_value;
|
|
else
|
|
warp = -1;
|
|
}
|
|
if ((warp < 0) || (warp >= WARP_MAXLINK))
|
|
stderror(ERR_NAME | ERR_STRING, CGETS(23, 10, "Invalid warp"));
|
|
if ((setwarp(warp) < 0) || (getwarp() != warp)) {
|
|
(void) setwarp(oldwarp);
|
|
stderror(ERR_NAME | ERR_STRING, CGETS(23, 11, "Setwarp failed"));
|
|
}
|
|
}
|
|
sigaction(SIGSYS, &old_sigsys_handler, NULL);
|
|
}
|
|
#endif /* WARP */
|
|
|
|
/***
|
|
*** Masscomp or HCX
|
|
***/
|
|
/* Added, DAS DEC-90. */
|
|
#if defined(masscomp) || defined(_CX_UX)
|
|
static void
|
|
setuniverse_cleanup(void *xbuf)
|
|
{
|
|
char *buf;
|
|
|
|
buf = xbuf;
|
|
setuniverse(buf);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
douniverse(Char **v, struct command *c)
|
|
{
|
|
Char *cp = v[1];
|
|
Char *cp2; /* dunno how many elements v comes in with */
|
|
char ubuf[100];
|
|
|
|
if (cp == 0) {
|
|
(void) getuniverse(ubuf);
|
|
xprintf("%s\n", ubuf);
|
|
}
|
|
else {
|
|
cp2 = v[2];
|
|
if (cp2 == 0) {
|
|
if (*cp == '\0' || setuniverse(short2str(cp)) != 0)
|
|
stderror(ERR_NAME | ERR_STRING, CGETS(23, 12, "Illegal universe"));
|
|
}
|
|
else {
|
|
(void) getuniverse(ubuf);
|
|
if (*cp == '\0' || setuniverse(short2str(cp)) != 0)
|
|
stderror(ERR_NAME | ERR_STRING, CGETS(23, 12, "Illegal universe"));
|
|
cleanup_push(ubuf, setuniverse_cleanup);
|
|
if (setintr) {
|
|
pintr_disabled++;
|
|
cleanup_push(&pintr_disabled, disabled_cleanup);
|
|
}
|
|
lshift(v, 2);
|
|
if (setintr)
|
|
cleanup_until(&pintr_disabled);
|
|
reexecute(c);
|
|
cleanup_until(ubuf);
|
|
}
|
|
}
|
|
}
|
|
#endif /* masscomp || _CX_UX */
|
|
|
|
/***
|
|
*** BS2000/OSD POSIX (Fujitsu Siemens Computers)
|
|
***/
|
|
#if defined(_OSD_POSIX)
|
|
static int
|
|
bs2upcase(char *str)
|
|
{
|
|
enum { outside = ' ', singlequote='\'', doublequote='"'} string = outside;
|
|
|
|
char *white;
|
|
|
|
for (white = str + strlen(str) - 1; isspace(*white) && white > str; --white)
|
|
*white = '\0';
|
|
|
|
for (; *str != '\0'; ++str)
|
|
{
|
|
if (string == outside)
|
|
{
|
|
*str = toupper (*str);
|
|
}
|
|
if (*str == '\'')
|
|
{
|
|
if (string == outside)
|
|
string = singlequote;
|
|
else if (string != doublequote)
|
|
string = outside;
|
|
}
|
|
else if (*str == '"')
|
|
{
|
|
if (string == outside)
|
|
string = doublequote;
|
|
else if (string != singlequote)
|
|
string = outside;
|
|
}
|
|
}
|
|
if (string != outside)
|
|
{
|
|
stderror(ERR_NAME | ERR_UNMATCHED, (Char) string);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
static int
|
|
bs2cmdlist(char *str)
|
|
{
|
|
char *str_beg = NULL;
|
|
int ret = 0;
|
|
|
|
enum { outside = ' ', singlequote='\'', doublequote='"'} string = outside;
|
|
|
|
while (*str != '\0')
|
|
{
|
|
while (isspace(*str))
|
|
++str;
|
|
|
|
if (*str == '\0')
|
|
break;
|
|
|
|
str_beg = str;
|
|
|
|
for (; *str != '\0'; ++str)
|
|
{
|
|
if (string == outside && *str == ';') /* End of command */
|
|
{
|
|
*str++ = '\0';
|
|
break; /* continue with next command */
|
|
}
|
|
if (*str == '\'')
|
|
{
|
|
if (string == outside)
|
|
string = singlequote;
|
|
else if (string != doublequote)
|
|
string = outside;
|
|
}
|
|
else if (*str == '"')
|
|
{
|
|
if (string == outside)
|
|
string = doublequote;
|
|
else if (string != singlequote)
|
|
string = outside;
|
|
}
|
|
}
|
|
if (strlen(str_beg) != 0)
|
|
{
|
|
ret = bs2system(str_beg);
|
|
flush();
|
|
if (ret != 0 /*&& !option.err_ignore*/)
|
|
break; /* do not continue after errors */
|
|
}
|
|
}
|
|
|
|
if (string != outside)
|
|
{
|
|
stderror(ERR_NAME | ERR_UNMATCHED, (Char) string);
|
|
return -1;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
/*ARGSUSED*/
|
|
void
|
|
dobs2cmd(Char **v, struct command *c)
|
|
{
|
|
Char *cp, **globbed;
|
|
int i = 0, len = 0;
|
|
char *cmd = NULL;
|
|
int pvec[2];
|
|
struct command faket;
|
|
Char *fakecom[2];
|
|
char tibuf[BUFSIZE];
|
|
int icnt, old_pintr_disabled;
|
|
static const Char STRbs2cmd[] = { 'b','s','2','c','m','d','\0' };
|
|
|
|
v++;
|
|
if (setintr)
|
|
pintr_push_enable(&old_pintr_disabled);
|
|
v = glob_all_or_error(v);
|
|
if (setintr)
|
|
cleanup_until(&old_pintr_disabled);
|
|
globbed = v;
|
|
cleanup_push(globbed, blk_cleanup);
|
|
|
|
/* First round: count the string lengths */
|
|
for (i=0; v[i]; ++i) {
|
|
len += Strlen(v[i]) + (v[i+1] != NULL);
|
|
}
|
|
|
|
cmd = xmalloc(len+1); /* 1 for the final '\0' *//* FIXME: memory leak? */
|
|
|
|
/* 2nd round: fill cmd buffer */
|
|
i = 0;
|
|
while ((cp = *v++) != 0) {
|
|
int c;
|
|
while (c = *cp++)
|
|
cmd[i++] = (char)c;
|
|
if (*v)
|
|
cmd[i++] = ' ';
|
|
}
|
|
cmd[i] = '\0';
|
|
|
|
/* Make upper case */
|
|
bs2upcase(cmd);
|
|
|
|
faket.t_dtyp = NODE_COMMAND;
|
|
faket.t_dflg = F_BACKQ|F_STDERR;
|
|
faket.t_dlef = 0;
|
|
faket.t_drit = 0;
|
|
faket.t_dspr = 0;
|
|
faket.t_dcom = fakecom;
|
|
fakecom[0] = (Char *)STRbs2cmd;
|
|
fakecom[1] = 0;
|
|
|
|
mypipe(pvec);
|
|
cleanup_push(&pvec[0], open_cleanup);
|
|
cleanup_push(&pvec[1], open_cleanup);
|
|
if (pfork(&faket, -1) == 0) {
|
|
sigset_t set;
|
|
/* child */
|
|
xclose(pvec[0]);
|
|
(void) dmove(pvec[1], 1);
|
|
(void) dmove(SHDIAG, 2);
|
|
initdesc();
|
|
sigemptyset(&set);
|
|
sigaddset(&set, SIGINT);
|
|
(void)sigprocmask(SIG_UNBLOCK, &set, NULL);
|
|
#ifdef SIGTSTP
|
|
signal(SIGTSTP, SIG_IGN);
|
|
#endif
|
|
#ifdef SIGTTIN
|
|
signal(SIGTTIN, SIG_IGN);
|
|
#endif
|
|
#ifdef SIGTTOU
|
|
signal(SIGTTOU, SIG_IGN);
|
|
#endif
|
|
xexit(bs2cmdlist(cmd));
|
|
}
|
|
cleanup_until(&pvec[1]);
|
|
for(;;) {
|
|
int old_pintr_disabled;
|
|
|
|
if (setintr)
|
|
pintr_push_enable(&old_pintr_disabled);
|
|
icnt = xread(pvec[0], tibuf, sizeof(tibuf));
|
|
if (setintr)
|
|
cleanup_until(&old_pintr_disabled);
|
|
if (icnt <= 0)
|
|
break;
|
|
for (i = 0; i < icnt; i++)
|
|
xputchar((unsigned char) tibuf[i]);
|
|
}
|
|
cleanup_until(&pvec[0]);
|
|
pwait();
|
|
|
|
flush();
|
|
|
|
cleanup_until(globbed);
|
|
}
|
|
#endif /* _OSD_POSIX */
|
|
|
|
#if defined(_CX_UX)
|
|
static void
|
|
setuniverse_cleanup(void *xbuf)
|
|
{
|
|
char *buf;
|
|
|
|
buf = xbuf;
|
|
setuniverse(buf);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
doatt(Char **v, struct command *c)
|
|
{
|
|
Char *cp = v[1];
|
|
char ubuf[100];
|
|
|
|
if (cp == 0)
|
|
(void) setuniverse("att");
|
|
else {
|
|
(void) getuniverse(ubuf);
|
|
(void) setuniverse("att");
|
|
cleanup_push(ubuf, setuniverse_cleanup);
|
|
if (setintr) {
|
|
pintr_disabled++;
|
|
cleanup_push(&pintr_disabled, disabled_cleanup);
|
|
}
|
|
lshift(v, 1);
|
|
if (setintr)
|
|
cleanup_until(&pintr_disabled);
|
|
reexecute(c);
|
|
cleanup_until(ubuf);
|
|
}
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
doucb(Char **v, struct command *c)
|
|
{
|
|
Char *cp = v[1];
|
|
char ubuf[100];
|
|
|
|
if (cp == 0)
|
|
(void) setuniverse("ucb");
|
|
else {
|
|
(void) getuniverse(ubuf);
|
|
(void) setuniverse("ucb");
|
|
cleanup_push(ubuf, setuniverse_cleanup);
|
|
if (setintr) {
|
|
pintr_disabled++;
|
|
cleanup_push(&pintr_disabled, disabled_cleanup);
|
|
}
|
|
lshift(v, 1);
|
|
if (setintr)
|
|
cleanup_until(&pintr_disabled);
|
|
reexecute(c);
|
|
cleanup_until(ubuf);
|
|
}
|
|
}
|
|
#endif /* _CX_UX */
|
|
|
|
#ifdef _SEQUENT_
|
|
/*
|
|
* Compute the difference in process stats.
|
|
*/
|
|
void
|
|
pr_stat_sub(struct process_stats *p2, struct process_stats *p1,
|
|
struct process_stats *pr)
|
|
{
|
|
pr->ps_utime.tv_sec = p2->ps_utime.tv_sec - p1->ps_utime.tv_sec;
|
|
pr->ps_utime.tv_usec = p2->ps_utime.tv_usec - p1->ps_utime.tv_usec;
|
|
if (pr->ps_utime.tv_usec < 0) {
|
|
pr->ps_utime.tv_sec -= 1;
|
|
pr->ps_utime.tv_usec += 1000000;
|
|
}
|
|
pr->ps_stime.tv_sec = p2->ps_stime.tv_sec - p1->ps_stime.tv_sec;
|
|
pr->ps_stime.tv_usec = p2->ps_stime.tv_usec - p1->ps_stime.tv_usec;
|
|
if (pr->ps_stime.tv_usec < 0) {
|
|
pr->ps_stime.tv_sec -= 1;
|
|
pr->ps_stime.tv_usec += 1000000;
|
|
}
|
|
|
|
pr->ps_maxrss = p2->ps_maxrss - p1->ps_maxrss;
|
|
pr->ps_pagein = p2->ps_pagein - p1->ps_pagein;
|
|
pr->ps_reclaim = p2->ps_reclaim - p1->ps_reclaim;
|
|
pr->ps_zerofill = p2->ps_zerofill - p1->ps_zerofill;
|
|
pr->ps_pffincr = p2->ps_pffincr - p1->ps_pffincr;
|
|
pr->ps_pffdecr = p2->ps_pffdecr - p1->ps_pffdecr;
|
|
pr->ps_swap = p2->ps_swap - p1->ps_swap;
|
|
pr->ps_syscall = p2->ps_syscall - p1->ps_syscall;
|
|
pr->ps_volcsw = p2->ps_volcsw - p1->ps_volcsw;
|
|
pr->ps_involcsw = p2->ps_involcsw - p1->ps_involcsw;
|
|
pr->ps_signal = p2->ps_signal - p1->ps_signal;
|
|
pr->ps_lread = p2->ps_lread - p1->ps_lread;
|
|
pr->ps_lwrite = p2->ps_lwrite - p1->ps_lwrite;
|
|
pr->ps_bread = p2->ps_bread - p1->ps_bread;
|
|
pr->ps_bwrite = p2->ps_bwrite - p1->ps_bwrite;
|
|
pr->ps_phread = p2->ps_phread - p1->ps_phread;
|
|
pr->ps_phwrite = p2->ps_phwrite - p1->ps_phwrite;
|
|
}
|
|
|
|
#endif /* _SEQUENT_ */
|
|
|
|
|
|
#ifndef HAVE_MEMSET
|
|
/* This is a replacement for a missing memset function */
|
|
void *xmemset(void *loc, int value, size_t len)
|
|
{
|
|
char *ptr = loc;
|
|
|
|
while (len--)
|
|
*ptr++ = value;
|
|
return loc;
|
|
}
|
|
#endif /* !HAVE_MEMSET */
|
|
|
|
|
|
#ifndef HAVE_MEMMOVE
|
|
/* memmove():
|
|
* This is the ANSI form of bcopy() with the arguments backwards...
|
|
* Unlike memcpy(), it handles overlaps between source and
|
|
* destination memory
|
|
*/
|
|
void *
|
|
xmemmove(void *vdst, const void *vsrc, size_t len)
|
|
{
|
|
const char *src = vsrc;
|
|
char *dst = vdst;
|
|
|
|
if (src == dst)
|
|
return vdst;
|
|
|
|
if (src > dst) {
|
|
while (len--)
|
|
*dst++ = *src++;
|
|
}
|
|
else {
|
|
src += len;
|
|
dst += len;
|
|
while (len--)
|
|
*--dst = *--src;
|
|
}
|
|
return vdst;
|
|
}
|
|
#endif /* HAVE_MEMMOVE */
|
|
|
|
|
|
#ifndef WINNT_NATIVE
|
|
#ifdef NEEDtcgetpgrp
|
|
pid_t
|
|
xtcgetpgrp(int fd)
|
|
{
|
|
int pgrp;
|
|
|
|
/* ioctl will handle setting errno correctly. */
|
|
if (ioctl(fd, TIOCGPGRP, (ioctl_t) & pgrp) < 0)
|
|
return (-1);
|
|
return (pgrp);
|
|
}
|
|
|
|
/*
|
|
* XXX: tcsetpgrp is not a macro any more cause on some systems,
|
|
* pid_t is a short, but the ioctl() takes a pointer to int (pyr)
|
|
* Thanks to Simon Day (simon@pharaoh.cyborg.bt.co.uk) for pointing
|
|
* this out.
|
|
*/
|
|
int
|
|
xtcsetpgrp(int fd, int pgrp)
|
|
{
|
|
return ioctl(fd, TIOCSPGRP, (ioctl_t) &pgrp);
|
|
}
|
|
|
|
#endif /* NEEDtcgetpgrp */
|
|
#endif /* WINNT_NATIVE */
|
|
|
|
|
|
#ifdef YPBUGS
|
|
void
|
|
fix_yp_bugs(void)
|
|
{
|
|
char *mydomain;
|
|
|
|
extern int yp_get_default_domain (char **);
|
|
/*
|
|
* PWP: The previous version assumed that yp domain was the same as the
|
|
* internet name domain. This isn't allways true. (Thanks to Mat Landau
|
|
* <mlandau@bbn.com> for the original version of this.)
|
|
*/
|
|
if (yp_get_default_domain(&mydomain) == 0) { /* if we got a name */
|
|
extern void yp_unbind (const char *);
|
|
|
|
yp_unbind(mydomain);
|
|
}
|
|
}
|
|
|
|
#endif /* YPBUGS */
|
|
|
|
#ifdef STRCOLLBUG
|
|
void
|
|
fix_strcoll_bug(void)
|
|
{
|
|
#if defined(NLS) && defined(HAVE_STRCOLL)
|
|
/*
|
|
* SunOS4 checks the file descriptor from openlocale() for <= 0
|
|
* instead of == -1. Someone should tell sun that file descriptor 0
|
|
* is valid! Our portable hack: open one so we call it with 0 used...
|
|
* We have to call this routine every time the locale changes...
|
|
*
|
|
* Of course it also tries to free the constant locale "C" it initially
|
|
* had allocated, with the sequence
|
|
* > setenv LANG "fr"
|
|
* > ls^D
|
|
* > unsetenv LANG
|
|
* But we are smarter than that and just print a warning message.
|
|
*/
|
|
int fd = -1;
|
|
static char *root = "/";
|
|
|
|
if (!didfds)
|
|
fd = xopen(root, O_RDONLY|O_LARGEFILE);
|
|
|
|
(void) strcoll(root, root);
|
|
|
|
if (fd != -1)
|
|
xclose(fd);
|
|
#endif
|
|
}
|
|
#endif /* STRCOLLBUG */
|
|
|
|
|
|
#ifdef OREO
|
|
#include <compat.h>
|
|
#endif /* OREO */
|
|
|
|
void
|
|
osinit(void)
|
|
{
|
|
#ifdef OREO
|
|
set42sig();
|
|
setcompat(getcompat() & ~COMPAT_EXEC);
|
|
signal(SIGIO, SIG_IGN); /* ignore SIGIO */
|
|
#endif /* OREO */
|
|
|
|
#ifdef aiws
|
|
{
|
|
struct sigstack inst;
|
|
inst.ss_sp = xmalloc(4192) + 4192;
|
|
inst.ss_onstack = 0;
|
|
sigstack(&inst, NULL);
|
|
}
|
|
#endif /* aiws */
|
|
|
|
#ifdef apollo
|
|
(void) isapad();
|
|
#endif
|
|
|
|
#ifdef _SX
|
|
/*
|
|
* kill(SIGCONT) problems, don't know what this syscall does
|
|
* [schott@rzg.mpg.de]
|
|
*/
|
|
syscall(151, getpid(), getpid());
|
|
#endif /* _SX */
|
|
}
|
|
|
|
#ifndef HAVE_STRERROR
|
|
extern int sys_nerr;
|
|
extern char *sys_errlist[];
|
|
char *
|
|
xstrerror(int i)
|
|
{
|
|
if (i >= 0 && i < sys_nerr) {
|
|
return sys_errlist[i];
|
|
} else {
|
|
static char *errbuf; /* = NULL; */
|
|
|
|
xfree(errbuf);
|
|
errbuf = xasprintf(CGETS(23, 13, "Unknown Error: %d"), i);
|
|
return errbuf;
|
|
}
|
|
}
|
|
#endif /* !HAVE_STRERROR */
|
|
|
|
#ifndef HAVE_GETHOSTNAME
|
|
# if !defined(_MINIX) && !defined(__EMX__) && !defined(WINNT_NATIVE)
|
|
# include <sys/utsname.h>
|
|
# endif /* !_MINIX && !__EMX__ && !WINNT_NATIVE */
|
|
|
|
int
|
|
xgethostname(char *name, int namlen)
|
|
{
|
|
# if !defined(_MINIX) && !defined(__EMX__) && !defined(WINNT_NATIVE)
|
|
int i, retval;
|
|
struct utsname uts;
|
|
|
|
retval = uname(&uts);
|
|
|
|
# ifdef DEBUG
|
|
xprintf(CGETS(23, 14, "sysname: %s\n"), uts.sysname);
|
|
xprintf(CGETS(23, 15, "nodename: %s\n"), uts.nodename);
|
|
xprintf(CGETS(23, 16, "release: %s\n"), uts.release);
|
|
xprintf(CGETS(23, 17, "version: %s\n"), uts.version);
|
|
xprintf(CGETS(23, 18, "machine: %s\n"), uts.machine);
|
|
# endif /* DEBUG */
|
|
i = strlen(uts.nodename) + 1;
|
|
(void) strncpy(name, uts.nodename, i < namlen ? i : namlen);
|
|
|
|
return retval;
|
|
# else /* !_MINIX && !__EMX__ */
|
|
if (namlen > 0) {
|
|
# ifdef __EMX__
|
|
(void) strncpy(name, "OS/2", namlen);
|
|
# else /* _MINIX */
|
|
(void) strncpy(name, "minix", namlen);
|
|
# endif /* __EMX__ */
|
|
name[namlen-1] = '\0';
|
|
}
|
|
return(0);
|
|
#endif /* _MINIX && !__EMX__ */
|
|
} /* end xgethostname */
|
|
#endif /* !HAVE_GETHOSTNAME */
|
|
|
|
#ifndef HAVE_NICE
|
|
# if defined(_MINIX) && defined(NICE)
|
|
# undef _POSIX_SOURCE /* redefined in <lib.h> */
|
|
# undef _MINIX /* redefined in <lib.h> */
|
|
# undef HZ /* redefined in <minix/const.h> */
|
|
# include <lib.h>
|
|
# endif /* _MINIX && NICE */
|
|
int
|
|
xnice(int incr)
|
|
{
|
|
#if defined(_MINIX) && defined(NICE)
|
|
return callm1(MM, NICE, incr, 0, 0, NIL_PTR, NIL_PTR, NIL_PTR);
|
|
#else
|
|
return /* incr ? 0 : */ 0;
|
|
#endif /* _MINIX && NICE */
|
|
} /* end xnice */
|
|
#endif /* !HAVE_NICE */
|
|
|
|
#ifndef HAVE_GETCWD
|
|
static char *strnrcpy (char *, char *, size_t);
|
|
|
|
/* xgetcwd():
|
|
* Return the pathname of the current directory, or return
|
|
* an error message in pathname.
|
|
*/
|
|
|
|
# ifdef hp9000s500
|
|
/*
|
|
* From: Bernd Mohr <mohr@faui77.informatik.uni-erlangen.de>
|
|
* I also ported the tcsh to the HP9000 Series 500. This computer
|
|
* is a little bit different than the other HP 9000 computer. It has
|
|
* a HP Chip instead of a Motorola CPU and it is no "real" UNIX. It runs
|
|
* HP-UX which is emulated in top of a HP operating system. So, the last
|
|
* supported version of HP-UX is 5.2 on the HP9000s500. This has two
|
|
* consequences: it supports no job control and it has a filesystem
|
|
* without "." and ".." !!!
|
|
*/
|
|
char *
|
|
xgetcwd(char *pathname, size_t pathlen)
|
|
{
|
|
char pathbuf[MAXPATHLEN]; /* temporary pathname buffer */
|
|
char *pnptr = &pathbuf[(sizeof pathbuf)-1]; /* pathname pointer */
|
|
dev_t rdev; /* root device number */
|
|
DIR *dirp = NULL; /* directory stream */
|
|
ino_t rino; /* root inode number */
|
|
off_t rsize; /* root size */
|
|
struct direct *dir; /* directory entry struct */
|
|
struct stat d, dd; /* file status struct */
|
|
int serrno;
|
|
|
|
*pnptr = '\0';
|
|
(void) stat("/.", &d);
|
|
rdev = d.st_dev;
|
|
rino = d.st_ino;
|
|
rsize = d.st_size;
|
|
for (;;) {
|
|
if (stat(".", &d) == -1) {
|
|
(void) xsnprintf(pathname, pathlen, CGETS(23, 24,
|
|
"getcwd: Cannot stat \".\" (%s)"), strerror(errno));
|
|
goto fail;
|
|
}
|
|
if (d.st_ino == rino && d.st_dev == rdev && d.st_size == rsize)
|
|
break; /* reached root directory */
|
|
if ((dirp = opendir("..")) == NULL) {
|
|
(void) xsnprintf(pathname, pathlen, CGETS(23, 19,
|
|
"getcwd: Cannot open \"..\" (%s)"), strerror(errno));
|
|
goto fail;
|
|
}
|
|
if (chdir("..") == -1) {
|
|
(void) xsnprintf(pathname, pathlen, CGETS(23, 20,
|
|
"getcwd: Cannot chdir to \"..\" (%s)"), strerror(errno));
|
|
goto fail;
|
|
}
|
|
do {
|
|
if ((dir = readdir(dirp)) == NULL) {
|
|
(void) xsnprintf(pathname, pathlen,
|
|
CGETS(23, 21, "getcwd: Read error in \"..\" (%s)"),
|
|
strerror(errno));
|
|
goto fail;
|
|
}
|
|
if (stat(dir->d_name, &dd) == -1) {
|
|
(void) xsnprintf(pathname, pathlen,
|
|
CGETS(23, 25, "getcwd: Cannot stat directory \"%s\" (%s)"),
|
|
dir->d_name, strerror(errno));
|
|
goto fail;
|
|
}
|
|
} while (dd.st_ino != d.st_ino ||
|
|
dd.st_dev != d.st_dev ||
|
|
dd.st_size != d.st_size);
|
|
closedir(dirp);
|
|
dirp = NULL;
|
|
pnptr = strnrcpy(dirp->d_name, pnptr, pnptr - pathbuf);
|
|
pnptr = strnrcpy("/", pnptr, pnptr - pathbuf);
|
|
}
|
|
|
|
if (*pnptr == '\0') /* current dir == root dir */
|
|
(void) strncpy(pathname, "/", pathlen);
|
|
else {
|
|
(void) strncpy(pathname, pnptr, pathlen);
|
|
pathname[pathlen - 1] = '\0';
|
|
if (chdir(pnptr) == -1) {
|
|
(void) xsnprintf(pathname, MAXPATHLEN, CGETS(23, 22,
|
|
"getcwd: Cannot change back to \".\" (%s)"),
|
|
strerror(errno));
|
|
return NULL;
|
|
}
|
|
}
|
|
return pathname;
|
|
|
|
fail:
|
|
serrno = errno;
|
|
(void) chdir(strnrcpy(".", pnptr, pnptr - pathbuf));
|
|
errno = serrno;
|
|
return NULL;
|
|
}
|
|
|
|
# else /* ! hp9000s500 */
|
|
|
|
|
|
char *
|
|
xgetcwd(char *pathname, size_t pathlen)
|
|
{
|
|
DIR *dp;
|
|
struct dirent *d;
|
|
|
|
struct stat st_root, st_cur, st_next, st_dotdot;
|
|
char pathbuf[MAXPATHLEN], nextpathbuf[MAXPATHLEN * 2];
|
|
char *pathptr, *nextpathptr, *cur_name_add;
|
|
int save_errno = 0;
|
|
|
|
/* find the inode of root */
|
|
if (stat("/", &st_root) == -1) {
|
|
(void) xsnprintf(pathname, pathlen, CGETS(23, 23,
|
|
"getcwd: Cannot stat \"/\" (%s)"),
|
|
strerror(errno));
|
|
return NULL;
|
|
}
|
|
pathbuf[MAXPATHLEN - 1] = '\0';
|
|
pathptr = &pathbuf[MAXPATHLEN - 1];
|
|
nextpathbuf[MAXPATHLEN - 1] = '\0';
|
|
cur_name_add = nextpathptr = &nextpathbuf[MAXPATHLEN - 1];
|
|
|
|
/* find the inode of the current directory */
|
|
if (lstat(".", &st_cur) == -1) {
|
|
(void) xsnprintf(pathname, pathlen, CGETS(23, 24,
|
|
"getcwd: Cannot stat \".\" (%s)"),
|
|
strerror(errno));
|
|
return NULL;
|
|
}
|
|
nextpathptr = strnrcpy(nextpathptr, "../", nextpathptr - nextpathbuf);
|
|
|
|
/* Descend to root */
|
|
for (;;) {
|
|
|
|
/* look if we found root yet */
|
|
if (st_cur.st_ino == st_root.st_ino &&
|
|
DEV_DEV_COMPARE(st_cur.st_dev, st_root.st_dev)) {
|
|
(void) strncpy(pathname, *pathptr != '/' ? "/" : pathptr, pathlen);
|
|
pathname[pathlen - 1] = '\0';
|
|
return pathname;
|
|
}
|
|
|
|
/* open the parent directory */
|
|
if (stat(nextpathptr, &st_dotdot) == -1) {
|
|
(void) xsnprintf(pathname, pathlen, CGETS(23, 25,
|
|
"getcwd: Cannot stat directory \"%s\" (%s)"),
|
|
nextpathptr, strerror(errno));
|
|
return NULL;
|
|
}
|
|
if ((dp = opendir(nextpathptr)) == NULL) {
|
|
(void) xsnprintf(pathname, pathlen, CGETS(23, 26,
|
|
"getcwd: Cannot open directory \"%s\" (%s)"),
|
|
nextpathptr, strerror(errno));
|
|
return NULL;
|
|
}
|
|
|
|
/* look in the parent for the entry with the same inode */
|
|
if (DEV_DEV_COMPARE(st_dotdot.st_dev, st_cur.st_dev)) {
|
|
/* Parent has same device. No need to stat every member */
|
|
for (d = readdir(dp); d != NULL; d = readdir(dp)) {
|
|
#ifdef __clipper__
|
|
if (((unsigned long)d->d_ino & 0xffff) == st_cur.st_ino)
|
|
break;
|
|
#else
|
|
if (d->d_ino == st_cur.st_ino)
|
|
break;
|
|
#endif
|
|
}
|
|
}
|
|
else {
|
|
/*
|
|
* Parent has a different device. This is a mount point so we
|
|
* need to stat every member
|
|
*/
|
|
for (d = readdir(dp); d != NULL; d = readdir(dp)) {
|
|
if (ISDOT(d->d_name) || ISDOTDOT(d->d_name))
|
|
continue;
|
|
(void)strncpy(cur_name_add, d->d_name,
|
|
(size_t) (&nextpathbuf[sizeof(nextpathbuf) - 1] - cur_name_add));
|
|
if (lstat(nextpathptr, &st_next) == -1) {
|
|
/*
|
|
* We might not be able to stat() some path components
|
|
* if we are using afs, but this is not an error as
|
|
* long as we find the one we need; we also save the
|
|
* first error to report it if we don't finally succeed.
|
|
*/
|
|
if (save_errno == 0)
|
|
save_errno = errno;
|
|
continue;
|
|
}
|
|
/* check if we found it yet */
|
|
if (st_next.st_ino == st_cur.st_ino &&
|
|
DEV_DEV_COMPARE(st_next.st_dev, st_cur.st_dev))
|
|
break;
|
|
}
|
|
}
|
|
if (d == NULL) {
|
|
(void) xsnprintf(pathname, pathlen, CGETS(23, 27,
|
|
"getcwd: Cannot find \".\" in \"..\" (%s)"),
|
|
strerror(save_errno ? save_errno : ENOENT));
|
|
closedir(dp);
|
|
return NULL;
|
|
}
|
|
else
|
|
save_errno = 0;
|
|
st_cur = st_dotdot;
|
|
pathptr = strnrcpy(pathptr, d->d_name, pathptr - pathbuf);
|
|
pathptr = strnrcpy(pathptr, "/", pathptr - pathbuf);
|
|
nextpathptr = strnrcpy(nextpathptr, "../", nextpathptr - nextpathbuf);
|
|
*cur_name_add = '\0';
|
|
closedir(dp);
|
|
}
|
|
} /* end getcwd */
|
|
# endif /* hp9000s500 */
|
|
|
|
/* strnrcpy():
|
|
* Like strncpy, going backwards and returning the new pointer
|
|
*/
|
|
static char *
|
|
strnrcpy(char *ptr, char *str, size_t siz)
|
|
{
|
|
int len = strlen(str);
|
|
if (siz == 0)
|
|
return ptr;
|
|
|
|
while (len && siz--)
|
|
*--ptr = str[--len];
|
|
|
|
return (ptr);
|
|
} /* end strnrcpy */
|
|
#endif /* !HAVE_GETCWD */
|
|
|
|
#ifdef apollo
|
|
/***
|
|
*** Domain/OS
|
|
***/
|
|
#include <apollo/base.h>
|
|
#include <apollo/loader.h>
|
|
#include <apollo/error.h>
|
|
|
|
|
|
static char *
|
|
apperr(status_$t *st)
|
|
{
|
|
static char *buf; /* = NULL */
|
|
short e_subl, e_modl, e_codel;
|
|
error_$string_t e_sub, e_mod, e_code;
|
|
|
|
error_$get_text(*st, e_sub, &e_subl, e_mod, &e_modl, e_code, &e_codel);
|
|
e_sub[e_subl] = '\0';
|
|
e_code[e_codel] = '\0';
|
|
e_mod[e_modl] = '\0';
|
|
xfree(buf);
|
|
buf = xasprintf("%s (%s/%s)", e_code, e_sub, e_mod);
|
|
|
|
return(buf);
|
|
}
|
|
|
|
static int
|
|
llib(Char *s)
|
|
{
|
|
short len = Strlen(s);
|
|
status_$t st;
|
|
char *t;
|
|
|
|
loader_$inlib(t = short2str(s), len, &st);
|
|
if (st.all != status_$ok)
|
|
stderror(ERR_SYSTEM, t, apperr(&st));
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
doinlib(Char **v, struct command *c)
|
|
{
|
|
Char **globbed;
|
|
|
|
setname(short2str(*v++));
|
|
v = glob_all_or_error(v);
|
|
globbed = v;
|
|
cleanup_push(globbed, blk_cleanup);
|
|
|
|
while (v && *v)
|
|
llib(*v++);
|
|
cleanup_until(globbed);
|
|
}
|
|
|
|
int
|
|
getv(Char *v)
|
|
{
|
|
if (eq(v, STRbsd43))
|
|
return(1);
|
|
else if (eq(v, STRsys53))
|
|
return(0);
|
|
else
|
|
stderror(ERR_NAME | ERR_SYSTEM, short2str(v),
|
|
CGETS(23, 28, "Invalid system type"));
|
|
/*NOTREACHED*/
|
|
return(0);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
dover(Char **v, struct command *c)
|
|
{
|
|
Char *p;
|
|
|
|
setname(short2str(*v++));
|
|
if (!*v) {
|
|
if (!(p = tgetenv(STRSYSTYPE)))
|
|
stderror(ERR_NAME | ERR_STRING,
|
|
CGETS(23, 29, "System type is not set"));
|
|
xprintf("%S\n", p);
|
|
}
|
|
else {
|
|
tsetenv(STRSYSTYPE, getv(*v) ? STRbsd43 : STRsys53);
|
|
dohash(NULL, NULL);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Many thanks to rees@citi.umich.edu (Jim Rees) and
|
|
* mathys@ssdt-tempe.sps.mot.com (Yves Mathys)
|
|
* For figuring out how to do this... I could have never done
|
|
* it without their help.
|
|
*/
|
|
typedef short enum {
|
|
name_$wdir_type,
|
|
name_$ndir_type,
|
|
name_$node_dir_type,
|
|
} name_$dir_type_t;
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
dorootnode(Char **v, struct command *c)
|
|
{
|
|
name_$dir_type_t dirtype = name_$node_dir_type;
|
|
uid_$t uid;
|
|
status_$t st;
|
|
char *name;
|
|
short namelen;
|
|
|
|
setname(short2str(*v++));
|
|
|
|
name = short2str(*v);
|
|
namelen = strlen(name);
|
|
|
|
name_$resolve(name, &namelen, &uid, &st);
|
|
if (st.all != status_$ok)
|
|
stderror(ERR_SYSTEM, name, apperr(&st));
|
|
namelen = 0;
|
|
name_$set_diru(&uid, "", &namelen, &dirtype, &st);
|
|
if (st.all != status_$ok)
|
|
stderror(ERR_SYSTEM, name, apperr(&st));
|
|
dohash(NULL, NULL);
|
|
}
|
|
|
|
int
|
|
isapad(void)
|
|
{
|
|
static int res = -1;
|
|
static status_$t st;
|
|
|
|
if (res == -1) {
|
|
int strm;
|
|
if (isatty(0))
|
|
strm = 0;
|
|
if (isatty(1))
|
|
strm = 1;
|
|
if (isatty(2))
|
|
strm = 2;
|
|
else {
|
|
res = 0;
|
|
st.all = status_$ok;
|
|
return(res);
|
|
}
|
|
res = stream_$isavt(&strm, &st);
|
|
res = res ? 1 : 0;
|
|
}
|
|
else {
|
|
if (st.all != status_$ok)
|
|
stderror(ERR_SYSTEM, "stream_$isavt", apperr(&st));
|
|
}
|
|
return(res);
|
|
}
|
|
#endif
|