ARG_MAX
| Shells
| portability
| permissions
| UUOC
| ancient
| -
| ../Various
| HOME
$() vs )
| IFS
| using siginfo
| nanosleep
| line charset
| locale
Back to the main page.
I am glad that the following is available in the
TUHS
Research Unix archive.
The source code was released by Alcatel-Lucent with a
Statement Regarding Research Unix Editions 8, 9, and 10 about non-commercial usage.
Here are extracts from 8th edition
/usr/sys/h/user.h and
/usr/src/sys/sys1.c
with some arbitrary emphasis in bold face.
user.h:
#define SHSIZE 32
struct user
{
[...]
union {
struct { /* header of executable file */
int Ux_mag; /* magic number */
unsigned Ux_tsize; /* text size */
unsigned Ux_dsize; /* data size */
unsigned Ux_bsize; /* bss size */
unsigned Ux_ssize; /* symbol table size */
unsigned Ux_entloc; /* entry location */
unsigned Ux_unused;
unsigned Ux_relflg;
} Ux_A;
char ux_shell[SHSIZE]; /* #! and name of interpreter */
} u_exdata;
[...]
};
sys1.c
/*
* exec system call, with and without environments.
*/
struct execa {
char *fname;
char **argp;
char **envp;
};
exec()
{
((struct execa *)u.u_ap)->envp = NULL;
exece();
}
struct shdata {
struct direct sd_save;
int sd_gid;
int sd_uid;
int sd_indir;
char sd_flag[SHSIZE];
};
struct swargs {
char *sw_cp;
int sw_argc;
int sw_envc;
int sw_chars;
int sw_bn;
struct buf *sw_bp;
};
[...]
exece()
{
register int i;
register int ap;
register int bsize;
register char *cp;
register char *ucp;
register struct execa *uap;
struct buf *bp;
struct inode *ip;
struct shdata sh;
struct swargs sw;
extern struct inode *gethead();
sh.sd_uid = u.u_uid;
sh.sd_gid = u.u_gid;
sh.sd_indir = 0;
sh.sd_flag[0] = '\0';
if ((ip = gethead(&sh)) == NULL)
return;
[...]
}
/*
* Get a shell after #! magic number.
*/
struct inode *
getshell(ip, sp)
struct inode *ip;
struct shdata *sp;
{
register char *cp;
extern struct inode *gethead();
if(u.u_exdata.ux_shell[0] != '#' || u.u_exdata.ux_shell[1] != '!' || sp->sd_indir)
goto error;
cp = &u.u_exdata.ux_shell[2];
for (;;) {
if (cp == &u.u_exdata.ux_shell[SHSIZE])
goto error;
if (*cp == '\n') {
*cp = '\0';
break;
}
if (*cp == '\t')
*cp = ' ';
cp++;
}
for (cp = &u.u_exdata.ux_shell[2]; *cp == ' '; cp++);
if (*cp == '\0')
goto error;
u.u_dirp = cp;
while (*cp != '\0') {
if (*cp == ' ') {
*cp++ = '\0';
while (*cp == ' ')
cp++;
/*
* Shell argument (one only).
*/
if (*cp != '\0') {
register int i;
i = 0;
do
sp->sd_flag[i++] = *cp++;
while (*cp != ' ' && *cp != '\0');
sp->sd_flag[i] = '\0';
}
break;
}
else
cp++;
}
iput(ip);
sp->sd_save = u.u_dent;
sp->sd_indir = 1;
return gethead(sp);
error:
iput(ip);
u.u_error = ENOEXEC;
return NULL;
}
/*
* Get the header of an executable and do all the right tests.
*/
struct inode *
gethead(sp)
struct shdata *sp;
{
register struct inode *ip;
if ((ip = namei(sp->sd_indir ? schar : uchar, 0, 1)) == NULL)
return NULL;
/*
* Setuid and setgid denied for network root.
*/
if ((ip->i_mode & ISUID) != 0 && ip->i_uid != -1)
sp->sd_uid = ip->i_uid;
if ((ip->i_mode & ISGID) != 0 && ip->i_gid != -1)
sp->sd_gid = ip->i_gid;
/*
* Check permission. May not trace something we can't read.
*/
if(access(ip, IEXEC) || (PTRACED(u.u_procp) && access(ip, IREAD)))
goto out;
/*
* Must be a regular file and must really be executable.
*/
if ((ip->i_mode & IFMT) != IFREG ||
(ip->i_mode & (IEXEC | (IEXEC >> 3) | (IEXEC >> 6))) == 0) {
u.u_error = EACCES;
goto out;
}
/*
* ux_mag = 407/410/413
* 407 is plain executable
* 410 is RO text
* 413 is demand paged RO text
*
* Also an ASCII line beginning with #! is
* the file name of a ``shell'' and arguments may be prepended
* to the argument list if given here.
*
* Shell names are limited in length.
*
* Only one argument may be passed to the shell from the ASCII line.
*/
u.u_base = (caddr_t)&u.u_exdata;
u.u_count = sizeof(u.u_exdata);
u.u_offset = 0;
u.u_segflg = 1;
readi(ip);
u.u_segflg = 0;
if (u.u_error)
goto out;
if (u.u_count > sizeof (u.u_exdata) - sizeof (u.u_exdata.Ux_A))
ip = getshell(ip, sp);
else {
switch (u.u_exdata.ux_mag) {
case 0407:
u.u_exdata.ux_dsize += u.u_exdata.ux_tsize;
u.u_exdata.ux_tsize = 0;
break;
case 0410:
case 0413:
if (u.u_exdata.ux_tsize == 0)
u.u_error = ENOEXEC;
break;
default:
ip = getshell(ip, sp);
}
}
out:
if (u.u_error && ip != NULL) {
iput(ip);
ip = NULL;
}
return ip;
}
[...]