* Copyright (c) 1993 Christoph M. Robitschko
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Christoph M. Robitschko
* 4. The name of the author may not be used to endorse or promote products
* derived from this software withough specific prior written permission
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* Everything that has to do with the getty table.
* This includes starting child precesses.
# define alloca __builtin_alloca
int checkstatus
= DEF_CHECKSTATUS
;
int checktime
= DEF_CHECKTIME
;
int def_waittimes
[] = {0,0,0,30,60,300,1800};
int *waittimes
= def_waittimes
;
* remove a ttytab entry from the list
/* Delete the entry from utmp, make log to wtmp */
logwtmp(tt
->name
, "", "");
/* unlink it from the list first, in case of unexpected signal */
tt
->next
->prev
= tt
->prev
;
tt
->prev
->next
= tt
->next
;
/* free the associated memory */
if (tt
->name
) free(tt
->name
);
if (tt
->type
) free(tt
->type
);
for (s
= tt
->argv
; *s
; s
++)
* create or change a ttytab entry based on the information in a ttyent struct
ent_to_tab(ent
, tt
, tab
, flags
)
const struct ttyent
*ent
;
/* Do we really need this entry ? */
if (ent
->ty_status
& TTY_ON
== 0)
Debug(4, "Processing tty entry %s", ent
->ty_name
);
/* Allocate a ttytab entry, if not already there */
tt
= malloc(sizeof(*tt
));
tt
->starttime
= (time_t)0;
tt
->prev
= (ttytab_t
*)0;
Debug(5, "Creating new ttytab entry");
Debug(5, "Reusing existing ttytab entry");
tt
->intflags
|= (flags
| INIT_SEEN
);
/* fill each field in from the ttyent, if it has changed */
if (strcmp(ent
->ty_name
, tt
->name
)) {
Debug(5, "name differs: old=\"%s\" new=\"%s\"", tt
->name
, ent
->ty_name
);
if (tt
->name
) free(tt
->name
);
tt
->name
= newstring(ent
->ty_name
);
tt
->intflags
|= INIT_CHANGED
;
if (!(argstr
= alloca(strlen(ent
->ty_getty
) +strlen(tt
->name
) +2)))
/* sprintf(argstr, "%s %s", ent->ty_getty, tt->name); */
strcpy(argstr
, ent
->ty_getty
);
strcat(argstr
, tt
->name
);
if (argv_changed(argstr
, (const char **)tt
->argv
)) {
for (s
= tt
->argv
; *s
; s
++)
tt
->argv
= string_to_argv(argstr
, (int *)0, (char **)0);
tt
->intflags
|= INIT_CHANGED
;
Debug(5, "argv differs.");
if (strcmp(ent
->ty_type
, tt
->type
)) {
if (tt
->type
) free(tt
->type
);
tt
->type
= newstring(ent
->ty_type
);
tt
->intflags
|= INIT_CHANGED
;
Debug(5, "type differs.");
if (!(tt
->intflags
& INIT_CHANGED
)) {
Debug(5, "entry unchanged.");
Debug(5, "entry has been changed.");
syslog(LOG_ERR
, "Out of memory in ent_to_tab");
callout(retrytime
, CO_ENT2TAB
, NULL
);
* compares a string and an argv
argv_changed(string
, argv
)
for (ss
= string
, sa
= argv
; *sa
; sa
++) {
register int len
= strlen(*sa
);
if (strncmp(*sa
, ss
, len
))
if ((*ss
!= ' ') && (*ss
!= '\t') && (*ss
))
while ((*ss
== ' ') || (*ss
== '\t')) ss
++;
if (*ss
) /* String longer than argv ? */
* breaks up a string into words. Speration characters are SPACE and TAB,
* unless prepended by a backslash \ or within double quotes ".
* Quotes and backslash can be escaped by an additional \.
* If errtext is non-NULL, it is set to point to an error message.
string_to_argv(string
, rargc
, errtext
)
Debug(4, "string_to_argv(\"%s\")", string
);
* argv is allocated in chunks of ALLOC_ARGV pointers; if it runs
* out of space, it is realloc'ed with ALLOC_ARGV more pointers.
argv
= (char **)malloc(ALLOC_ARGV
* sizeof(char *));
for (; (*s
== ' ') || (*s
== '\t'); s
++); /* Skip blanks */
if (!(buf
= (char *)malloc(strlen(s
)+1))) goto malloc_fail
;
*errtext
= "Unmatched \".";
if (!(argv
[argc
] = (char *)realloc(buf
, strlen(buf
)+1))) goto malloc_fail
;
if (++argc
>= alloc_argc
) {
alloc_argc
+= ALLOC_ARGV
;
if (!(ra
= realloc(argv
, alloc_argc
* sizeof(char **))))
/* Terminate argv with a NULL pointer and return */
for (ra
= argv
; *ra
; ra
++)
Debug(5, " \"%s\"", *ra
);
/* free all so-far allocated memory and return a NULL pointer */
* start a getty process for a ttytab entry
Debug(2, "do_getty for %s", tt
->name
);
if (tt
->intflags
& INIT_FAILSLEEP
)
tt
->intflags
&= ~INIT_FAILSLEEP
;
/* Delete old entry from utmp, make log to wtmp */
logwtmp(tt
->name
, "", "");
if ((checkstatus
&& status
) || (checktime
&& (time(0) - tt
->starttime
<= checktime
))) {
if (tt
->intflags
& INIT_FAILED
) {
if (++tt
->failcount
>= nwaittimes
)
tt
->failcount
= nwaittimes
;
tt
->intflags
|= INIT_FAILED
;
if (waittimes
[tt
->failcount
]) {
tt
->intflags
|= INIT_FAILSLEEP
;
syslog(LOG_WARNING
, "getty \"%s\" for %s failed, sleeping", tt
->argv
[0], tt
->name
);
callout (waittimes
[tt
->failcount
], CO_GETTY
, (void *)tt
);
tt
->intflags
&= ~INIT_FAILED
;
syslog(LOG_ERR
, "fork failed for %s: %m", tt
->name
);
callout(retrytime
, CO_FORK
, (void *)tt
);
iputenv("TERM", tt
->type
);
if (tt
->intflags
& INIT_OPEN
) {
char *device
= alloca(strlen(tt
->name
) + sizeof("/dev/"));
/* sprintf(device, "/dev/%s", tt->name); */
strcat(device
, tt
->name
);
fd
= open(device
, O_RDWR
);
syslog(LOG_ERR
, "open %s failed: %m", device
);
syslog(LOG_ERR
, "login_tty for %s failed: %m", device
);
closelog(); /* Necessary, because dup2 fails otherwise (?) */
if (tt
->intflags
& INIT_ARG0
)
execve(tt
->argv
[0], tt
->argv
+1, ienviron
);
execve(tt
->argv
[0], tt
->argv
, ienviron
);
syslog(LOG_ERR
, "Exec \"%s\" failed for %s: %m", tt
->argv
[0], tt
->name
);