/*
* $Log: sys1.c,v $
* Revision 22.5 90/11/12 19:19:10 root
* Новые вещи для СМ1425 и перемещение include.
*
* Revision 22.4 89/07/01 20:13:46 avg
* Увеличен размер области свопинга, для которой начнут выполняться
* проверки.
*
* Revision 22.3 89/04/28 17:02:44 avg
* Добавлен #include "h/space.h" для вытаскивания констант SEMMNS и MSGMNI.
*
* Revision 22.2 89/04/12 15:36:09 korotaev
* "param.h" ==> <sys/param.h>
*
* Revision 22.1 89/04/02 13:33:09 abs
* заменил один anic на printf
*
* Revision 22.0 89/03/31 17:59:54 korotaev
* Begining DEMOS 2.2.
*
* Revision 1.12 89/03/03 14:16:12 abs
* semaphores
*
* Revision 1.11 89/02/09 16:36:59 abs
* механизм копирования аргументов при ШеллСкрипте переписан вообще на фиг !
*
* Revision 1.10 89/02/07 15:51:28 abs
* UCB_SHELLSCRIPT теперь имеет аргументы.
*
* Revision 1.9 89/02/04 18:51:33 avg
* Ускорено переключение пользовательских оверлеев.
*
* Revision 1.8 89/01/26 15:55:42 korotaev
* Уменьшены диагностики.
*
* Revision 1.7 89/01/07 20:56:57 korotaev
* Слияние с исправлениями насчет FIFO, +fcntl, + разные режимы открытия
*
* (from VAX/UTS SV.2)
*
* Revision 1.5 88/03/23 13:37:36 korotaev
* Состояние после слияния с АЗЛК, Э-85 и Бурковским планировщиком
*
* Revision 1.4 88/01/23 19:53:30 korotaev
* Состояние после слияния с AVG-Э-85.
*
* Revision 1.3 87/12/09 16:31:52 andrew
* 31 оверлей
*
* Revision 1.2 87/04/18 14:42:44 avg
* Правки в vfork by alex.
*
* Revision 1.1 86/04/19 15:52:28 avg
* Initial revision
*
*/
/* Структура стека сразу после exec-а :
----------------
| na-ne= argc
| a0
| ...
| an
| NULL
| e0
| ...
| em
| NULL
a0:| "argv0\0"
| ...
an:| "argvn\0"
e0:| "envp0\0"
| ...
em:| "envpm\0"
| 0
0:| пустой стек
-----
*/
#include <sys/param.h>
#include <sys/systm.h>
#include "../include/map.h"
#include <sys/dir.h>
#include <sys/user.h>
#include <sys/proc.h>
#include "../include/buf.h"
#include "../include/reg.h"
#include "../include/psw.h"
#include <sys/inode.h>
#include <sys/seg.h>
#include <sys/acct.h>
#include <sys/file.h>
#include <sys/wait.h>
#include "h/space.h" /* для SEMMNS */
extern panicreboot;
/*
* exec system call, with and without environments.
*/
struct execa {
char *fname;
char **argp;
char **envp;
};
exec()
{
((struct execa *)u.u_ap)->envp = NULL;
exece();
}
#define byteaddress int
exece()
{
register nc; /* общее число байт в argp и envp */
int na, /* число строк в argp и envp вместе */
ne, /* число строк в envp */
ucp,c;
byteaddress ap;
/* грязное место. В дальнейшем время от времени
* ap используется по разному: как char *
* как char ** и как int
*/
register char *cp;
register struct buf *bp;
register struct execa *uap;
memaddr bno;
struct inode *ip;
char *next;
#define AP (uap->argp)
#define EP (uap->envp)
# define SCRMAG "#!"
# define SCRMAG2 "/*#!"
# define ARGPLACE "$*"
# define SHSIZE 70
# define ARGV 11
char **AV;
extern int schar();
int uid, gid;
char indir, local;
off_t off;
char shellcmd[ SHSIZE ]; /* прочитанная команда */
char *argv[ ARGV ]; /* разобранная команда */
if ((ip = namei(uchar, LOOKUP, 1)) == NULL)
return;
#ifdef SCHED
u.u_procp->p_sflag |= SEXEC;
#endif SCHED
bno = 0;
bp = (struct buf *) NULL;
indir = 0;
uid = u.u_uid;
gid = u.u_gid;
if (ip->i_mode&ISUID)
uid = ip->i_uid;
if (ip->i_mode&ISGID)
gid = ip->i_gid;
again:
if (access(ip, IEXEC))
goto bad;
if ((ip->i_mode & IFMT) != IFREG ||
(ip->i_mode & (IEXEC | (IEXEC >> 3) | (IEXEC >> 6))) == 0) {
u.u_error = EACCES;
goto bad;
}
/* moved from getxfile() */
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 bad;
/* check if script. */
if (indir < NSYMLNK && u.u_offset > (off_t)2 ){
cp = (char *) &u.u_exdata;
if( !bcmp(cp, SCRMAG, 2 ))
off = (off_t) 2;
else if( u.u_offset > (off_t)4 && !bcmp( cp, SCRMAG2, 4))
off = (off_t) 4;
else goto NoScript;
/* да, имеется shell script */
indir++;
/* зачитать в буфер первые SHSIZE байт файла */
u.u_count = SHSIZE;
u.u_base = shellcmd;
u.u_offset= off;
u.u_segflg = 1;
readi( ip );
u.u_segflg = 0;
if( u.u_error )
goto bad;
iput( ip );
off = u.u_offset - off;
/* столько байт на самом деле прочлось внутрь */
/* обработка */
/* пока nc используется как временная переменная */
for( nc=0; nc < (int) off; nc++ )
if( shellcmd[ nc ] == '\n' ){
shellcmd[ nc] = '\0';
goto Parse;
}
Big:
/* строка слишком длинная */
u.u_error = E2BIG;
Ret:
# ifdef SCHED
u.u_procp->p_sflag &= ~SEXEC;
# endif SCHED
return;
Parse:
nc = 0;
cp = shellcmd;
for(;;){
/* пропуск пробелов */
while( *cp == ' ' ) cp++;
if( ! *cp ) break; /* конец строки */
if( nc == ARGV-1 ) goto Big;
argv[ nc++ ] = cp;
/* пропуск аргумента */
while( *cp && *cp != ' ' ) cp++;
if( ! *cp ) break;
*cp ++ = '\0';
}
argv[ nc ] = NULL;
if( !nc ){
u.u_error = EINVAL;
goto Ret;
}
u.u_dirp = argv[0];
/* смотрим, что лежит в указуемом файле */
if ((ip = namei(schar, LOOKUP, 1)) == NULL) {
# ifdef SCHED
u.u_procp->p_sflag &= ~SEXEC;
# endif SCHED
return;
}
goto again;
}
if( indir == NSYMLNK ){
u.u_error = ELOOP;
goto bad;
}
NoScript:
/*other magic numbers are described in getxfile()*/
/*
* Collect arguments on "file" in swap space.
* ip - locked ino of executable core image file.
*/
uap = (struct execa *)u.u_ap;
ap = na = ne = nc = 0;
/* заказать в своппинге место для размещения
* аргументов и окружения новой программы
*/
#ifndef UCB_NKB
if ((bno = malloc(swapmap, (NCARGS + BSIZE - 1) / BSIZE)) == 0) {
#else UCB_NKB
if ((bno = malloc(swapmap, ctod((int) btoc(NCARGS + BSIZE)))) == 0) {
#endif UCB_NKB
/* panicreboot++;
* panic("out of swap");
*/
printf( "misswap\n");
u.u_error = ENOSPC;
goto bad;
}
/* формат:
пусть есть файл /.../.../x
со следующим содержимым:
-------------------------------
|#!CMD A1 A2 A3
| .......
Вызываем команду:
x B1 B2
Запустится на самом деле такая команда:
CMD A1 A2 A3 /.../.../x B1 B2
Один из аргументов Ai может иметь вид $*
Тогда аргументы запуска подставятся на это место, а не в конец:
-------------------------------
|#!CMD A1 $* A2 A3
| .......
Вызываем:
x B1 B2
Запустится:
CMD A1 /.../.../x B1 B2 A2 A3
*/
if( indir ) AV = argv;
else AV = NULL;
/* цикл чтения сначала argp, затем envp в своппинг */
if ( AP ) for (;;) {
GetNext:
/* здесь ap используется как флаг, что можно
* брать аргументы из argv
*/
if( AV && ! ap ){
next = *AV++;
if( next == NULL ){
AV = NULL;
goto GetNext;
}
if( !bcmp( next, ARGPLACE, 2 ))
goto Argp;
local = 1;
}else
Argp: if( AP ){
next = fuword ( (caddr_t) AP++ );
if( next == NULL ){
AP = NULL;
ap = 0;
/* можно дочитывать argv,
* если еще осталось
*/
goto GetNext;
}
/* полное имя косвенного файла задаем как
* argp0 скриптовой программе.
*/
if( ap == 0 && indir )
next = (caddr_t) (uap->fname);
local = 0;
ap++; /* не ноль */
}else
if( EP ){
next = fuword( (caddr_t) EP++ );
if( next == NULL ) break;
local = 0;
ne++;
ap++;
}else
break;
/* число пересланных строк */
na++;
if (next == (char *)-1)
u.u_error = EFAULT;
/* Адрес строки сейчас хранится в next.
* Начинаем цикл пересылки строки в "файл" в своппинге
*/
do {
if (nc >= NCARGS - 1)
u.u_error = E2BIG;
if( local ){
/* строка - в пространстве ядра */
c = *next++;
c &= 0377;
} else
/* строка - в пространстве юзера */
if ((c = fubyte((caddr_t) next++)) < 0)
u.u_error = EFAULT;
if (u.u_error)
goto bad;
if ((nc & BMASK) == 0) {
if (bp) {
mapout(bp);
bdwrite(bp);
}
/* заказываем кэш-буфер для записи в
* "своппинговый файл"
*/
#ifndef UCB_NKB
bp = getblk(swapdev, swplo + bno + (nc >> BSHIFT));
#else
bp = getblk(swapdev,
dbtofsb(clrnd(swplo + bno)) + (nc >> BSHIFT));
#endif
cp = mapin(bp);
}
/* число засланных байтов ++ */
nc++;
/* заносим байт в кэш-буфер */
*cp++ = c;
} while (c > 0); /* пока не конец строки */
}
if (bp) {
mapout(bp);
bdwrite(bp);
}
/* выделяем память для новой программы,
* зачитываем программу из файла в эту память
*/
bp = 0;
nc = (nc + NBPW - 1) & ~(NBPW - 1);
if (getxfile(ip, (na * NBPW) + nc, uid, gid) || u.u_error)
goto bad;
/*
* copy back arglist
* формируем стек нового процесса (для вызова main)
*/
ucp = -nc - NBPW;
ap = ucp - na * NBPW - 3 * NBPW;
u.u_ar0[R6] = ap;
suword((caddr_t)ap, na - ne);
nc = 0;
for (;;) {
ap += NBPW;
if (na == ne) {
suword((caddr_t)ap, 0);
ap += NBPW;
}
if (--na < 0)
break;
suword((caddr_t)ap, ucp);
do {
if ((nc & BMASK) == 0) {
if (bp) {
mapout(bp);
bp->b_flags |= B_AGE;
brelse(bp);
}
#ifndef UCB_NKB
bp = bread(swapdev, swplo + bno + (nc>>BSHIFT));
#else
bp = bread(swapdev,
dbtofsb(clrnd(swplo + bno)) + (nc >> BSHIFT));
#endif
bp->b_flags &= ~B_DELWRI;
cp = mapin(bp);
/* stick in interpreter name for accounting */
if (indir && nc == 0)
bcopy(cp, (caddr_t)u.u_dbuf, DIRSIZ);
}
subyte((caddr_t)ucp++, (c = *cp++));
nc++;
} while(c & 0377);
}
suword((caddr_t) ap, 0);
suword((caddr_t) (-NBPW), 0);
/* завершено формирование стека */
if (bp) {
mapout(bp);
bp->b_flags |= B_AGE;
brelse(bp);
bp = 0;
}
setregs();
bad:
#ifdef SCHED
u.u_procp->p_sflag &= ~SEXEC;
#endif SCHED
if (bp) {
mapout(bp);
bp->b_flags |= B_AGE;
brelse(bp);
}
if (bno)
#ifndef UCB_NKB
mfree(swapmap, (NCARGS + BSIZE - 1) / BSIZE, bno);
#else
mfree(swapmap, ctod((int) btoc(NCARGS + BSIZE)), bno);
#endif
iput(ip);
}
/*
* Read in and set up memory for executed file.
* Zero return is normal;
* non-zero means only the text is being replaced
*/
getxfile(ip, nargc, uid, gid)
int nargc, uid, gid;
register struct inode *ip;
{
[...]
}
/*
* Clear registers on exec
*/
setregs()
{
[...]
}
/*
* exit system call:
* pass back caller's arg
*/
rexit()
{
register struct a {
int rval;
} *uap;
uap = (struct a *)u.u_ap;
exit((uap->rval & 0377) << 8);
}
/*
* Release resources.
* Save u. area for parent to look at.
* Enter zombie state.
* Wake up parent and init processes,
* and dispose of children.
*/
exit(rv)
{
[...]
}
/*
* Wait system call.
* Search for a terminated (zombie) child,
* finally lay it to rest, and collect its status.
* Look also for stopped (traced) children,
* and pass back status from them.
*/
wait()
{
[...]
}
/*
* fork system call.
*/
#ifdef VIRUS_VFORK
fork()
{
fork1(0);
}
/*
* vfork system call
*/
vfork()
{
fork1(1);
}
fork1(isvfork)
#else VIRUS_VFORK
fork()
#endif
{
[...]
}
/*
* break system call.
* -- bad planning: "break" is a dirty word in C.
*/
sbreak()
{
[...]
}