mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-03-09 15:50:02 +00:00
This commit fixes 'command -x' to adapt to OS limitations with
regards to data alignment in the arguments list. A feature test is
added that detects if the OS aligns the argument on 32-bit or
64-bit boundaries or not at all, allowing 'command -x' to avoid
E2BIG errors while maximising efficiency.
Also, as of now, 'command -x' is a way to bypass built-ins and
run/query an external command. Built-ins do not limit the length of
their argument list, so '-x' never made sense to use for them. And
because '-x' hangs on Linux and macOS on every ksh93 release
version to date (see acf84e96
), few use it, so there is little
reason not to make this change.
Finally, this fixes a longstanding bug that caused the minimum exit
status of 'command -x' to be 1 if a command with many arguments was
divided into several command invocations. This is done by replacing
broken flaggery with a new SH_XARG state flag bit.
src/cmd/ksh93/features/externs:
- Add new C feature test detecting byte alignment in args list.
The test writes a #define ARG_ALIGN_BYTES with the amount of
bytes the OS aligns arguments to, or zero for no alignment.
src/cmd/ksh93/include/defs.h:
- Add new SH_XARG state bit indicating 'command -x' is active.
src/cmd/ksh93/sh/path.c: path_xargs():
- Leave extra 2k in the args buffer instead of 1k, just to be sure;
some commands add large environment variables these days.
- Fix a bug in subtracting the length of existing arguments and
environment variables. 'size -= strlen(cp)-1;' subtracts one less
than the size of cp, which makes no sense; what is necessary is
to substract the length plus one to account for the terminating
zero byte, i.e.: 'size -= strlen(cp)+1'.
- Use the ARG_ALIGN_BYTES feature test result to match the OS's
data alignment requirements.
- path_spawn(): E2BIG: Change to checking SH_XARG state bit.
src/cmd/ksh93/bltins/whence.c: b_command():
- Allow combining -x with -p, -v and -V with the expected results
by setting P_FLAG to act like 'whence -p'. E.g., as of now,
command -xv printf
is equivalent to
whence -p printf
but note that 'whence' has no equivalent of 'command -pvx printf'
which searches $(getconf PATH) for a command.
- When -x will run a command, now set the new SH_XARG state flag.
src/cmd/ksh93/sh/xec.c: sh_exec():
- Change to using the new SH_XARG state bit.
- Skip the check for built-ins if SH_XARG is active, so that
'command -x' now always runs an external command.
src/lib/libcmd/date.c, src/lib/libcmd/uname.c:
- These path-bound builtins sometimes need to run the external
system command by the same name, but they did that by hardcoding
an unportable direct path. Now that 'command -x' runs an external
command, change this to using 'command -px' to guarantee using
the known-good external system utility in the default PATH.
- In date.c, fix the format string passed to 'command -px date'
when setting the date; it was only compatible with BSD systems.
Use the POSIX variant on non-BSD systems.
514 lines
12 KiB
C
514 lines
12 KiB
C
/***********************************************************************
|
|
* *
|
|
* This software is part of the ast package *
|
|
* Copyright (c) 1992-2012 AT&T Intellectual Property *
|
|
* and is licensed under the *
|
|
* Eclipse Public License, Version 1.0 *
|
|
* by AT&T Intellectual Property *
|
|
* *
|
|
* A copy of the License is available at *
|
|
* http://www.eclipse.org/org/documents/epl-v10.html *
|
|
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
|
|
* *
|
|
* Information and Software Systems Research *
|
|
* AT&T Research *
|
|
* Florham Park NJ *
|
|
* *
|
|
* Glenn Fowler <gsf@research.att.com> *
|
|
* David Korn <dgk@research.att.com> *
|
|
* *
|
|
***********************************************************************/
|
|
#pragma prototyped
|
|
/*
|
|
* David Korn
|
|
* Glenn Fowler
|
|
* AT&T Research
|
|
*
|
|
* uname
|
|
*/
|
|
|
|
static const char usage[] =
|
|
"[-?\n@(#)$Id: uname (AT&T Research) 2007-04-19 $\n]"
|
|
USAGE_LICENSE
|
|
"[+NAME?uname - identify the current system ]"
|
|
"[+DESCRIPTION?By default \buname\b writes the operating system name to"
|
|
" standard output. When options are specified, one or more"
|
|
" system characteristics are written to standard output, space"
|
|
" separated, on a single line. When more than one option is specified"
|
|
" the output is in the order specified by the \b-A\b option below."
|
|
" Unsupported option values are listed as \a[option]]\a. If any unknown"
|
|
" options are specified, the OS default \buname\b(1) is called.]"
|
|
"[+?If any \aname\a operands are specified then the \bsysinfo\b(2) values"
|
|
" for each \aname\a are listed, separated by space, on one line."
|
|
" \bgetconf\b(1), a pre-existing \astandard\a interface, provides"
|
|
" access to the same information; vendors should spend more time"
|
|
" using standards than inventing them.]"
|
|
"[+?Selected information is printed in the same order as the options below.]"
|
|
"[a:all?Equivalent to \b-snrvmpio\b.]"
|
|
"[s:system|sysname|kernel-name?The detailed kernel name. This is the default.]"
|
|
"[n:nodename?The hostname or nodename.]"
|
|
"[r:release|kernel-release?The kernel release level.]"
|
|
"[v:version|kernel-version?The kernel version level.]"
|
|
"[m:machine?The name of the hardware type the system is running on.]"
|
|
"[p:processor?The name of the processor instruction set architecture.]"
|
|
"[i:implementation|platform|hardware-platform?The hardware implementation;"
|
|
" this is \b--host-id\b on some systems.]"
|
|
"[o:operating-system?The generic operating system name.]"
|
|
"[h:host-id|id?The host id in hex.]"
|
|
"[d:domain?The domain name returned by \agetdomainname\a(2).]"
|
|
"[R:extended-release?The extended release name.]"
|
|
"[A:everything?Equivalent to \b-snrvmpiohdR\b.]"
|
|
"[f:list?List all \bsysinfo\b(2) names and values, one per line.]"
|
|
"[S:sethost?Set the hostname or nodename to \aname\a. No output is"
|
|
" written to standard output.]:[name]"
|
|
"\n"
|
|
"\n[ name ... ]\n"
|
|
"\n"
|
|
"[+SEE ALSO?\bhostname\b(1), \bgetconf\b(1), \buname\b(2),"
|
|
" \bsysconf\b(2), \bsysinfo\b(2)]"
|
|
;
|
|
|
|
#if defined(__STDPP__directive) && defined(__STDPP__hide)
|
|
__STDPP__directive pragma pp:hide getdomainname gethostid gethostname sethostname
|
|
#else
|
|
#define getdomainname ______getdomainname
|
|
#define gethostid ______gethostid
|
|
#define gethostname ______gethostname
|
|
#define sethostname ______sethostname
|
|
#endif
|
|
|
|
#include <cmd.h>
|
|
#include <ctype.h>
|
|
#include <proc.h>
|
|
|
|
#include "FEATURE/utsname"
|
|
|
|
#define MAXHOSTNAME 64
|
|
|
|
#if _lib_uname && _sys_utsname
|
|
|
|
#include <sys/utsname.h>
|
|
|
|
#endif
|
|
|
|
#if defined(__STDPP__directive) && defined(__STDPP__hide)
|
|
__STDPP__directive pragma pp:nohide getdomainname gethostid gethostname sethostname
|
|
#else
|
|
#undef getdomainname
|
|
#undef gethostid
|
|
#undef gethostname
|
|
#undef sethostname
|
|
#endif
|
|
|
|
#if _lib_getdomainname
|
|
extern int getdomainname(char*, size_t);
|
|
#endif
|
|
#if _lib_gethostid
|
|
extern long gethostid(void);
|
|
#endif
|
|
#if _lib_gethostname
|
|
extern int gethostname(char*, size_t);
|
|
#endif
|
|
#if _lib_sethostname
|
|
extern int sethostname(const char*, size_t);
|
|
#endif
|
|
|
|
#ifndef HOSTTYPE
|
|
#define HOSTTYPE "unknown"
|
|
#endif
|
|
|
|
static const char hosttype[] = HOSTTYPE;
|
|
|
|
#if !_lib_uname || !_sys_utsname
|
|
|
|
#if defined(__STDPP__)
|
|
#define SYSNAME #(getprd machine)
|
|
#define RELEASE #(getprd release)
|
|
#define VERSION #(getprd version)
|
|
#define MACHINE #(getprd architecture)
|
|
#else
|
|
#define SYSNAME ""
|
|
#define RELEASE ""
|
|
#define VERSION ""
|
|
#define MACHINE ""
|
|
#endif
|
|
|
|
struct utsname
|
|
{
|
|
char* sysname;
|
|
char nodename[MAXHOSTNAME];
|
|
char* release;
|
|
char* version;
|
|
char* machine;
|
|
};
|
|
|
|
int
|
|
uname(register struct utsname* ut)
|
|
{
|
|
#ifdef HOSTTYPE
|
|
char* sys = 0;
|
|
char* arch = 0;
|
|
|
|
if (*hosttype)
|
|
{
|
|
static char buf[sizeof(hosttype)];
|
|
|
|
strcpy(buf, hosttype);
|
|
sys = buf;
|
|
if (arch = strchr(sys, '.'))
|
|
{
|
|
*arch++ = 0;
|
|
if (!*arch)
|
|
arch = 0;
|
|
}
|
|
if (!*sys)
|
|
sys = 0;
|
|
}
|
|
#endif
|
|
#ifdef _lib_gethostname
|
|
if (gethostname(ut->nodename, sizeof(ut->nodename) - 1))
|
|
return -1;
|
|
#else
|
|
strncpy(ut->nodename, "local", sizeof(ut->nodename) - 1);
|
|
#endif
|
|
#ifdef HOSTTYPE
|
|
if (!(ut->sysname = sys))
|
|
#endif
|
|
if (!*(ut->sysname = SYSNAME))
|
|
ut->sysname = ut->nodename;
|
|
#ifdef HOSTTYPE
|
|
if (!(ut->machine = arch))
|
|
#endif
|
|
ut->machine = MACHINE;
|
|
ut->release = RELEASE;
|
|
ut->version = VERSION;
|
|
return 0;
|
|
}
|
|
|
|
#endif
|
|
|
|
#define OPT_system (1<<0)
|
|
#define OPT_nodename (1<<1)
|
|
#define OPT_release (1<<2)
|
|
#define OPT_version (1<<3)
|
|
#define OPT_machine (1<<4)
|
|
#define OPT_processor (1<<5)
|
|
|
|
#define OPT_STANDARD 6
|
|
|
|
#define OPT_implementation (1<<6)
|
|
#define OPT_operating_system (1<<7)
|
|
|
|
#define OPT_ALL 8
|
|
|
|
#define OPT_hostid (1<<8)
|
|
#define OPT_vendor (1<<9)
|
|
#define OPT_domain (1<<10)
|
|
#define OPT_machine_type (1<<11)
|
|
#define OPT_base (1<<12)
|
|
#define OPT_extended_release (1<<13)
|
|
#define OPT_extra (1<<14)
|
|
|
|
#define OPT_TOTAL 15
|
|
|
|
#define OPT_all (1L<<29)
|
|
#define OPT_total (1L<<30)
|
|
#define OPT_standard ((1<<OPT_STANDARD)-1)
|
|
|
|
#ifndef MACHINE
|
|
#if defined(__STDPP__)
|
|
#define MACHINE #(getprd architecture)
|
|
#else
|
|
#define MACHINE ""
|
|
#endif
|
|
#endif
|
|
|
|
#ifndef HOSTTYPE
|
|
#define HOSTTYPE "unknown"
|
|
#endif
|
|
|
|
#define extra(m) do \
|
|
{ \
|
|
if ((char*)&ut.m[sizeof(ut.m)] > last) \
|
|
last = (char*)&ut.m[sizeof(ut.m)]; \
|
|
} while(0)
|
|
|
|
#define output(f,v,u) do \
|
|
{ \
|
|
if ((flags&(f))&&(*(v)||(flags&(OPT_all|OPT_total))==OPT_all&&((f)&OPT_standard)||!(flags&(OPT_all|OPT_total)))) \
|
|
{ \
|
|
if (sep) \
|
|
sfputc(sfstdout, ' '); \
|
|
else \
|
|
sep = 1; \
|
|
if (*(v)) \
|
|
sfputr(sfstdout, v, -1); \
|
|
else \
|
|
sfprintf(sfstdout, "[%s]", u); \
|
|
} \
|
|
} while (0)
|
|
|
|
int
|
|
b_uname(int argc, char** argv, Shbltin_t* context)
|
|
{
|
|
register long flags = 0;
|
|
register int sep = 0;
|
|
register int n;
|
|
register char* s;
|
|
char* t;
|
|
char* e;
|
|
char* sethost = 0;
|
|
int list = 0;
|
|
struct utsname ut;
|
|
char buf[257];
|
|
|
|
cmdinit(argc, argv, context, ERROR_CATALOG, 0);
|
|
for (;;)
|
|
{
|
|
switch (optget(argv, usage))
|
|
{
|
|
case 'a':
|
|
flags |= OPT_all|((1L<<OPT_ALL)-1);
|
|
continue;
|
|
case 'b':
|
|
flags |= OPT_base;
|
|
continue;
|
|
case 'c':
|
|
flags |= OPT_vendor;
|
|
continue;
|
|
case 'd':
|
|
flags |= OPT_domain;
|
|
continue;
|
|
case 'f':
|
|
list = 1;
|
|
continue;
|
|
case 'h':
|
|
flags |= OPT_hostid;
|
|
continue;
|
|
case 'i':
|
|
flags |= OPT_implementation;
|
|
continue;
|
|
case 'm':
|
|
flags |= OPT_machine;
|
|
continue;
|
|
case 'n':
|
|
flags |= OPT_nodename;
|
|
continue;
|
|
case 'o':
|
|
flags |= OPT_operating_system;
|
|
continue;
|
|
case 'p':
|
|
flags |= OPT_processor;
|
|
continue;
|
|
case 'r':
|
|
flags |= OPT_release;
|
|
continue;
|
|
case 's':
|
|
flags |= OPT_system;
|
|
continue;
|
|
case 't':
|
|
flags |= OPT_machine_type;
|
|
continue;
|
|
case 'v':
|
|
flags |= OPT_version;
|
|
continue;
|
|
case 'x':
|
|
flags |= OPT_extra;
|
|
continue;
|
|
case 'A':
|
|
flags |= OPT_total|((1L<<OPT_TOTAL)-1);
|
|
continue;
|
|
case 'R':
|
|
flags |= OPT_extended_release;
|
|
continue;
|
|
case 'S':
|
|
sethost = opt_info.arg;
|
|
continue;
|
|
case ':':
|
|
{
|
|
char **new_argv = (char **)stakalloc((argc + 3) * sizeof(char*));
|
|
new_argv[0] = "command";
|
|
new_argv[1] = "-px";
|
|
for (n = 0; n <= argc; n++)
|
|
new_argv[n + 2] = argv[n];
|
|
return sh_run(context, argc + 2, new_argv);
|
|
}
|
|
case '?':
|
|
error(ERROR_usage(2), "%s", opt_info.arg);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
argv += opt_info.index;
|
|
if (error_info.errors || *argv && (flags || sethost) || sethost && flags)
|
|
error(ERROR_usage(2), "%s", optusage(NiL));
|
|
if (sethost)
|
|
{
|
|
#if _lib_sethostname
|
|
if (sethostname(sethost, strlen(sethost) + 1))
|
|
#else
|
|
#ifdef ENOSYS
|
|
errno = ENOSYS;
|
|
#else
|
|
errno = EPERM;
|
|
#endif
|
|
#endif
|
|
error(ERROR_system(1), "%s: cannot set host name", sethost);
|
|
}
|
|
else if (list)
|
|
astconflist(sfstdout, NiL, ASTCONF_base|ASTCONF_defined|ASTCONF_lower|ASTCONF_quote|ASTCONF_matchcall, "CS|SI");
|
|
else if (*argv)
|
|
{
|
|
e = &buf[sizeof(buf)-1];
|
|
while (s = *argv++)
|
|
{
|
|
t = buf;
|
|
*t++ = 'C';
|
|
*t++ = 'S';
|
|
*t++ = '_';
|
|
while (t < e && (n = *s++))
|
|
*t++ = islower(n) ? toupper(n) : n;
|
|
*t = 0;
|
|
sfprintf(sfstdout, "%s%c", *(t = astconf(buf, NiL, NiL)) ? t : *(t = astconf(buf+3, NiL, NiL)) ? t : "unknown", *argv ? ' ' : '\n');
|
|
}
|
|
}
|
|
else
|
|
{
|
|
s = buf;
|
|
if (!flags)
|
|
flags = OPT_system;
|
|
memzero(&ut, sizeof(ut));
|
|
if (uname(&ut) < 0)
|
|
error(ERROR_usage(2), "information unavailable");
|
|
output(OPT_system, ut.sysname, "sysname");
|
|
if (flags & OPT_nodename)
|
|
{
|
|
#if !_mem_nodeext_utsname && _lib_gethostname
|
|
if (sizeof(ut.nodename) > 9 || gethostname(s, sizeof(buf)))
|
|
#endif
|
|
s = ut.nodename;
|
|
output(OPT_nodename, s, "nodename");
|
|
}
|
|
output(OPT_release, ut.release, "release");
|
|
output(OPT_version, ut.version, "version");
|
|
output(OPT_machine, ut.machine, "machine");
|
|
if (flags & OPT_processor)
|
|
{
|
|
if (!*(s = astconf("ARCHITECTURE", NiL, NiL)))
|
|
s = ut.machine;
|
|
output(OPT_processor, s, "processor");
|
|
}
|
|
if (flags & OPT_implementation)
|
|
{
|
|
if (!*(s = astconf("PLATFORM", NiL, NiL)) && !*(s = astconf("HW_NAME", NiL, NiL)))
|
|
{
|
|
if (t = strchr(hosttype, '.'))
|
|
t++;
|
|
else
|
|
t = (char*)hosttype;
|
|
strncpy(s = buf, t, sizeof(buf) - 1);
|
|
}
|
|
output(OPT_implementation, s, "implementation");
|
|
}
|
|
if (flags & OPT_operating_system)
|
|
{
|
|
s = astconf("OPERATING_SYSTEM", NiL, NiL);
|
|
if (!*s)
|
|
#ifdef _UNAME_os_DEFAULT
|
|
s = _UNAME_os_DEFAULT;
|
|
#else
|
|
s = ut.sysname;
|
|
#endif
|
|
output(OPT_operating_system, s, "operating-system");
|
|
}
|
|
if (flags & OPT_extended_release)
|
|
{
|
|
s = astconf("RELEASE", NiL, NiL);
|
|
output(OPT_extended_release, s, "extended-release");
|
|
}
|
|
#if _mem_idnumber_utsname
|
|
output(OPT_hostid, ut.idnumber, "hostid");
|
|
#else
|
|
if (flags & OPT_hostid)
|
|
{
|
|
if (!*(s = astconf("HW_SERIAL", NiL, NiL)))
|
|
#if _lib_gethostid
|
|
sfsprintf(s = buf, sizeof(buf), "%08x", gethostid());
|
|
#else
|
|
/*NOP*/;
|
|
#endif
|
|
output(OPT_hostid, s, "hostid");
|
|
}
|
|
#endif
|
|
if (flags & OPT_vendor)
|
|
{
|
|
s = astconf("HW_PROVIDER", NiL, NiL);
|
|
output(OPT_vendor, s, "vendor");
|
|
}
|
|
if (flags & OPT_domain)
|
|
{
|
|
if (!*(s = astconf("SRPC_DOMAIN", NiL, NiL)))
|
|
#if _lib_getdomainname
|
|
getdomainname(s, sizeof(buf));
|
|
#else
|
|
/*NOP*/;
|
|
#endif
|
|
output(OPT_domain, s, "domain");
|
|
}
|
|
#if _mem_m_type_utsname
|
|
s = ut.m_type;
|
|
#else
|
|
s = astconf("MACHINE", NiL, NiL);
|
|
#endif
|
|
output(OPT_machine_type, s, "m_type");
|
|
#if _mem_base_rel_utsname
|
|
s = ut.base_rel;
|
|
#else
|
|
s = astconf("BASE", NiL, NiL);
|
|
#endif
|
|
output(OPT_base, s, "base_rel");
|
|
if (flags & OPT_extra)
|
|
{
|
|
char* last = (char*)&ut;
|
|
|
|
extra(sysname);
|
|
extra(nodename);
|
|
extra(release);
|
|
extra(version);
|
|
extra(machine);
|
|
#if _mem_idnumber_utsname
|
|
extra(idnumber);
|
|
#endif
|
|
#if _mem_m_type_utsname
|
|
extra(m_type);
|
|
#endif
|
|
#if _mem_base_rel_utsname
|
|
extra(base_rel);
|
|
#endif
|
|
if (last < ((char*)(&ut + 1)))
|
|
{
|
|
s = t = last;
|
|
while (s < (char*)(&ut + 1))
|
|
{
|
|
if (!(n = *s++))
|
|
{
|
|
if ((s - t) > 1)
|
|
{
|
|
if (sep)
|
|
sfputc(sfstdout, ' ');
|
|
else
|
|
sep = 1;
|
|
sfputr(sfstdout, t, -1);
|
|
}
|
|
t = s;
|
|
}
|
|
else if (!isprint(n))
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (sep)
|
|
sfputc(sfstdout, '\n');
|
|
}
|
|
return error_info.errors;
|
|
}
|