CAP/applications/aufs/aufs.c

1978 lines
52 KiB
C

/*
* $Author: djh $ $Date: 1996/09/12 05:11:59 $
* $Header: /mac/src/cap60/applications/aufs/RCS/aufs.c,v 2.34 1996/09/12 05:11:59 djh Rel djh $
* $Revision: 2.34 $
*
*/
/*
* aufs - UNIX AppleTalk Unix File Server
*
*
* AppleTalk package for UNIX (4.2 BSD).
*
* Copyright (c) 1986, 1987, 1988 by The Trustees of Columbia University in the
* City of New York.
*
* Edit History:
*
* March 1987 Schilit Created.
*
*/
char copyright[] = "Copyright (c) 1986, 1987, 1988 by The Trustees of Columbia University in the City of New York";
#include <stdio.h>
#include <sys/param.h>
#ifndef _TYPES
/* assume included by param.h */
#include <sys/types.h>
#endif _TYPES
#include <sys/file.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/ioctl.h>
#include <netinet/in.h> /* for htons, etc. */
#include <signal.h>
#include <netat/appletalk.h> /* include appletalk definitions */
#include <netat/compat.h>
#include <netat/afp.h>
#include "afps.h" /* server includes */
#ifdef NEEDFCNTLDOTH
#include <fcntl.h>
#endif NEEDFCNTLDOTH
#ifdef USESTRINGDOTH
# include <string.h>
#else USESTRINGDOTH
# include <strings.h>
#endif USESTRINGDOTH
#ifdef USEVPRINTF
# include <varargs.h>
#endif USEVPRINTF
#ifndef NOWAIT3
# define DORUSAGE
#endif NOWAIT3
#ifdef aux
# ifdef DORUSAGE
# undef DORUSAGE
# endif DORUSAGE
#endif aux
#ifdef NOPGRP
# ifdef xenix5
# define killpg(pid,sig) kill(-(pid),sig)
# else xenix5
# define NOSHUTDOWNCODE
# endif xenix5
#endif NOPGRP
#ifdef DEBUG_AFP_CMD
#ifndef DEBUG_AFP
#define DEBUG_AFP
#endif /* DEBUG_AFP */
#endif /* DEBUG_AFP_CMD */
/* known attention codes */
#define AFPSHUTDOWNTIME(x) (0x8000|((x)&0xfff))
#define AFPSHUTDOWNCANCEL (0x8fff)
#define AFPSHUTDOWNNOW (0x8000)
#define AFPSERVERCRASH (0x4000)
#define AFPSERVERMESG (0x2000)
#define AFPDONTRECONN (0x1000)
export int statflg = FALSE; /* default is not to show stats */
export u_char *srvrname = NULL; /* NBP registered name */
export u_char *srvrtype = (u_char *)AFSTYPE; /* NBP registered type */
export char *messagefile = NULL; /* AFP2.1 GetSrvrMsg srvr msg filename */
export char *motdfile = NULL; /* AFP2.1 GetSrvrMsg login msg filename */
export char *dsiTCPIPFilter = NULL; /* AFP2.2 AppleShareIP address filter */
export u_int asip_addr = INADDR_ANY; /* AFP2.2 AppleShare over TCP/IP */
export u_short asip_port = ASIP_PORT; /* AFP2.2 AppleShare TCP/IP port */
export int asip_enable = FALSE; /* AFP2.2 AppleShare TCP/IP default off */
private char *sysvolfile = NULL; /* system afpvols file */
private char *passwdlookaside = NULL; /* local password file??? */
private char *guestid = NULL; /* any guest ids? */
private char *coredir = NULL; /* place to put coredumps */
#ifdef DEBUG_AFP
private char *debugAFPFile = NULL; /* AFP debug file name */
#endif DEBUG_AFP
#ifdef ISO_TRANSLATE
private u_char isoSrvrName[80];
private u_char isoSrvrType[80];
#endif ISO_TRANSLATE
#ifdef REREAD_AFPVOLS
private int readafpvols = FALSE;/* set by USR1 signal */
#endif REREAD_AFPVOLS
#ifdef LWSRV_AUFS_SECURITY
export char *userlogindir = NULL; /* budd -- name of userlogin file */
#endif LWSRV_AUFS_SECURITY
#ifdef APPLICATION_MANAGER
export char *enforcelist = NULL;/* name of list for appln run control */
#endif APPLICATION_MANAGER
#ifdef USR_FILE_TYPES
export char *uftfilename = NULL;/* file with suffix -> creat&type mappings */
#endif USR_FILE_TYPES
#ifdef LOGIN_AUTH_PROG
export char *login_auth_prog = NULL; /* path to external login auth. prog */
#endif LOGIN_AUTH_PROG
export int mcs, qs; /* maxcmdsize and quantum size */
export int sqs = atpMaxNum; /* maximum send quantum */
export int n_rrpkts = atpMaxNum; /* maximum send quantum to allow remote */
/* (used in spwrtcontinue) */
export int nousrvol = FALSE; /* no user home dir/vol flag */
export int nopwdsave = FALSE; /* allow user to save password */
#ifdef AUFS_README
export char *aufsreadme; /* path of readme file */
export char *aufsreadmename; /* pointer into aufsreadme with just name */
#endif AUFS_README
#ifdef DEBUG_AFP
export FILE *dbg = NULL;
#endif /* DEBUG_AFP */
private EntityName srvr_entity_name; /* our entity name */
private char zonetorun[34]; /* zone to run in if different than std. */
private char logfile[MAXPATHLEN]; /* log file name if any */
#ifdef PID_FILE
private char pid_file[MAXPATHLEN]; /* pid file name if any */
#endif /* PID_FILE */
private int parent_pid; /* pid of main server */
private int mypid; /* pid of running process */
private int nomoresessions = FALSE; /* set true of out of asp sessions */
private int sesscount = 0; /* number of asp sessions active */
private int maxsess = 10;
private int cno = -1; /* current connection */
#ifndef NOSHUTDOWNCODE
private int minutes_to_shutdown = -1;
#endif NOSHUTDOWNCODE;
#ifdef AUFS_IDLE_TIMEOUT
private int idletime = 0; /* allowable no traffic period */
private int timeidle = 0; /* have been idle for this time */
private int guestonly = 1; /* default to guest idle timeouts only */
#endif AUFS_IDLE_TIMEOUT
/*
* CNO TO PID handling
*
* Must keep a table to session reference numbers (aka connection
* numbers) to pid mappings for the server since sessions are
* "half"-closed. This handling was previously in the asp protocol
* handler, but this doesn't make sense and there is much better
* control over things here
*
* internal strategy at this point is to record fork terminations
* and handling via garbage collector at a later point. maximum time
* to scan is around 5 seconds at this point. to minimize scan time
* for gc, the "dead" ones are pushed onto a stack.
*
* an alternative strategy is to have the signal handler write to an
* internal pipe watched by a fdlistener. if this is done the sleeps
* can be made much longer. carefully handled this will work very
* well, but it is a little ugly. (note: best way to do is probably
* to have the listener set a variable and the inferior termination
* handler write the pids out. the scan process would then pick up
* the pids from the pipe.)
*
*/
typedef struct cno_to_pid {
int state; /* back reference */
#define CP_NOTINUSE 0x1 /* to mark not in use */
#define CP_RUNNING 0x2 /* inferior is running? */
#define CP_TIMEDOUT 0x4 /* tickle timeout on inferior */
int pid; /* recorded pid */
long timeval; /* time when pid died */
WSTATUS status;
#ifdef DORUSAGE
struct rusage rusage;
#endif DORUSAGE
} CTP, *CTPP;
private struct cno_to_pid *ctp_tab;
private int *ctp_stack;
private int ctp_stack_cnt;
usage(name)
char *name;
{
char *DBLevelOpts();
fprintf(stderr,"usage: %s [-d cap-flags] [-a afp-levels] ",name);
#ifdef LWSRV_AUFS_SECURITY
fprintf(stderr,"[-n name] [-t packets] [-s] [-V afpvols] [-X usrfile]\n");
#else LWSRV_AUFS_SECURITY
fprintf(stderr,"[-n name] [-t packets] [-s] [-V afpvols]\n");
#endif LWSRV_AUFS_SECURITY
#ifdef APPLICATION_MANAGER
fprintf(stderr,"[-A applistfile] ");
#endif APPLICATION_MANAGER
#ifdef AUFS_README
fprintf(stderr,"[-r readme_path] ");
#endif AUFS_README
#ifdef AUFS_IDLE_TIMEOUT
fprintf(stderr,"[-[i|I] idle_timeout] ");
#endif AUFS_IDLE_TIMEOUT
#ifdef USR_FILE_TYPES
fprintf(stderr,"[-F typelist] ");
#endif USR_FILE_TYPES
#ifdef LOGIN_AUTH_PROG
fprintf(stderr,"[-L authprog] ");
#endif LOGIN_AUTH_PROG
fprintf(stderr,"[-m login_message_file] [-M srvr_message_file] ");
fprintf(stderr,"[-p] [-u] ");
fprintf(stderr,"\n\t-d for CAP debugging flags:\n");
fprintf(stderr,"\t l = lap, d = ddp, a = atp, n = nbp, p = pap,");
fprintf(stderr,"i = ini, s = asp\n");
fprintf(stderr,"\t-Ds[shct] for ASP debug limiting flags:\n");
fprintf(stderr,"\t s = socket, h = handlers, c = call, t = tickle\n");
fprintf(stderr,"\t-a for AFP debugging by level (or setenv AUFSDEBUG):\n");
fprintf(stderr,"\t %s\n",DBLevelOpts());
fprintf(stderr,"\t-t for packet traces (or setenv AUFSTRACE):\n");
fprintf(stderr,"\t [I|O|B]CmdName\n");
fprintf(stderr,"\t-n for setting the server's name\n");
fprintf(stderr,"\t-s for statistics\n");
fprintf(stderr,"\t-u do not show user home directory or vols\n");
fprintf(stderr,"\t-p do not allow AFP client to save password\n");
fprintf(stderr,"\t-V VolsFile for server wide afp volumes\n");
fprintf(stderr,"\t-G <username> to set guest id for <anonymous> logins\n");
fprintf(stderr,"\t-P LookAsidePasswordFile for scrambled transactions\n");
fprintf(stderr,"\t-T enable AFP connections via TCP/IP (default addr)\n");
fprintf(stderr,"\t-B <addr[:port]> enable AFP over TCP/IP & set address\n");
fprintf(stderr,"\t-f <filterfile> set the AFP over TCP-IP address filter\n");
fprintf(stderr,"\t-U <number> to allow <number> sessions\n");
fprintf(stderr,"\t-m|M <file> specifies login or server message file\n");
#ifndef STAT_CACHE
fprintf(stderr,"\t-c directory to specify a directory to coredump to\n");
#endif STAT_CACHE
fprintf(stderr,"\t-l file to send logfile to other than <servername>.log\n");
#ifdef PID_FILE
fprintf(stderr,"\t-w file to write pid to other than ./%s\n", PID_FILE);
#endif /* PID_FILE */
fprintf(stderr,"\t-S <n> limit responses to <n> packets\n");
fprintf(stderr,"\t-R <n> limit remote to sending <n> packets\n");
#ifdef LWSRV_AUFS_SECURITY
fprintf(stderr,"\t-X datafile of logged in users\n"); /* budd */
#endif LWSRV_AUFS_SECURITY
#ifdef APPLICATION_MANAGER
fprintf(stderr,"\t-A <file> application run manager\n");
#endif APPLICATION_MANAGER
#ifdef AUFS_README
fprintf(stderr,"\t-r readme file for new users\n");
#endif AUFS_README
#ifdef USR_FILE_TYPES
fprintf(stderr,"\t-F <file> to map from suffix to creator/translation\n");
#endif USR_FILE_TYPES
#ifdef LOGIN_AUTH_PROG
fprintf(stderr,"\t-L <prog> to provide login authorization service\n");
#endif LOGIN_AUTH_PROG
#ifdef DEBUG_AFP
fprintf(stderr, "\t-Z <file> to dump parameters from AFP commands\n");
#endif DEBUG_AFP
fprintf(stderr,"\nExample: %s -t 'bdelete irename' -a 'file fork dir' -s\n",
name);
exit(1);
}
/*
* generate default name from host name
*
*/
char *
afs_default_name()
{
char hostname[255];
static char afsname[255];
char *ap;
gethostname(hostname,(int) sizeof(hostname));
if ((ap = index(hostname,'.')) != NULL)
*ap = '\0'; /* remove trailing domain name */
sprintf(afsname,"%s Aufs",hostname);
return(afsname);
}
doargs(argc,argv)
int argc;
char **argv;
{
int c;
char *p;
u_char *parsename();
extern char *optarg;
extern int optind;
extern boolean dochecksum;
static char optlist[100] = "a:B:d:f:D:n:N:t:kpsTuV:U:G:P:c:l:z:S:R:M:m:";
#ifdef ISO_TRANSLATE
void cISO2Mac();
#endif ISO_TRANSLATE
#ifdef LWSRV_AUFS_SECURITY
strcat(optlist, "X:");
#endif LWSRV_AUFS_SECURITY
#ifdef APPLICATION_MANAGER
strcat(optlist, "A:");
#endif APPLICATION_MANAGER
#ifdef AUFS_README
strcat(optlist, "r:");
#endif AUFS_README
#ifdef AUFS_IDLE_TIMEOUT
strcat(optlist, "i:I:");
#endif AUFS_IDLE_TIMEOUT
#ifdef USR_FILE_TYPES
strcat(optlist, "F:");
#endif USR_FILE_TYPES
#ifdef LOGIN_AUTH_PROG
strcat(optlist, "L:");
#endif LOGIN_AUTH_PROG
#ifdef PID_FILE
pid_file[0] = '\0';
strcat(optlist, "w:");
#endif /* PID_FILE */
#ifdef DEBUG_AFP
strcat(optlist, "Z:");
#endif /* DEBUG_AFP */
while ((c = getopt(argc,argv,optlist)) != EOF) {
switch (c) {
case 'z':
strncpy(zonetorun, optarg, 32);
break;
case 'l':
strncpy(logfile, optarg, sizeof(logfile)-1);
break;
case 'c':
coredir = optarg;
break;
case 'k':
dochecksum = 0; /* no DDP checksum */
break;
case 'p':
nopwdsave = TRUE; /* don't allow save password */
break;
case 's':
statflg = TRUE;
break;
case 'u':
nousrvol = TRUE; /* don't show home dir */
break;
case 'd':
dbugarg(optarg); /* '-d' is debug */
break;
case 'D':
if (optarg[0] != 's')
usage(argv[0]);
aspdebug(optarg+1); /* call asp debug */
break;
case 'a':
if (!SetDBLevel(optarg)) /* -a for afp debug */
usage(argv[0]);
break;
case 'm':
motdfile = optarg; /* -m message file path */
break;
case 'M':
messagefile = optarg; /* -M message file path */
break;
case 'n':
case 'N':
srvrname = (u_char *)optarg; /* '-n' to set server name */
srvrtype = parsename(srvrname); /* (optional "-n name:type") */
#ifdef ISO_TRANSLATE
bcopy(srvrname, isoSrvrName, strlen(srvrname)+1);
cISO2Mac(srvrname);
bcopy(srvrtype, isoSrvrType, strlen(srvrtype)+1);
cISO2Mac(srvrtype);
#endif ISO_TRANSLATE
break;
case 't':
if (!SetPktTrace(optarg))
usage(argv[0]);
break;
case 'f': /* AppleShareIP IP address filter */
dsiTCPIPFilter = optarg;
break;
case 'B': /* Bind AppleShare TCP/IP address */
if ((p = (char *)index(optarg, ':')) != NULL) {
asip_port = atoi(p+1);
*p = '\0';
}
if ((asip_addr = (u_int)ntohl(inet_addr(optarg))) == -1)
asip_addr = INADDR_ANY;
if (p != NULL)
*p = ':';
/* fall through */
case 'T': /* Enable AppleShare TCP/IP */
asip_enable = TRUE;
break;
case 'V': /* system afpvols file */
sysvolfile = optarg;
break;
case 'U':
maxsess = atoi(optarg);
break;
case 'P':
passwdlookaside = optarg;
break;
case 'G':
guestid = optarg;
break;
case 'S':
sqs = atoi(optarg);
if (sqs <= 0) {
fprintf(stderr, "Must have at least one packet in a response, resetting to one\n");
sqs = 1;
}
if (sqs > atpMaxNum) {
fprintf(stderr, "No more than %d packets allowed in a response\n",
atpMaxNum);
sqs = atpMaxNum;
}
break;
case 'R':
n_rrpkts = atoi(optarg);
if (n_rrpkts <= 0) {
fprintf(stderr, "Must have at least one packet in a response, resetting to one\n");
n_rrpkts = 1;
}
if (n_rrpkts > atpMaxNum) {
fprintf(stderr, "No more than %d packets allowed in a response\n",
atpMaxNum);
n_rrpkts = atpMaxNum;
}
break;
#ifdef LWSRV_AUFS_SECURITY
case 'X': /* budd... */
userlogindir = optarg;
break; /* ...budd */
#endif LWSRV_AUFS_SECURITY
#ifdef APPLICATION_MANAGER
case 'A':
enforcelist = optarg;
break;
#endif APPLICATION_MANAGER
#ifdef AUFS_README
case 'r':
aufsreadme = optarg;
if (*aufsreadme != '/') {
fprintf(stderr, "The -r parameter must be a full path name\n");
exit(1);
}
aufsreadmename = (char *)rindex(aufsreadme, '/') + 1;
break;
#endif AUFS_README
#ifdef AUFS_IDLE_TIMEOUT
case 'I': /* also users */
guestonly = 0;
/* fall thro' */
case 'i': /* guests only */
idletime = atoi(optarg) * 6;
break;
#endif AUFS_IDLE_TIMEOUT
#ifdef USR_FILE_TYPES
case 'F': /* file suffix mapping */
uftfilename = optarg;
break;
#endif USR_FILE_TYPES
#ifdef LOGIN_AUTH_PROG
case 'L': /* login authorization */
login_auth_prog = optarg;
if (*login_auth_prog != '/') {
fprintf(stderr, "The -L parameter must be a full path name\n");
exit(1);
}
break;
#endif LOGIN_AUTH_PROG
#ifdef PID_FILE
case 'w': /* pid file */
strncpy(pid_file, optarg, sizeof(pid_file)-1);
break;
#endif /* PID_FILE */
#ifdef DEBUG_AFP
case 'Z': /* command debug file */
debugAFPFile = optarg;
break;
#endif /* DEBUG_AFP */
default:
usage(argv[0]);
break;
}
}
}
/*
* check name for optional ':' delimited type
*
*/
u_char *
parsename(name)
u_char *name;
{
u_char *cp;
if ((cp = (u_char *)index((char *)name, ':')) != NULL) {
*cp++ = '\0'; /* NULL terminate name */
return(cp);
}
return((u_char *)AFSTYPE);
}
export AddrBlock addr; /* budd */
main(argc,argv)
int argc;
char **argv;
{
int timedout();
void inferiordone(), dienow(), dying();
#ifdef REREAD_AFPVOLS
void setreadafpvols();
void dorereadafpvols();
#endif REREAD_AFPVOLS
#ifdef CLOSE_LOG_SIG
void closelog();
#endif /* CLOSE_LOG_SIG */
#ifndef NOSHUTDOWNCODE
void killnow(), killin5(), diein5();
void msgnotify(), msgavail();
#endif NOSHUTDOWNCODE;
int err,atpskt,slsref;
int comp,comp2;
byte *srvinfo;
int srvinfolen;
char *getenv(),*env;
int pid;
int mask;
byte *buf; /* [atpMaxData]; */
byte *rspbuf; /* [atpMaxData*atpMaxNum]; */
import byte *aufsicon; /* aufs icon */
import int aufsiconsize; /* and its size */
import char *aufs_versiondate;
import int aufs_version[];
extern int errno;
#ifdef ISO_TRANSLATE
void cISO2Mac();
#endif ISO_TRANSLATE
#ifdef DIGITAL_UNIX_SECURITY
set_auth_parameters(argc, argv);
#endif DIGITAL_UNIX_SECURITY
OSEnable(); /* enable OS dependent items */
IniServer();
srvrname = (u_char *)afs_default_name(); /* set default server name */
#ifdef ISO_TRANSLATE
bcopy(srvrname, isoSrvrName, strlen(srvrname)+1);
cISO2Mac(srvrname);
bcopy(AFSTYPE, isoSrvrType, strlen(AFSTYPE)+1);
#endif ISO_TRANSLATE
logfile[0] = '\0';
zonetorun[0] = '\0';
doargs(argc,argv); /* handle command line */
#ifdef AUTHENTICATE
#ifdef ISO_TRANSLATE
initauthenticate(*argv, (char *)isoSrvrName);
#else ISO_TRANSLATE
initauthenticate(*argv, (char *)srvrname);
#endif ISO_TRANSLATE
#endif AUTHENTICATE
env = getenv("AUFSTRACE"); /* See if user wants to */
if (env != NULL) /* trace some packets */
SetPktTrace(env);
env = getenv("AUFSDEBUG");
if (env != NULL)
SetDBLevel(env);
if (!DBDEB) {
#ifdef ISO_TRANSLATE
fprintf(stderr,"Apple Unix File Server (%s:%s@*) starting\n",
(char *)isoSrvrName, (char *)isoSrvrType);
#else ISO_TRANSLATE
fprintf(stderr,"Apple Unix File Server (%s:%s@*) starting\n",
(char *)srvrname, (char *)srvrtype);
#endif ISO_TRANSLATE
}
/* here's the place to fork off */
if (!DBDEB) {
if (fork())
_exit(0);
{
int f;
for (f = 0; f < 10; f++)
(void) close(f);
}
(void) open("/", 0);
#ifndef NODUP2
(void) dup2(0, 1);
(void) dup2(0, 2);
#else NODUP2
(void)dup(0); /* for slot 1 */
(void)dup(0); /* for slot 2 */
#endif NODUP2
#ifndef POSIX
#ifdef TIOCNOTTY
{
int t;
t = open("/dev/tty", 2);
if (t >= 0) {
ioctl(t, TIOCNOTTY, (char *)0);
(void) close(t);
}
}
#endif TIOCNOTTY
#ifdef linux
(void) setsid();
#endif linux
#ifdef xenix5
/*
* USG process groups:
* The fork guarantees that the child is not a process group leader.
* Then setpgrp() can work, whick loses the controllong tty.
* Note that we must be careful not to be the first to open any tty,
* or it will become our controlling tty. C'est la vie.
*/
setpgrp();
#endif xenix5
#else POSIX
(void) setsid();
#endif POSIX
}
#ifdef DEBUG_AFP
if (debugAFPFile != NULL)
if ((dbg = fopen(debugAFPFile, "w")) != NULL)
fprintf(dbg, "AUFS Debug Session\n");
#endif /* DEBUG_AFP */
#ifdef FIXED_DIRIDS
InitDID(); /* init directory stuff */
#endif FIXED_DIRIDS
mypid = parent_pid = getpid(); /* remember who we are */
#ifdef PID_FILE
{ FILE *pidfd;
if (pid_file[0] == '\0')
strncpy(pid_file, PID_FILE, sizeof(pid_file)-1);
if( (pidfd = fopen(pid_file, "w")) == NULL ) {
logit(0,"Can't open pid file %s", pid_file);
exit(-1);
}
fprintf(pidfd, "%d\n", mypid);
fclose(pidfd);
}
#endif /* PID_FILE */
if (logfile[0] == '\0') {
#ifdef ISO_TRANSLATE
sprintf(logfile, "%s.log", (char *)isoSrvrName);
#else ISO_TRANSLATE
sprintf(logfile, "%s.log", (char *)srvrname);
#endif ISO_TRANSLATE
}
logitfileis(logfile, "a+");
logit(0,"****************************************");
#ifdef ISO_TRANSLATE
logit(0,"Apple Unix File Server (%s:%s@*) starting",
(char *)isoSrvrName, (char *)isoSrvrType);
#else ISO_TRANSLATE
logit(0,"Apple Unix File Server (%s:%s@*) starting",
(char *)srvrname, (char *)srvrtype);
#endif ISO_TRANSLATE
logit(0,"Aufs version: %d(%d) as of %s",aufs_version[0], aufs_version[1],
aufs_versiondate);
if (sysvolfile != NULL) { /* if known system vols file */
FILE *fd = fopen(sysvolfile, "r");
if (fd == NULL)
logit(0,"Aufs: no such system volumes file %s", sysvolfile);
else if (!VRdVFile(fd)) /* then try to read it now */
logit(0,"Aufs: system volumes file %s bad",sysvolfile);
}
if (zonetorun[0] != '\0')
zoneset(zonetorun);
abInit(TRUE); /* initialize applebus */
nbpInit(); /* initialize nbp */
maxsess = aspInit(maxsess); /* init asp */
logit(0,"%d sessions allowed",maxsess);
if ((ctp_tab = (CTPP)malloc(sizeof(struct cno_to_pid)*maxsess)) == NULL) {
logit(0,"couldn't malloc table for pid recording, fatal!");
}
if ((ctp_stack = (int *)malloc(sizeof(int)*maxsess)) == NULL) {
logit(0,"couldn't malloc stack for pid recording, fatal!");
}
if (asip_enable)
if (asip_addr != INADDR_ANY)
logit(0,"AFP over TCP/IP enabled (IP %08x Port %d)",asip_addr,asip_port);
else
logit(0,"AFP over TCP/IP enabled (IP INADDR_ANY Port %d)", asip_port);
#ifdef LWSRV_AUFS_SECURITY
if (userlogindir != NULL) { /* budd... */
logit(0,"Aufs: user login database in %s", userlogindir);
} /* ...budd */
#endif LWSRV_AUFS_SECURITY
#ifdef APPLICATION_MANAGER
if (enforcelist != NULL) {
logit(4,"aufs: application manager database in %s", enforcelist);
readAppList(enforcelist);
}
#endif APPLICATION_MANAGER
#ifdef AUFS_IDLE_TIMEOUT
if (idletime)
logit(0, "Idle timeout set to %d minutes for %s sessions",
idletime/6, (guestonly) ? "guest" : "all");
#endif AUFS_IDLE_TIMEOUT
#ifdef LOGIN_AUTH_PROG
if (login_auth_prog)
logit(0, "Login authorization program: %s\n", login_auth_prog);
#endif LOGIN_AUTH_PROG
ctp_stack_cnt = 0;
{ int i;
for (i = 0 ; i < maxsess; i++) {
ctp_tab[i].state = CP_NOTINUSE;
ctp_tab[i].pid = -1;
}
}
tellaboutos(); /* tell about os stuff */
if (sqs < atpMaxNum)
logit(0,"maximum of %d packet%s will be sent on a response", sqs,
sqs > 1 ? "s" : "");
sqs *= atpMaxData;
if (n_rrpkts < atpMaxNum)
logit(0,"remote limited to %d packet%s in a response", n_rrpkts,
n_rrpkts > 1 ? "s" : "");
dsiGetParms(&mcs, &qs);
if (DBDEB)
printf("Command buffer size is %d, Quantum size is %d\n", mcs, qs);
buf = (byte *)malloc(mcs);
rspbuf = (byte *)malloc(qs);
if (buf == NULL || rspbuf == NULL) {
logit(0,"memory allocation failure!\n");
exit(999);
}
addr.net = addr.node = addr.skt = 0; /* use any */
atpskt = 0; /* make sure we use dynamic skt */
err = ATPOpenSocket(&addr,&atpskt);
if (err != noErr) {
logit(0,"ATPOpenSocket failed with error %d\n",err);
exit(0);
}
GetMyAddr(&addr); /* set net and node */
addr.skt = atpskt;
if (SrvrRegister(atpskt,srvrname,srvrtype,"*", &srvr_entity_name) != noErr) {
logit(0,"SrvrRegister for %s:%s failed...", srvrname, srvrtype);
exit(2);
}
/*
* set available User Authentication Methods
*
*/
if (guestid != NULL)
allowguestid(guestid);
allowcleartext();
#ifdef DISTRIB_PASSWDS
allow2wayrand(passwdlookaside);
#else /* DISTRIB_PASSWDS */
if (passwdlookaside != NULL)
allowrandnum(passwdlookaside);
#endif /* DISTRIB_PASSWDS */
#ifndef STAT_CACHE
if (coredir)
if (chdir(coredir) < 0) {
perror("chdir for coredumps");
logit(0,"chdir to %s for coredumps failed",coredir);
} else
logit(0,"***CORE DUMPS WILL BE IN %s",coredir);
#endif STAT_CACHE
/* Get server info once and stash away*/
srvinfolen = GetSrvrInfo(rspbuf,srvrname,aufsicon,aufsiconsize);
srvinfo = (byte *) malloc(srvinfolen);
bcopy(rspbuf,srvinfo,srvinfolen);
if (DBSRV)
PrtSrvrInfo(srvinfo,srvinfolen);
/* Init asp */
err = dsiInit(&addr,srvinfo,srvinfolen,&slsref);
if (err != noErr) {
logit(0,"dsiInit failed with code %d, fatal",err);
exit(0);
}
logit(0,"Aufs Starting (%s)",srvrname);
if (sysvolfile)
logit(0,"System vols in '%s'",sysvolfile);
logit(0,"dsiInit Completed. Waiting for connection...");
#ifndef NOSHUTDOWNCODE
# ifndef NOPGRP
setpgrp(0, parent_pid); /* set our process group */
/* (inherited) */
# endif NOPGRP
#endif NOSHUTDOWNCODE;
#ifndef DEBUGFORK
if (!DBDEB)
#endif
signal(SIGCHLD, inferiordone);
#ifndef NOSHUTDOWNCODE
signal(SIGHUP, killnow); /* kill -HUP -- Immediate shutdown */
signal(SIGTERM, killin5); /* kill -TERM -- Timed (5 min) shutdown */
signal(SIGURG, msgnotify); /* kill -URG -- A srvr message is available */
#endif NOSHUTDOWNCODE;
#ifdef REREAD_AFPVOLS
signal(SIGUSR1, setreadafpvols); /* kill -USR1 -- force afpvols re-read */
#endif REREAD_AFPVOLS
#ifdef CLOSE_LOG_SIG
signal(CLOSE_LOG_SIG, closelog); /* kill -USR2 -- force close/reopen log */
#endif /* CLOSE_LOG_SIG */
do {
pid = -1; /* make sure zero at start */
dsiGetSession(slsref,&cno,&comp);
if (comp > 0)
logit(0,"Waiting for session %d to activate", cno);
/* won't wait if we set comp above */
while (comp > 0) {
abSleep(sectotick(5),TRUE);
#ifdef REREAD_AFPVOLS
if (readafpvols == TRUE)
dorereadafpvols();
#endif REREAD_AFPVOLS
gcinferior();
}
if (comp == NoMoreSessions) {
nomoresessions = TRUE;
logit(0,"Woops, no more sessions");
while (nomoresessions) {
gcinferior();
abSleep(sectotick(5), TRUE);
}
logit(0,"Okay, sessions should be available");
continue;
}
if (comp != noErr) {
logit(0,"GetSession returned %d on server socket %d",comp,slsref);
continue;
} else {
sesscount++;
logit(0,"New session %d started on server socket %d, count %d",
cno,slsref,sesscount);
if ((err = dsiGetNetworkInfo(cno, &addr)) != noErr) {
if (err > 0) { /* AppleShareIP session */
logit(0,"Session %d from [IP addr %d.%d.%d.%d, port %d]",
cno, addr.net>>8, addr.net&0xff, addr.node, addr.skt, err);
err = noErr;
} else
logit(0,"Get Network info failed with error %d", err);
} else {
#ifdef AUTHENTICATE
err = (authenticate(ntohs(addr.net), addr.node)) ? noErr : ~noErr;
logit(0,"%session %d from [Network %d.%d, node %d, socket %d]",
(err == noErr) ? "S" : "Authentication failed, s",
#else AUTHENTICATE
logit(0,"Session %d from [Network %d.%d, node %d, socket %d]",
#endif AUTHENTICATE
cno,
nkipnetnumber(addr.net), nkipsubnetnumber(addr.net),
addr.node, addr.skt);
}
#ifdef AUTHENTICATE
if(err != noErr) {
dsiCloseSession(cno, 1, 1, &comp2);
continue;
}
#endif AUTHENTICATE
}
#ifndef DEBUGFORK
if (!DBDEB) {
#endif
#ifdef NOSIGMASK
mask = 0;
sighold(SIGCHLD);
sighold(SIGHUP);
# ifndef NOSHUTDOWNCODE
sighold(SIGTERM);
sighold(SIGURG);
# endif NOSHUTDOWNCODE;
#else NOSIGMASK
# ifndef NOSHUTDOWNCODE
mask = sigblock(sigmask(SIGCHLD)|sigmask(SIGHUP)
|sigmask(SIGTERM)|sigmask(SIGURG));
# else NOSHUTDOWNCODE;
mask = sigblock(sigmask(SIGCHLD)|sigmask(SIGHUP));
# endif NOSHUTDOWNCODE;
#endif NOSIGMASK
/* fork on connection - only tickle from parent */
if ((pid = dsiFork(cno, TRUE, FALSE)) < 0) {
logit(0,"dsiFork failed on session %d, last system error %d",cno,errno);
/* try to close, but don't worry too much */
dsiCloseSession(cno, 1, 1, &comp2);
#ifdef NOSIGMASK
sigrelse(SIGCHLD);
sigrelse(SIGHUP);
# ifndef NOSHUTDOWNCODE
sigrelse(SIGTERM);
sigrelse(SIGURG);
# endif NOSHUTDOWNCODE;
#else NOSIGMASK
sigsetmask(mask);
#endif NOSIGMASK
continue;
}
dsiTickleUserRoutine(cno, timedout, pid);
if (pid) {
logit(0,"pid %d starting for session %d",pid, cno);
addinferior(cno, pid); /* addinferior scans (phew) */
} else {
#ifndef NOSHUTDOWNCODE
alarm(0); /* make sure off */
#endif NOSHUTDOWNCODE;
nbpShutdown(); /* don't need this in inferior */
signal(SIGCHLD, SIG_DFL);
#ifndef NOSHUTDOWNCODE
signal(SIGTERM, diein5); /* die in 5 minutes */
signal(SIGURG, msgavail); /* message is available */
#endif NOSHUTDOWNCODE;
signal(SIGHUP, dienow); /* superior signaled us to shutdown */
mypid = getpid();
#ifndef NOSHUTDOWNCODE
#ifdef REREAD_AFPVOLS
signal(SIGUSR1, SIG_DFL);/* ignore in inferior */
#endif REREAD_AFPVOLS
# ifndef NOPGRP
setpgrp(0, parent_pid); /* set our process group */
# endif NOPGRP
dying(); /* are we dying? if so, handle it*/
#endif NOSHUTDOWNCODE;
}
#ifdef NOSIGMASK
sigrelse(SIGCHLD);
sigrelse(SIGHUP);
# ifndef NOSHUTDOWNCODE
sigrelse(SIGTERM);
sigrelse(SIGURG);
# endif NOSHUTDOWNCODE;
#else NOSIGMASK
sigsetmask(mask);
#endif NOSIGMASK
#ifndef DEBUGFORK
} else pid = 0;
#endif
} while (pid != 0); /* pid = 0 implies inferior process */
if (pid == 0)
inferior_handler(buf, rspbuf);
if (statflg)
SrvrPrintStats(); /* print stats */
if (mypid == parent_pid)
if ((err = SrvrShutdown(&srvr_entity_name)) != noErr)
logit(0,"NBPRemove failed: code %d\n", err);
exit(0);
}
#ifndef TREL_TIMEOUT
inferior_handler(buf, rspbuf)
byte *buf;
byte *rspbuf;
#else TREL_TIMEOUT
inferior_handler(buf1, rspbuf1)
byte *buf1;
byte *rspbuf1;
#endif TREL_TIMEOUT
{
int mask;
OSErr err;
#ifndef TREL_TIMEOUT
int comp;
int type,rlen,rsplen;
ReqRefNumType reqref;
#else TREL_TIMEOUT
int comp1,comp2;
int type1,rlen1,rsplen1;
int type2,rlen2,rsplen2;
ReqRefNumType reqref1;
ReqRefNumType reqref2;
byte * buf2;
byte * rspbuf2;
#endif TREL_TIMEOUT
#ifdef TREL_TIMEOUT
buf2 = (byte *)malloc(mcs);
rspbuf2 = (byte *)malloc(qs);
if (buf2 == NULL || rspbuf2 == NULL) {
logit(0,"memory allocation failure!\n");
exit(999);
}
comp1 = 0;
comp2 = 0;
#endif TREL_TIMEOUT
umask(0); /* file creates have explict modes */
for (;;) {
#ifndef TREL_TIMEOUT
dsiGetRequest(cno,buf,mcs,&reqref,&type,&rlen,&comp);
while (comp > 0) {
abSleep(sectotick(60),TRUE);
#ifdef AUFS_IDLE_TIMEOUT
if (idletime)
(void) checkIdle(cno,buf,comp);
#endif AUFS_IDLE_TIMEOUT
}
if (comp == SessClosed || comp == ParamErr) {
#else TREL_TIMEOUT
if (comp1 > 0 && comp2 > 0) {
while (comp1 > 0 && comp2 > 0) {
abSleep(sectotick(60),TRUE);
}
if (DBSRV)
printf("done\n");
}
if (comp1 <= 0) {
dsiGetRequest(cno,buf1,mcs,&reqref1,&type1,&rlen1,&comp1);
while (comp1 > 0) {
abSleep(sectotick(60),TRUE);
#ifdef AUFS_IDLE_TIMEOUT
if (idletime)
(void) checkIdle(cno,buf1,comp1);
#endif AUFS_IDLE_TIMEOUT
}
if (comp1 == SessClosed || comp1 == ParamErr) {
#endif TREL_TIMEOUT
logit(0,"Session (%d) closed",cno);
#ifdef LWSRV_AUFS_SECURITY
clearuserlogin(); /* budd */
#endif LWSRV_AUFS_SECURITY
return;
}
#ifndef TREL_TIMEOUT
if (comp < 0) {
logit(0,"dsiGetRequest failed %d",comp);
#else TREL_TIMEOUT
if (comp1 < 0) {
logit(0,"dsiGetRequest failed %d",comp1);
#endif TREL_TIMEOUT
continue;
}
#ifndef TREL_TIMEOUT
if (rlen == 0)
#else TREL_TIMEOUT
if (rlen1 == 0)
#endif TREL_TIMEOUT
continue;
#ifndef NOSHUTDOWNCODE
/* mask off potential race condition */
# ifdef NOSIGMASK
sighold(SIGTERM);
sighold(SIGURG);
sighold(SIGALRM);
# else NOSIGMASK
mask = sigblock(sigmask(SIGTERM)|sigmask(SIGURG)|sigmask(SIGALRM));
# endif NOSIGMASK
#endif NOSHUTDOWNCODE;
#ifndef TREL_TIMEOUT
switch (type) {
#else TREL_TIMEOUT
switch (type1) {
#endif TREL_TIMEOUT
case aspWrite:
case aspCommand:
#ifndef TREL_TIMEOUT
err = SrvrDispatch(buf,rlen,rspbuf,&rsplen,cno,reqref);
#else TREL_TIMEOUT
err = SrvrDispatch(buf1,rlen1,rspbuf1,&rsplen1,cno,reqref1);
#endif TREL_TIMEOUT
if (DBSRV) {
#ifndef TREL_TIMEOUT
printf("Sending reply len=%d err=%s ...\n",rsplen,afperr(err));
#else TREL_TIMEOUT
printf("Sending reply len=%d err=%s ...\n",rsplen1,afperr(err));
#endif TREL_TIMEOUT
fflush(stdout); /* force out */
}
#ifndef TREL_TIMEOUT
if (type == aspWrite)
dsiWrtReply(cno,reqref,(dword) err,rspbuf,rsplen,&comp);
#else TREL_TIMEOUT
if (type1 == aspWrite)
dsiWrtReply(cno,reqref1,(dword) err,rspbuf1,rsplen1,&comp1);
#endif TREL_TIMEOUT
else
#ifndef TREL_TIMEOUT
dsiCmdReply(cno,reqref,(dword) err,rspbuf,rsplen,&comp);
while (comp > 0) {
abSleep(sectotick(60),TRUE);
}
if (DBSRV)
printf("done\n");
#else TREL_TIMEOUT
dsiCmdReply(cno,reqref1,(dword) err,rspbuf1,rsplen1,&comp1);
#endif TREL_TIMEOUT
break;
case aspCloseSession:
logit(0,"Closing ASP Session...");
#ifndef TREL_TIMEOUT
dsiCloseSession(cno,10,3,&comp); /* 5 times, .75 seconds */
while (comp > 0)
#else TREL_TIMEOUT
dsiCloseSession(cno,10,3,&comp1); /* 5 times, .75 seconds */
while (comp1 > 0)
#endif TREL_TIMEOUT
abSleep(1, TRUE);
#ifndef NOSHUTDOWNCODE
#ifdef NOSIGMASK
sigrelse(SIGCHLD);
sigrelse(SIGHUP);
#else NOSIGMASK
sigsetmask(mask);
#endif NOSIGMASK
#endif NOSHUTDOWNCODE;
return;
default:
#ifndef TREL_TIMEOUT
logit(0,"Unknown asp command type = %d",type);
#else TREL_TIMEOUT
logit(0,"Unknown asp command type = %d",type1);
#endif TREL_TIMEOUT
break;
}
#ifndef NOSHUTDOWNCODE
#ifdef NOSIGMASK
sigrelse(SIGCHLD);
sigrelse(SIGHUP);
#else NOSIGMASK
sigsetmask(mask);
#endif NOSIGMASK
#endif NOSHUTDOWNCODE;
#ifdef TREL_TIMEOUT
} else { /* comp2 */
dsiGetRequest(cno,buf2,mcs,&reqref2,&type2,&rlen2,&comp2);
while (comp2 > 0) {
abSleep(sectotick(60),TRUE);
#ifdef AUFS_IDLE_TIMEOUT
if (idletime)
(void) checkIdle(cno,buf2,comp2);
#endif AUFS_IDLE_TIMEOUT
}
if (comp2 == SessClosed || comp2 == ParamErr) {
logit(0,"Session (%d) closed",cno);
#ifdef LWSRV_AUFS_SECURITY
clearuserlogin(); /* budd */
#endif LWSRV_AUFS_SECURITY
return;
}
if (comp2 < 0) {
logit(0,"dsiGetRequest failed %d",comp2);
continue;
}
if (rlen2 == 0)
continue;
#ifndef NOSHUTDOWNCODE
/* mask off potential race condition */
# ifdef NOSIGMASK
sighold(SIGTERM);
sighold(SIGURG);
sighold(SIGALRM);
# else NOSIGMASK
mask = sigblock(sigmask(SIGTERM)|sigmask(SIGURG)|sigmask(SIGALRM));
# endif NOSIGMASK
#endif NOSHUTDOWNCODE;
switch (type2) {
case aspWrite:
case aspCommand:
err = SrvrDispatch(buf2,rlen2,rspbuf2,&rsplen2,cno,reqref2);
if (DBSRV) {
printf("Sending reply len=%d err=%s ...\n",rsplen2,afperr(err));
fflush(stdout); /* force out */
}
if (type2 == aspWrite)
dsiWrtReply(cno,reqref2,(dword) err,rspbuf2,rsplen2,&comp2);
else
dsiCmdReply(cno,reqref2,(dword) err,rspbuf2,rsplen2,&comp2);
break;
case aspCloseSession:
logit(0,"Closing ASP Session...");
dsiCloseSession(cno,10,3,&comp2); /* 5 times, .75 seconds */
while (comp2 > 0)
abSleep(1, TRUE);
#ifndef NOSHUTDOWNCODE
#ifdef NOSIGMASK
sigrelse(SIGCHLD);
sigrelse(SIGHUP);
#else NOSIGMASK
sigsetmask(mask);
#endif NOSIGMASK
#endif NOSHUTDOWNCODE;
return;
default:
logit(0,"Unknown asp command type = %d",type2);
break;
}
#ifndef NOSHUTDOWNCODE
#ifdef NOSIGMASK
sigrelse(SIGCHLD);
sigrelse(SIGHUP);
#else NOSIGMASK
sigsetmask(mask);
#endif NOSIGMASK
#endif NOSHUTDOWNCODE;
}
#endif TREL_TIMEOUT
}
}
/*
* Deals with inferior process termination - just close off the
* "half closed" socket
*
*/
void
inferiordone()
{
WSTATUS status;
#ifdef DORUSAGE
struct rusage rusage;
# define RUSAGEVAR &rusage
#else DORUSAGE
# define RUSAGEVAR 0 /* may not be used, but.. */
#endif DORUSAGE
int pid;
int i;
struct cno_to_pid *cp;
#ifndef NOWAIT3
# define DOWAIT while ((pid=wait3(&status, WNOHANG, RUSAGEVAR)) > 0)
#else NOWAIT3
# define DOWAIT if ((pid=wait(&status)) > 0)
#endif NOWAIT3
DOWAIT {
/* remember for later */
for (i = 0, cp = ctp_tab; i < maxsess; i++, cp++) {
if (cp->pid == pid && (cp->state & CP_NOTINUSE) == 0) {
/* one of alive, dead or timedout */
/* if alive, move to dead */
/* if dead, shouldn't be here */
/* if timedout, then leave state */
if ((cp->state & CP_RUNNING) == 0)
logit(0,"Internal error: pid %d has died twice according to wait",pid);
cp->state &= ~CP_RUNNING; /* not running anymore */
(void)time(&cp->timeval); /* log time */
bcopy(&status, &cp->status, sizeof(status)); /* copy status */
#ifdef DORUSAGE
bcopy(&rusage, &cp->rusage, sizeof(rusage));
#endif DORUSAGE
ctp_stack[ctp_stack_cnt++] = i; /* mark cno */
logit(0,"Recorded terminated inferior Aufs PID %d", pid);
break;
}
}
if (i == maxsess)
logit(0,"Unknown terminating inferior pid %d ignored", pid);
}
signal(SIGCHLD, inferiordone);
}
/*
* scan for dead inferiors and handle gracefully. Know we are never
* called from a "bad" context. e.g. we won't be called while in a
* "critical" section where data structures are being updated
*
*/
gcinferior()
{
char tmpbuf[30]; /* reasonable */
int srn, comp;
struct cno_to_pid *cp;
int mask;
if (ctp_stack_cnt <= 0) { /* stack of died pids empty? */
if (ctp_stack_cnt < 0)
logit(0,"internal error: unsafe condition: ctp stack count less than zero");
return; /* yes, just return */
}
#ifdef NOSIGMASK
sighold(SIGCHLD);
#else NOSIGMASK
mask = sigblock(sigmask(SIGCHLD));
#endif NOSIGMASK
do {
srn = ctp_stack[--ctp_stack_cnt]; /* get pid */
cp = &ctp_tab[srn]; /* pointer to info on died pid */
if (cp->state & CP_NOTINUSE) /* nothing to do */
continue;
/* fork termination has three cases: */
/* [?,0177] - stopped */
/* [?, 0] - exit status */
/* [0, ?] - terminated due to signal */
if (cp->state & CP_TIMEDOUT) {
logit(0,"process %d, session %d was terminated due to a timeout",
cp->pid, srn);
} else if (WIFSTOPPED(cp->status)) {
logit(0,"process %d, session %d was suspended! gads what is happening?",
cp->pid, srn);
} else if (WIFSIGNALED(cp->status)) {
dsiAttention(srn, AFPSHUTDOWNNOW, 1, -1, &comp);
while (comp > 0) {abSleep(30, TRUE);} /* ignore error */
dsiCloseSession(srn, 3, 2, &comp); /* try 3 times every .5 seconds */
while (comp > 0) { abSleep(30, TRUE); } /* close down if we can */
logit(0,"process %d, session %d was terminated on signal %d",
cp->pid, srn, W_TERMSIG(cp->status));
if (W_COREDUMP(cp->status)) {
logit(0,"woops: we just dumped core on pid %d", cp->pid);
sprintf(tmpbuf, "core%d",cp->pid);
if (link("core", tmpbuf) == 0) { /* making copy */
if (unlink("core") != 0)
logit(0,"woops: couldn't unlink core for pid %d", cp->pid);
logit(0,"core dump for pid %d is in %s",cp->pid, tmpbuf);
} else
logit(0,"core dump for pid %d is in core - plz be careful though!",
cp->pid);
}
} else {
logit(0,"process %d, session %d terminated with exit code %d",
cp->pid, srn, W_RETCODE(cp->status));
}
dsiShutdown(srn);
nomoresessions = FALSE; /* if this was set, unset now */
#ifdef DORUSAGE
logit(0,"%d messages out, %d in, CPU %.2f user %.2f system",
cp->rusage.ru_msgsnd,cp->rusage.ru_msgrcv,
((float)cp->rusage.ru_utime.tv_sec)+
((float)cp->rusage.ru_utime.tv_usec)/1000000.0,
((float)cp->rusage.ru_stime.tv_sec)+
((float)cp->rusage.ru_stime.tv_usec)/1000000.0);
#endif DORUSAGE
logit(0,"Process %d terminated", cp->pid);
cp->state = CP_NOTINUSE;
cp->pid = -1; /* make -1 to speed up sigchld handler */
} while (ctp_stack_cnt);
#ifdef NOSIGMASK
sigrelse(SIGCHLD);
#else NOSIGMASK
sigsetmask(mask); /* restore mask */
#endif NOSIGMASK
}
/*
*
* record inferior pid for later handling
*
* must be called with sigchild and other signals,etc. that could
* affect ctp_tab off.
*
*
*/
addinferior(cno, pid)
int cno;
int pid;
{
struct cno_to_pid *cp;
/* need to scan here in case something timed out */
gcinferior();
cp = &ctp_tab[cno]; /* get pointer to table entry */
/* If was in table, just smash because we have a new pid on cno */
/* should we scan table for duplicates? */
cp->state = CP_RUNNING;
cp->pid = pid;
}
/*
* Connection timed because remote didn't tickle us enough
* Kill inferior and shutdown half closed skt.
*
* Note: called from abSleep scheduler.
*
*/
int
timedout(srn, pid)
int srn;
int pid;
{
nomoresessions = FALSE; /* if this was set, unset now */
logit(0,"Server timeout on session %d pid %d, not talking to remote anymore",
srn, pid);
/* shouldn't need to do anymore here since remote stopped talking */
/* assume sigchild interlocked here */
if (ctp_tab[srn].state & CP_RUNNING)
ctp_tab[srn].state |= CP_TIMEDOUT;
dsiShutdown(srn); /* ignore errors */
kill(pid, SIGHUP); /* hangup inferior */
}
/* got a hup and are inferior of server */
void
dienow()
{
int comp;
logit(0,"Superior told us to shutdown - probably tickle timeout");
/* The following shouldn't really do anything since remote should be gone */
/* be in case it really isn't, let's go through this rigamorle */
/* Tell remote we are shutting down */
dsiAttention(cno, AFPSHUTDOWNNOW, 1, -1, &comp);
while (comp > 0) {abSleep(30, TRUE);} /* ignore error */
/* Try closing just in case */
dsiCloseSession(cno, 3, 2, &comp); /* 3 times, .5 seconds */
while (comp > 0) { abSleep(30, TRUE); } /* close down if we can */
#ifdef LWSRV_AUFS_SECURITY
clearuserlogin(); /* gtw: delete auth-file entry for dead users */
#endif LWSRV_AUFS_SECURITY
exit(0);
}
#ifndef NOSHUTDOWNCODE
/*
* inferior handler: setup and handle: terminate in minutes_to_shutdown
*
*/
void
dying()
{
int comp;
void dying();
void dienow();
if (minutes_to_shutdown < 0) /* not in die mode */
return;
if (!minutes_to_shutdown)
dienow();
signal(SIGALRM, dying);
/* Tell remote we are shutting down */
if (minutes_to_shutdown % 2) { /* all odd minutes */
/* there is a potential race condition here */
dsiAttention(cno, AFPSHUTDOWNTIME(minutes_to_shutdown), 1, -1, &comp);
while (comp > 0) {abSleep(30, TRUE);} /* ignore error */
}
minutes_to_shutdown--;
alarm(60);
}
/*
* inferior handler: setup and handle: terminate in 5 minutes
*
*/
void
diein5()
{
void dying();
signal(SIGTERM, SIG_IGN);
if (minutes_to_shutdown >= 0) /* already in shutdown mode */
return;
logit(0,"Superior told us to shutdown by time -- initiating 5 minute shutdown");
minutes_to_shutdown = 5;
dying(); /* start */
}
/*
* inferior handler: advise client that a message is available
*
*/
void
msgavail()
{
int comp;
signal(SIGURG, SIG_IGN);
dsiAttention(cno, AFPSERVERMESG, 1, -1, &comp);
while (comp > 0)
abSleep(30, TRUE);
signal(SIGURG, msgavail);
return;
}
/*
* Call when the master process receives a SIGHUP -- immediate shutdown
*
*/
void
killnow()
{
OSErr err;
signal (SIGHUP, SIG_IGN);
logit(0,"Parent received SIGHUP -- immediate shutdown");
#ifdef linux
killlist(SIGHUP);
#else linux
killpg (parent_pid, SIGHUP);
#endif linux
if ((err = SrvrShutdown(&srvr_entity_name)) != noErr)
logit(0,"NBPRemove failed: code %d\n", err);
exit(0);
}
/*
* Called with the master process receives a SIGTERM
*/
void
killin5()
{
void killinn();
#ifdef REREAD_AFPVOLS
signal(SIGUSR1, SIG_IGN);
#endif REREAD_AFPVOLS
signal (SIGTERM, SIG_IGN);
logit(0,"Shutdown by time -- initiating 5 minute shutdown");
#ifdef linux
killlist(SIGTERM);
#else linux
killpg (parent_pid, SIGTERM);
#endif linux
minutes_to_shutdown = 4;
/* in case children get blocked up */
signal(SIGALRM, killinn);
alarm(68); /* a litte more than a minute */
}
void
killinn()
{
void killinn();
void killnow();
if (minutes_to_shutdown < 0) /* not in die mode */
return;
if (!minutes_to_shutdown)
killnow();
#ifdef linux
killlist(SIGTERM);
#else linux
killpg (parent_pid, SIGTERM); /* in case inferior was blocked up */
#endif linux
signal(SIGALRM, killinn);
minutes_to_shutdown--;
alarm(60);
}
/*
* called when the master process receives a SIGURG
*
*/
void
msgnotify()
{
signal(SIGURG, SIG_IGN);
logit(0, "Server Message available -- notifying clients");
#ifdef linux
killlist(SIGURG);
#else linux
killpg(parent_pid, SIGURG);
#endif linux
signal(SIGURG, msgnotify);
return;
}
#ifdef linux
/*
* send specified signal to child processes
* (process groups appear to be broken)
*
*/
killlist(sig)
int sig;
{
int i;
struct cno_to_pid *cp;
for (i = 0, cp = ctp_tab; i < maxsess; i++, cp++)
if (cp->state == CP_RUNNING)
kill(cp->pid, sig);
return;
}
#endif /* linux */
#endif /* NOSHUTDOWNCODE */
#ifdef REREAD_AFPVOLS
/*
* a SIGUSR1 sets the 'readafpvols' flag which causes
* dorereadafpvols() to be called next time through the loop
*
*/
void
setreadafpvols()
{
signal(SIGUSR1, SIG_IGN);
readafpvols = TRUE;
signal(SIGUSR1, setreadafpvols);
}
void
dorereadafpvols()
{
FILE *fd, *fopen();
readafpvols = FALSE;
if (sysvolfile != NULL) {
if ((fd = fopen(sysvolfile, "r")) == NULL)
logit(0, "aufs: system volumes file %s disappeared", sysvolfile);
else
if (!VRRdVFile(fd))
logit(0, "aufs: bad format system volumes file %s", sysvolfile);
}
}
#endif REREAD_AFPVOLS
#ifdef CLOSE_LOG_SIG
/*
* A SIGUSR2 requests that the log be closed and reopened. This is
* important if you wish to rotate your logs on a regular basis.
*
*/
void
closelog()
{
signal(CLOSE_LOG_SIG, SIG_IGN);
nologitfile();
logitfileis(logfile, "a+");
signal(CLOSE_LOG_SIG, closelog);
return;
}
#endif /* CLOSE_LOG_SIG */
#ifdef notdef
/*
* log an error message
*/
#ifndef USEVPRINTF
/* Bletch - gotta do it because pyramids don't work the other way */
/* (using _doprnt and &args) and don't have vprintf */
/* of course, there will be something that is just one arg larger :-) */
/*VARARGS1*/
logit(fmt, a1,a2,a3,a4,a5,a6,a7,a8,a9,aa,ab,ac,ad,ae,af)
char *fmt;
#else /* USEVPRINTF */
logit(va_alist)
va_dcl
#endif /* USEVPRINTF */
{
static FILE *fp = NULL;
#ifdef USEVPRINTF
register char *fmt;
va_list args;
#endif
if (fp == NULL)
if (DBDEB)
fp = stderr;
else
if ((fp = fopen(logfile, "a+")) == NULL)
return;
if (mypid != parent_pid)
fprintf(fp, "%05d: ", mypid);
else
fprintf(fp, "%05d* ",mypid);
tmprt(fp);
#ifdef USEVPRINTF
va_start(args);
fmt = va_arg(args, char *);
vfprintf(fp, fmt, args);
va_end(args);
#else /* USEVPRINTF */
fprintf(fp, fmt, a1,a2,a3,a4,a5,a6,a7,a8,a9,aa,ab,ac,ad,ae,af);
#endif /* USEVPRINTF */
putc('\n', fp);
fflush(fp);
}
tmprt(fp)
FILE *fp;
{
fprintf(fp, "%s", mytod(0L));
}
/*
* return tod in a static buffer, rotate among <n> buffers to
* allow at least <n> calls "uses" to be active at a time
*
* <n> is currently 2
*
*/
char *
mytod(ptime)
long ptime;
{
long tloc;
struct tm *tm, *localtime();
#define NTODBUF 2
char * buf;
static char buffers[NTODBUF][100];
static int idx = 0;
if (ptime == 0L)
(void)time(&tloc);
else
tloc = ptime;
tm = localtime(&tloc);
buf = buffers[idx];
++idx; /* move to next */
idx %= NTODBUF; /* make sure in range */
if (tm->tm_year > 99)
sprintf(buf, "%02d:%02d:%02d %02d/%02d/%04d ",
tm->tm_hour, tm->tm_min, tm->tm_sec,
tm->tm_mon+1, tm->tm_mday, tm->tm_year+1900);
else
sprintf(buf, "%02d:%02d:%02d %02d/%02d/%02d ",
tm->tm_hour, tm->tm_min, tm->tm_sec,
tm->tm_mon+1, tm->tm_mday, tm->tm_year);
return(buf);
}
#endif notdef
#ifdef LWSRV_AUFS_SECURITY
/**************** budd... ****************/
clearuserlogin()
{
#ifdef HIDE_LWSEC_FILE
char protecteddir[MAXPATHLEN];
char dir_fname[MAXPATHLEN];
#endif HIDE_LWSEC_FILE
if( userlogindir != NULL ) {
char fname[ 100 ];
int fd;
#ifdef HIDE_LWSEC_FILE
strcpy(protecteddir, userlogindir);
make_userlogin(fname, protecteddir, addr);
strcpy(protecteddir, fname);
strcpy(dir_fname, fname);
fname[0] = '\0';
make_userlogin(fname, protecteddir, addr);
if (unlink(fname) < 0) {
logit(0, "clearuserlogin: unlink failed for %s", fname);
if ((fd = open(fname, O_WRONLY|O_TRUNC)) >= 0)
close(fd);
} else
if (rmdir(dir_fname) < 0)
logit(0, "clearuserlogin: rmdir failed for %s", dir_fname);
#else HIDE_LWSEC_FILE
make_userlogin( fname, userlogindir, addr );
if( unlink( fname ) < 0 ) {
if( (fd = open( fname, O_WRONLY|O_TRUNC )) != -1 )
close( fd );
} /* unlink failed */
#endif HIDE_LWSEC_FILE
} /* have userlogindir */
} /* clearuserlogin */
/* duplicated in aufs.c and lwsrv.c sigh */
make_userlogin( buf, dir, addrb )
char *buf, *dir;
AddrBlock addrb;
{
sprintf( buf, "%s/net%d.%dnode%d",
dir,
nkipnetnumber(addrb.net), nkipsubnetnumber(addrb.net),
addrb.node
);
} /* make_userlogin */
/**************** ...budd ****************/
#endif LWSRV_AUFS_SECURITY
#ifdef APPLICATION_MANAGER
/*
* read the -A specified file for a list of pathnames
* and an indication of the maximum number of times that
* the file (resource fork) can be opened (colon separated).
* Build a sorted list so that searching can be more efficient.
* When the file is opened, read lock the next available byte,
* return 'aeLockErr' if no locks available. If the maximum number
* is specified with a trailing 'P', then the file is PROTECTED from
* Finder copying.
*
* djh@munnari.OZ.AU
* September, 1991
*
*/
struct flist *applist = NULL; /* head ptr for file list */
int fdplist[NOFILE]; /* fd list for protections */
readAppList(file)
char *file;
{
char *c;
int qty = 0;
int num, protect;
FILE *fp, *fopen();
char linebuf[MAXPATHLEN*2];
struct flist *newapplp, *p, *q;
for (num = 0; num < NOFILE; num++)
fdplist[num] = -1;
if ((fp = fopen(file, "r")) == NULL) {
logit(0, "readAppList(): cannot open %s for reading", file);
return;
}
while (fgets(linebuf, sizeof(linebuf), fp) != NULL) {
if (linebuf[0] == '#')
continue;
if ((c = (char *) rindex(linebuf, ':')) == NULL) {
logit(0, "readAppList(): bad format (line %d) in %s", qty+1, file);
fclose(fp);
return;
}
*c++ = '\0';
if ((num = atoi(c)) <= 0) {
logit(0, "readAppList(): illegal value (%d) in %s", num, file);
fclose(fp);
return;
}
protect = ((char *)index(c, 'P') == NULL) ? 0 : 1;
if ((newapplp = (struct flist *)malloc(sizeof(struct flist))) == NULL) {
logit(0, "readAppList(): malloc(%d) failed", sizeof(struct flist));
fclose(fp);
return;
}
if ((newapplp->filename = (char *)malloc(strlen(linebuf)+12)) == NULL) {
logit(0, "readAppList(): malloc(%d) failed", strlen(linebuf)+12);
fclose(fp);
return;
}
if ((c = (char *)rindex(linebuf,'/')) == NULL)
continue;
*c++ = '\0';
strcpy(newapplp->filename, linebuf);
strcat(newapplp->filename, "/.resource/");
strcat(newapplp->filename, c);
newapplp->incarnations = num;
newapplp->protected = protect;
newapplp->next = NULL;
qty++;
/* start list if none */
if (applist == NULL) {
applist = newapplp;
continue;
}
/* else insert in-order */
q = NULL;
p = applist;
while (p != NULL) {
if (strcmp(p->filename, newapplp->filename) > 0)
break;
q = p;
p = p->next;
}
newapplp->next = p;
if (q == NULL)
applist = newapplp;
else
q->next = newapplp;
}
fclose(fp);
p = applist;
logit(0, "Read %d application restrictions from %s", qty, file);
while (p != NULL) {
logit(0, " %s, %d%s", p->filename, p->incarnations,
(p->protected) ? " (no copy)" : "");
p = p->next;
}
return;
}
#endif APPLICATION_MANAGER
#ifdef AUFS_IDLE_TIMEOUT
/*
* If an idle time is set ('-i' for guests, '-I' for everyone) then
* check for number of minutes of no AFP activity. Give warnings
* at 5, 3 & 1 minute marks. If anything happens then we reset the
* timer and notify user that shutdown is aborted.
*
* djh@munnari.OZ.AU
* February, 1992
*
*/
int
checkIdle(cno, buf, cmp)
int cno, cmp;
unsigned char *buf;
{
int i, comp;
extern int guestlogin;
static int sentshutdown = 0;
if (guestonly && !guestlogin)
return;
if (cmp == 0 && *buf != 17) { /* periodic GetVolParms AFP call */
if (sentshutdown) {
logit(0, "Session %d: Aborting Idle Timeout", cno);
dsiAttention(cno, AFPSHUTDOWNCANCEL, 1, -1, &comp);
while (comp > 0) { abSleep(30, TRUE); } /* ignore error */
sentshutdown = 0;
}
timeidle = 0;
return;
}
switch (cmp) {
case 0: /* noErr */
timeidle++;
break;
case 1: /* abSleep() timeout */
if (!sentshutdown) return;
timeidle += 6;
break;
default: /* some error */
return;
break;
}
if (timeidle < idletime)
return;
switch ((i = timeidle-idletime)) {
case 0: /* shutdown in 5 min */
case 12: /* shutdown in 3 min */
case 24: /* shutdown in 1 min */
logit(0, "Session %d: sending %d minute idle timeout warning",cno,5-i/6);
dsiAttention(cno, AFPSHUTDOWNTIME(5-i/6), 1, -1, &comp);
while (comp > 0) { abSleep(30, TRUE); } /* ignore error */
sentshutdown++;
return;
break;
case 30: /* shutdown now */
logit(0, "Session %d: Idle Timeout Shutdown", cno);
dsiAttention(cno, AFPSHUTDOWNNOW, 1, -1, &comp);
while (comp > 0) { abSleep(30, TRUE); } /* ignore error */
dsiCloseSession(cno, 3, 2, &comp); /* 3 times, .5 seconds */
while (comp > 0) { abSleep(30, TRUE); } /* close down if we can */
#ifdef LWSRV_AUFS_SECURITY
clearuserlogin(); /* gtw: delete auth-file entry for dead users */
#endif LWSRV_AUFS_SECURITY
exit(0);
break;
}
}
#endif AUFS_IDLE_TIMEOUT