* Copyright (c) 1989 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
"@(#) Copyright (c) 1989 The Regents of the University of California.\n\
static char sccsid
[] = "@(#)main.c 5.1 (Berkeley) %G%";
#define LINSIZ sizeof(wtmp.ut_line)
#define CMDSIZ 200 /* max string length for getty or window command*/
#define ALL p = itab; p ; p = p->next
#define SCPYN(a, b) strncpy(a, b, sizeof(a))
#define SCMPN(a, b) strncmp(a, b, sizeof(a))
char shell
[] = "/bin/sh";
char utmpf
[] = "/etc/utmp";
char wtmpf
[] = "/usr/adm/wtmp";
char ctty
[] = "/dev/console";
int baud
; /* outgoing baud rate */
int sock
; /* socket if outgoing connected */
int fd
; /* file desc if we have, else -1 */
int errfd
; /* error file desc if we have, else -1 */
int gpid
; /* pid of getty or connector */
char tty3
[LINSIZ
] = { "tty3" } ;
char tty2
[LINSIZ
] = { "tty2" } ;
char *strcpy(), *strcat();
struct conversation convers
[MAXCONNECTS
] ;
fd_set rd_fdset
, wr_fdset
;
struct timeval tv_2th
= { 0, 500000 } ;
main (argc
,argv
) char *argv
[]; {
int sock
, msgsock
, rval
, rv
;
struct sockaddr_un rqsts
;
int constatus
, rqst
, resp
;
struct connectdomain
*cdp
;
struct conversation
*cd
;
signal (SIGTTOU
, SIG_IGN
) ;
signal (SIGTTIN
, SIG_IGN
) ;
signal (SIGPIPE
, sigpipe
) ;
if(setjmp(terminate
)) goto on_error
;
openlog("connectd", LOG_CONS
|LOG_ODELAY
, LOG_AUTH
);
/* disassociate from tty pgrp */
n
= open ("/dev/tty", 2) ;
/* make incoming request socket */
sock
= socket (AF_UNIX
, SOCK_STREAM
, 0) ;
perror("stream socket") ;
rqsts
.sun_family
= AF_UNIX
;
strcpy (rqsts
.sun_path
,"/dev/connect") ;
if (bind (sock
, &rqsts
, sizeof (rqsts
))) {
perror ("bind /dev/connect") ;
if ((argc
<= 1) || strcmp(argv
[1],"-d") != 0) {
close (0); close (1); close (2);
itab
= (struct tab
*)calloc(1, sizeof(*itab
));
itab
->fd
= -1; /* do we have a fd open */
itab
->sock
= -1; /* does someone else have this fd? */
itab
->gpid
= 0; /* does getty have this fd? */
itab
->next
= (struct tab
*)calloc(1, sizeof(*itab
));
itab
->next
->fd
= -1; /* do we have a fd open */
itab
->next
->sock
= -1; /* does someone else have this fd? */
itab
->next
->gpid
= 0; /* does getty else have this fd? */
SCPYN(itab
->next
->line
, tty2
);
/* accept connection requests on socket */
FD_SET (sock
, &rd_fdset
) ;
/* add requests from other lines */
/* service requests as they come in */
fd_set readable
, writeable
;
if (FD_ISSET(i
,&readable
)) fprintf(stderr
, "rd%d ", i
) ;
if (FD_ISSET(i
,&writeable
)) fprintf(stderr
, "wr%d ", i
) ;
if ((n
= select(21, &readable
, &writeable
,
(fd_set
*)0, &tv_2th
)) <= 0) {
if (n
< 0 && errno
!= EINTR
)
syslog(LOG_WARNING
, "select: %m\n");
/* got a request, see who it is */
fprintf(stderr
, "select %d\n", n
) ;
if (FD_ISSET(i
,&readable
))
fprintf(stderr
, "rdsel%d ", i
) ;
if (FD_ISSET(i
,&writeable
))
fprintf(stderr
, "wrsel%d ", i
) ;
/* have we a new connection request? */
if (FD_ISSET(sock
, &readable
)) {
msgsock
= accept(sock
, 0, 0) ;
/*allocate a connection */
convers
[msgsock
].co_sock
= msgsock
;
FD_SET (msgsock
, &rd_fdset
) ;
fprintf(stderr
, "accept %d\n", msgsock
) ;
/* have we a incoming request */
for (p
= itab
; p
; p
= p
->next
)
if (FD_ISSET(p
->fd
, &writeable
)) {
/* fork off getty after setting up line */
printf("do a getty on fd%d\n", p
->fd
) ;
if(p
->sock
>= 0) { printf("on a conn?\n") ; continue; }
for (n
=3 ; n
< i
; n
++) close (n
) ;
execl("/etc/getty", "getty", "std.1200", "-", 0) ;
printf("cd: waitgetty %d %d\n", i
, n
) ;
/* have we an existing socket request */
for (cd
= convers
; cd
- convers
< MAXCONNECTS
; cd
++) {
if (FD_ISSET(cd
->co_sock
, &readable
)) {
fprintf(stderr
, "recv %d\n", cd
->co_sock
) ;
/* recieve connnection request message */
rqst
= rcvrequest(cd
->co_sock
, cd
, &optp
,
/*fprintf(stderr, "rqst %d\n", rqst) ;*/
if (rqst
< 0) goto end_session
;
/*printf("cd:request %d ", rqst) ;*/
/*printf("cd_family %d, cd_address %s, cd_alen %d\n",
cdp->cd_family, cdp->cd_address, cdp->cd_alen) ;*/
printf("option:%s\n", optp);*/
} else cd
->co_errfd
= -1 ;
for (p
= itab
; p
; p
= p
->next
)
if (p
->gpid
== 0 && p
->fd
>= 0 && p
->sock
< 0) break;
if (!p
) exit(0); /* return error can't find a line */
fprintf(stderr
, "allocate fd%d line %s\n", p
->fd
, p
->line
) ;
ioctl(p
->fd
, TIOCSIGNCAR
, 0) ;
if (cd
->co_errfd
) dup2(cd
->co_errfd
,2);
for (n
=3 ; n
< i
; n
++) close (n
) ;
execl("con", "con", cdp
->cd_address
, 0) ;
/*printf("cd: wait %d %d\n", i, n) ;*/
if (n
== 0) cd
->co_constatus
= n
;
fprintf(stderr
, "cd: con fails status %d\n", n
) ;
cd
->co_constatus
= (-1 <<16) | n
;
fprintf(stderr
, "cd: sending fd %d \n", p
->fd
) ;
ioctl(p
->fd
, TIOCCIGNCAR
, 0) ;
/* send connnection response message */
err
= sendrequest(cd
->co_sock
, resp
, cd
, optp
, optlen
, p
->fd
) ;
if(p
->fd
>= 0) closeline (p
, 1) ;
if (cd
->co_constatus
) goto end_session
;
for (p
= itab
; p
; p
= p
->next
)
if (p
->sock
== cd
->co_sock
) break;
if(!p
) exit(0); /* return no such connection */
fprintf(stderr
, "cd: received fd %d \n", p
->fd
) ;
ioctl(p
->fd
, TIOCSIGNCAR
, 0) ;
if (cd
->co_errfd
<= 0) dup2(cd
->co_errfd
,2);
for (n
=3 ; n
< i
; n
++) close (n
) ;
execl("con", "con", "drop" , 0) ;
fprintf(stderr
,"cd: wait %d %d\n", i
, n
) ;
if (n
== 0) cd
->co_constatus
= n
;
else cd
->co_constatus
= (-1 <<16) | n
;
fprintf(stderr
,"cd: dropped \n") ;
cd
->co_rqst
= resp
= CDFINISHRESPONSE
;
/* send connnection response message */
err
= sendrequest(cd
->co_sock
, resp
, cd
, 0, 0, 0) ;
} ; continue; /* end of if */
/*fprintf(stderr, "end_session\n") ;*/
FD_CLR (cd
->co_sock
, &rd_fdset
) ;
if (p
->fd
>= 0) closeline (p
, 0) ;
unlink ("/dev/connect") ;
for (p
= itab
; p
; p
= p
->next
)
if (p
->gpid
) kill (p
->gpid
, SIGHUP
);
sigpipe() { printf("SIGPIPE\n") ; fflush (stdout
) ; longjmp (terminate
); }
* open and prepare line for connectd
openline(p
) struct tab
*p
; {
p
->fd
= open (ttyn
, O_RDWR
|O_NDELAY
) ;
/* disassociate from our pgrp */
n
= open ("/dev/tty", O_RDWR
|O_NDELAY
) ;
ioctl (n
, TIOCNOTTY
, 0) ;
/* mark 'em to be watched for carrier */
FD_SET (p
->fd
, &wr_fdset
) ;
/* if set in a still open state */
ioctl(p
->fd
, TIOCCIGNCAR
, 0) ;
if (debug
) fprintf(stderr
, "openline: %s: fd %d\n", p
->line
, p
->fd
) ;
closeline(p
, i
) struct tab
*p
; {
if (debug
) fprintf(stderr
, "closeline: %s: fd %d ", p
->line
, p
->fd
) ;
FD_CLR (p
->fd
, &wr_fdset
) ;
if (debug
) fprintf(stderr
, "remove from use\n") ;
if (debug
) fprintf(stderr
, "entirely\n") ;
if (p
->gpid
) kill (p
->gpid
, SIGKILL
); /* no mercy */
if(p
->sock
>= 0) close (p
->sock
);
struct sigvec rvec
= { reset
, sigmask(SIGHUP
), 0 };
if (argc
> 1 && argv
[1][0] == '-') {
while (*cp
) switch (*cp
++) {
openlog("connectd", LOG_CONS
|LOG_ODELAY
, LOG_AUTH
);
sigvec(SIGTERM
, &rvec
, (struct sigvec
*)0);
signal(SIGSTOP
, SIG_IGN
);
signal(SIGTTIN
, SIG_IGN
);
signal(SIGTTOU
, SIG_IGN
);
if (setjmp(shutpass
) == 0)
if (oldhowto
& RB_SINGLE
)
if (runcom(oldhowto
) == 0)
register struct tab
*p
, *p1
;
close(creat(utmpf
, 0644));
signal(SIGALRM
, shutreset
);
(void) kill(-1, SIGTERM
); /* one chance to catch it */
while (wait((int *)0) != -1)
char shutfailm
[] = "WARNING: Something is hung (wont die); ps axl advised\n";
write(ct
, shutfailm
, sizeof (shutfailm
));
signal(SIGALRM
, SIG_DFL
);
f
= open(wtmpf
, O_WRONLY
|O_APPEND
);
SCPYN(wtmp
.ut_line
, "~");
SCPYN(wtmp
.ut_name
, "shutdown");
write(f
, (char *)&wtmp
, sizeof(wtmp
));
signal(SIGTERM
, SIG_DFL
);
signal(SIGALRM
, SIG_DFL
);
signal(SIGTSTP
, SIG_IGN
);
(void) open(ctty
, O_RDWR
);
execl(shell
, minus
, (char *)0);
while ((xpid
= wait((int *)0)) != pid
)
if (xpid
== -1 && errno
== ECHILD
)
(void) open("/", O_RDONLY
);
if (oldhowto
& RB_SINGLE
)
execl(shell
, shell
, runc
, (char *)0);
execl(shell
, shell
, runc
, "autoboot", (char *)0);
while (wait(&status
) != pid
)
f
= open(wtmpf
, O_WRONLY
|O_APPEND
);
SCPYN(wtmp
.ut_line
, "~");
SCPYN(wtmp
.ut_name
, "reboot");
write(f
, (char *)&wtmp
, sizeof(wtmp
));
struct sigvec mvec
= { merge
, sigmask(SIGTERM
), 0 };
* Multi-user. Listen for users leaving, SIGHUP's
* which indicate ttys has changed, and SIGTERM's which
* are used to shutdown the system.
sigvec(SIGHUP
, &mvec
, (struct sigvec
*)0);
omask
= sigblock(SIGHUP
);
/* must restart window system BEFORE emulator */
if (p
->wpid
== pid
|| p
->wpid
== -1)
if (p
->pid
== pid
|| p
->pid
== -1) {
/* disown the window system */
* Merge current contents of ttys file
* into in-core table of configured tty lines.
* Entered as signal handler for SIGHUP.
register struct ttyent
*t
;
while (t
= getttyent()) {
/* is it init's responsibility?
if ((t->ty_status & TTY_ON)) continue; */
if ((t
->ty_status
& TTY_ON
) == 0)
if (SCMPN(p
->line
, t
->ty_name
))
if (SCMPN(p
->comn
, t
->ty_getty
)) {
SCPYN(p
->comn
, t
->ty_getty
);
if (SCMPN(p
->wcmd
, t
->ty_window
)) {
p
->xflag
|= WCHANGE
|CHANGE
;
SCPYN(p
->wcmd
, t
->ty_window
);
* Make space for a new one
p1
= (struct tab
*)calloc(1, sizeof(*p1
));
syslog(LOG_ERR
, "no space for '%s' !?!", t
->ty_name
);
* Put new terminal at the end of the linked list.
for (p
= itab
; p
->next
; p
= p
->next
)
SCPYN(p
->line
, t
->ty_name
);
p
->xflag
|= FOUND
|CHANGE
;
SCPYN(p
->comn
, t
->ty_getty
);
if (strcmp(t
->ty_window
, "") != 0) {
SCPYN(p
->wcmd
, t
->ty_window
);
if ((p
->xflag
&FOUND
) == 0) {
/* window system should be started first */
/* send SIGHUP to get rid of connections */
if ((t
- p
->gettytime
) >= 60) {
} else if (p
->gettycnt
>= 5) {
signal(SIGTERM
, SIG_DFL
);
sigsetmask(0); /* since can be called from masked code */
syslog(LOG_ERR
, "'%s %s' failing, sleeping", p
->comn
, p
->line
);
execit(p
->comn
, p
->line
);
static unsigned utmpsize
;
static struct utmp
*utmp
;
if (utmpsize
< statbf
.st_size
) {
utmpsize
= statbf
.st_size
+ 10 * sizeof(struct utmp
);
utmp
= (struct utmp
*)realloc(utmp
, utmpsize
);
utmp
= (struct utmp
*)malloc(utmpsize
);
syslog(LOG_ERR
, "utmp malloc failed");
if (statbf
.st_size
&& utmp
) {
nutmp
= read(f
, utmp
, statbf
.st_size
);
nutmp
/= sizeof(struct utmp
);
for (u
= utmp
; u
< &utmp
[nutmp
] ; u
++) {
if (SCMPN(u
->ut_line
, p
->line
) ||
lseek(f
, ((long)u
)-((long)utmp
), L_SET
);
write(f
, (char *)u
, sizeof(*u
));
f
= open(wtmpf
, O_WRONLY
|O_APPEND
);
SCPYN(wtmp
.ut_line
, p
->line
);
write(f
, (char *)&wtmp
, sizeof(wtmp
));
* After a proper login force reset
* of error detection code in dfork.
/* if window system dies, mark it for restart */
if ((t
- p
->windtime
) >= 60) {
} else if (p
->windcnt
>= 5) {
signal(SIGTERM
, SIG_DFL
);
sigsetmask(0); /* since can be called from masked code */
syslog(LOG_ERR
, "'%s %s' failing, sleeping", p
->wcmd
, p
->line
);
execit(p
->wcmd
, p
->line
);
#define NARGS 20 /* must be at least 4 */
#define ARGLEN 512 /* total size for all the argument strings */
char *arg
; /* last argument on line */
char *argv
[NARGS
], args
[ARGLEN
], *envp
[1];
register char *ap
= args
;
* First we have to set up the argument vector.
* "prog arg1 arg2" maps to exec("prog", "-", "arg1", "arg2").
for (i
= 1; i
< NARGS
- 2; i
++) {
if ((c
= *sp
++) == '\0' || ap
>= &args
[ARGLEN
-1]) {
execve(argv
[0], &argv
[1], envp
);
/* report failure of exec */
syslog(LOG_ERR
, "%s: %m", argv
[0]);
sleep(10); /* prevent failures from eating machine */