#include "mt.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <ulimit.h>
#include <wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stropts.h>
#include <ctype.h>
#include <sys/conf.h>
#include <errno.h>
#include <signal.h>
#include "sac.h"
#define COMMENT '#'
#define NOWAIT 0
#define WAIT 1
static char *eatwhite(char *);
static int doassign(char *);
static int dopush(int, char *);
static int dopop(int, char *);
static int dorun(char *, int);
int
doconfig(int fd, char *script, long rflag)
{
int line;
struct stat statbuf;
FILE *fp;
char buf[BUFSIZ + 1];
char *bp;
char *p;
if (stat(script, &statbuf) < 0)
return (0);
fp = fopen(script, "rF");
if (fp == NULL)
return (-1);
line = 0;
while (fgets(buf, BUFSIZ, fp)) {
line++;
p = strchr(buf, '\n');
if (p == NULL) {
(void) fclose(fp);
return (line);
}
*p = '\0';
p = strchr(buf, COMMENT);
if (p)
*p = '\0';
bp = eatwhite(buf);
if (*bp == '\0')
continue;
p = &buf[strlen(buf) - 1];
while (*p && isspace(*p))
*p-- = '\0';
p = bp;
while (*p && !isspace(*p))
p++;
if (*p)
*p++ = '\0';
p = eatwhite(p);
if (strcmp(bp, "assign") == 0) {
if ((rflag & NOASSIGN) || doassign(p)) {
(void) fclose(fp);
return (line);
}
} else if (strcmp(bp, "push") == 0) {
if (dopush(fd, p)) {
(void) fclose(fp);
return (line);
}
} else if (strcmp(bp, "pop") == 0) {
if (dopop(fd, p)) {
(void) fclose(fp);
return (line);
}
} else if (strcmp(bp, "run") == 0) {
if ((rflag & NORUN) || dorun(p, NOWAIT)) {
(void) fclose(fp);
return (line);
}
} else if (strcmp(bp, "runwait") == 0) {
if ((rflag & NORUN) || dorun(p, WAIT)) {
(void) fclose(fp);
return (line);
}
} else {
(void) fclose(fp);
return (line);
}
}
if (!feof(fp)) {
(void) fclose(fp);
return (-1);
}
(void) fclose(fp);
return (0);
}
static int
doassign(char *p)
{
char *var;
char val[BUFSIZ];
char scratch[BUFSIZ];
char delim;
char *tp;
if (*p == '\0')
return (-1);
var = p;
while (*p && !isspace(*p) && (*p != '='))
p++;
if (*p == '\0')
return (-1);
if (isspace(*p)) {
*p++ = '\0';
while (*p && isspace(*p))
p++;
if (*p == '\0')
return (-1);
if (*p == '=')
p++;
else
return (-1);
} else {
*p = '\0';
p++;
}
p = eatwhite(p);
if (*p == '\'' || *p == '"') {
delim = *p++;
tp = val;
for (;;) {
if (*p == '\0') {
return (-1);
} else if (*p == delim) {
if (*(p - 1) != '\\')
break;
else
*(tp - 1) = *p++;
} else
*tp++ = *p++;
}
*tp = '\0';
tp = ++p;
p = val;
} else {
tp = p;
while (*tp && !isspace(*tp))
tp++;
}
if (*tp)
return (-1);
(void) snprintf(scratch, sizeof (scratch), "%s=%s", var, p);
tp = malloc(strlen(scratch) + 1);
if (tp == NULL)
return (-1);
(void) strcpy(tp, scratch);
if (putenv(tp))
return (-1);
return (0);
}
static int
dopush(int fd, char *p)
{
char *tp;
int i;
int npush;
if (*p == '\0')
return (-1);
npush = 0;
for (;;) {
if (*p == '\0')
return (0);
p = eatwhite(p);
if (*p == '\0')
return (-1);
tp = p;
while (*tp && !isspace(*tp) && (*tp != ','))
tp++;
if (*tp)
*tp++ = '\0';
if (ioctl(fd, I_PUSH, p) < 0) {
for (i = 0; i < npush; ++i)
(void) ioctl(fd, I_POP, 0);
return (-1);
}
npush++;
p = tp;
}
}
static int
dopop(int fd, char *p)
{
char *modp;
char buf[FMNAMESZ + 1];
if (*p == '\0') {
if (ioctl(fd, I_POP, 0) < 0)
return (-1);
return (0);
}
p = eatwhite(p);
modp = p;
while (*p && !isspace(*p))
p++;
if (*p)
return (-1);
if (strcmp(modp, "ALL") == 0) {
while (ioctl(fd, I_POP, 0) == 0)
;
if (errno != EINVAL)
return (-1);
return (0);
}
if (ioctl(fd, I_FIND, modp) != 1)
return (-1);
for (;;) {
if (ioctl(fd, I_LOOK, buf) < 0)
return (-1);
if (strcmp(modp, buf) == 0)
return (0);
if (ioctl(fd, I_POP, 0) < 0)
return (-1);
}
}
static int
dorun(char *p, int waitflg)
{
char *tp;
char *ep;
char savech;
int status;
pid_t pid;
pid_t rpid;
void (*func)();
if (*p == '\0')
return (-1);
for (tp = p; *tp && !isspace(*tp); ++tp)
;
savech = '\0';
if (*tp) {
savech = *tp;
*tp = '\0';
}
if (strcmp(p, "cd") == 0) {
*tp = savech;
tp = eatwhite(tp);
if (*tp == '\0')
tp = getenv("HOME");
if (chdir(tp) < 0)
return (-1);
} else if (strcmp(p, "ulimit") == 0) {
*tp = savech;
tp = eatwhite(tp);
if (*tp == '\0')
return (-1);
for (ep = tp; *ep && !isspace(*ep); ++ep)
;
ep = eatwhite(ep);
if (*ep)
return (-1);
if (!isdigit(*tp))
return (-1);
if (ulimit(2, atoi(tp)) < 0)
return (-1);
} else if (strcmp(p, "umask") == 0) {
*tp = savech;
tp = eatwhite(tp);
if (*tp == '\0')
return (-1);
for (ep = tp; *ep && !isspace(*ep); ++ep)
;
ep = eatwhite(ep);
if (*ep)
return (-1);
if (!isdigit(*tp))
return (-1);
(void) umask(strtol(tp, NULL, 8));
} else {
*tp = savech;
func = signal(SIGCLD, SIG_DFL);
if ((pid = fork()) < 0) {
(void) signal(SIGCLD, func);
return (-1);
}
if (pid) {
if (waitflg == WAIT) {
status = 0;
rpid = -1;
while (rpid != pid)
rpid = wait(&status);
if (status) {
(void) signal(SIGCLD, func);
return (-1);
}
}
(void) signal(SIGCLD, func);
} else {
(void) putenv("IFS=\" \"");
closefrom(0);
if (open("/dev/null", O_RDWR) != 0)
return (-1);
if (dup(0) != 1)
return (-1);
if (dup(0) != 2)
return (-1);
(void) execl("/usr/bin/sh", "sh", "-c", p, NULL);
exit(1);
}
}
return (0);
}
static char *
eatwhite(char *p)
{
while (*p && isspace(*p))
p++;
return (p);
}