#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <ctype.h>
#include <string.h>
#include <termio.h>
#include <sys/stat.h>
#include <signal.h>
#include <stdarg.h>
#include "tmstruct.h"
#include "tmextern.h"
#include "ttymon.h"
static int nflg = 0;
static int iflg = 0;
static int fflg = 0;
static int lflg = 0;
static void usage(void);
static void check_ref(void);
static void add_entry(struct Gdef *) __NORETURN;
static void remove_entry(char *);
static int copy_file(FILE *, FILE *, int, int);
static int verify(char *, int);
static FILE *open_temp(char *);
int
main(int argc, char *argv[])
{
int c;
int errflg = 0;
int aflg = 0;
int bflg = 0;
int ret;
const char *argtmp;
char *nextlabel;
struct Gdef ttydef, *ptr;
if (argc == 1)
usage();
memset(&ttydef, 0, sizeof (ttydef));
ptr = &ttydef;
while ((c = getopt(argc, argv, "a:n:i:f:br:l")) != -1) {
switch (c) {
case 'a':
aflg = TRUE;
ptr->g_id = optarg;
break;
case 'n':
nflg = TRUE;
ptr->g_nextid = optarg;
break;
case 'i':
iflg = TRUE;
ptr->g_iflags = optarg;
break;
case 'f':
fflg = TRUE;
ptr->g_fflags = optarg;
break;
case 'b':
bflg = TRUE;
ptr->g_autobaud |= A_FLAG;
break;
case 'r':
if ((argc > 3) || (optind < argc))
usage();
remove_entry(optarg);
break;
case 'l':
lflg = TRUE;
if (argc > 3)
usage();
if ((ret = check_version(TTYDEFS_VERS, TTYDEFS)) != 0) {
if (ret != 2) {
(void) fprintf(stderr,
"%s version number is incorrect "
"or missing.\n", TTYDEFS);
exit(1);
}
(void) fprintf(stderr,
"sttydefs: can't open %s.\n", TTYDEFS);
exit(1);
}
if (argv[optind] == NULL) {
read_ttydefs(NULL, TRUE);
printf("\n");
check_ref();
} else {
if (argc == 3) {
if (verify(argv[optind], 0) != 0) {
errflg++;
break;
}
argtmp = argv[optind];
} else {
argtmp = argv[optind] + 2;
}
read_ttydefs(argtmp, TRUE);
if (Ndefs == 0) {
(void) fprintf(stderr,
"ttylabel <%s> not found.\n",
argtmp);
exit(1);
}
nextlabel = Gdef[--Ndefs].g_nextid;
Ndefs = 0;
read_ttydefs(nextlabel, FALSE);
if (Ndefs == 0) {
(void) printf("\nWarning -- nextlabel "
"<%s> of <%s> does not reference "
"any existing ttylabel.\n",
nextlabel, argtmp);
}
}
exit(0);
case '?':
errflg++;
break;
}
if (errflg)
usage();
}
if (optind < argc)
usage();
if (aflg) {
add_entry(ptr);
}
if ((iflg) || (fflg) || (bflg) || (nflg))
usage();
return (0);
}
static int
verify(char *arg, int maxarglen)
{
if (*arg == '-') {
(void) fprintf(stderr, "Invalid argument -- %s.\n", arg);
return (-1);
}
if ((maxarglen) && ((int)strlen(arg) > maxarglen)) {
arg[maxarglen] = '\0';
(void) fprintf(stderr, "string too long, truncated to %s.\n",
arg);
return (-1);
}
return (0);
}
static void
usage(void)
{
(void) fprintf(stderr, "Usage:\tsttydefs -a ttylabel [-n nextlabel] "
"[-i initial-flags]\n\t\t [-f final-flags] [-b]\n");
(void) fprintf(stderr, "\tsttydefs -r ttylabel\n");
(void) fprintf(stderr, "\tsttydefs -l [ttylabel]\n");
exit(2);
}
static void
add_entry(struct Gdef *ttydef)
{
FILE *fp;
int errflg = 0;
char tbuf[BUFSIZ], *tp;
int add_version = FALSE;
if (getuid()) {
(void) fprintf(stderr, "User not privileged for operation.\n");
exit(1);
}
tp = tbuf;
*tp = '\0';
if ((fp = fopen(TTYDEFS, "r")) != NULL) {
if (check_version(TTYDEFS_VERS, TTYDEFS) != 0) {
(void) fprintf(stderr,
"%s version number is incorrect or missing.\n",
TTYDEFS);
exit(1);
}
if (find_label(fp, ttydef->g_id)) {
(void) fclose(fp);
(void) fprintf(stderr,
"Invalid request -- ttylabel <%s> already "
"exists.\n",
ttydef->g_id);
exit(1);
}
(void) fclose(fp);
} else {
add_version = TRUE;
}
if ((fp = fopen(TTYDEFS, "a+")) == NULL) {
(void) fprintf(stderr, "Could not open \"%s\": %s", TTYDEFS,
strerror(errno));
exit(1);
}
if (add_version) {
(void) fprintf(fp, "# VERSION=%d\n", TTYDEFS_VERS);
}
if (!iflg)
ttydef->g_iflags = DEFAULT.g_iflags;
else
if (check_flags(ttydef->g_iflags) != 0)
errflg++;
if (!fflg)
ttydef->g_fflags = DEFAULT.g_fflags;
else
if (check_flags(ttydef->g_fflags) != 0)
errflg++;
if (errflg)
exit(1);
if (!nflg)
ttydef->g_nextid = ttydef->g_id;
if (ttydef->g_autobaud & A_FLAG) {
(void) fprintf(fp, "%s:%s:%s:A:%s\n", ttydef->g_id,
ttydef->g_iflags, ttydef->g_fflags, ttydef->g_nextid);
} else {
(void) fprintf(fp, "%s:%s:%s::%s\n", ttydef->g_id,
ttydef->g_iflags, ttydef->g_fflags, ttydef->g_nextid);
}
(void) fclose(fp);
exit(0);
}
static void
remove_entry(char *ttylabel)
{
FILE *tfp;
int line;
FILE *fp;
char *tname = "/etc/.ttydefs";
if (getuid()) {
(void) fprintf(stderr, "User not privileged for operation.\n");
exit(1);
}
fp = fopen(TTYDEFS, "r");
if (fp == NULL) {
(void) fprintf(stderr, "Could not open \"%s\": %s", TTYDEFS,
strerror(errno));
exit(1);
}
if (check_version(TTYDEFS_VERS, TTYDEFS) != 0) {
(void) fprintf(stderr,
"%s version number is incorrect or missing.\n", TTYDEFS);
exit(1);
}
if ((line = find_label(fp, ttylabel)) == 0) {
(void) fprintf(stderr,
"Invalid request, ttylabel <%s> does not exist.\n",
ttylabel);
exit(1);
}
tfp = open_temp(tname);
if (line != 1)
if (copy_file(fp, tfp, 1, line - 1)) {
(void) fprintf(stderr, "Error accessing temp file.\n");
exit(1);
}
if (copy_file(fp, tfp, line + 1, -1)) {
(void) fprintf(stderr, "Error accessing temp file.\n");
exit(1);
}
(void) fclose(fp);
if (fclose(tfp) == EOF) {
(void) unlink(tname);
(void) fprintf(stderr, "Error closing temp file.\n");
exit(1);
}
(void) unlink(TTYDEFS);
if (rename(tname, TTYDEFS) != 0) {
perror("Rename failed");
(void) unlink(tname);
exit(1);
}
exit(0);
}
static FILE *
open_temp(char *tname)
{
FILE *fp;
struct sigaction sigact;
sigact.sa_flags = 0;
sigact.sa_handler = SIG_IGN;
(void) sigemptyset(&sigact.sa_mask);
(void) sigaddset(&sigact.sa_mask, SIGHUP);
(void) sigaddset(&sigact.sa_mask, SIGINT);
(void) sigaddset(&sigact.sa_mask, SIGQUIT);
(void) sigaction(SIGHUP, &sigact, NULL);
(void) sigaction(SIGINT, &sigact, NULL);
(void) sigaction(SIGQUIT, &sigact, NULL);
(void) umask(0333);
if (access(tname, 0) != -1) {
(void) fprintf(stderr, "tempfile busy; try again later.\n");
exit(1);
}
fp = fopen(tname, "w");
if (fp == NULL) {
perror("Cannot create tempfile");
exit(1);
}
return (fp);
}
static int
copy_file(FILE *fp, FILE *tfp, int start, int finish)
{
int i;
char dummy[BUFSIZ];
rewind(fp);
if (start != 1) {
for (i = 1; i < start; i++)
if (!fgets(dummy, BUFSIZ, fp))
return (-1);
}
if (finish != -1) {
for (i = start; i <= finish; i++) {
if (!fgets(dummy, BUFSIZ, fp))
return (-1);
if (fputs(dummy, tfp) == EOF)
return (-1);
}
} else {
for (;;) {
if (fgets(dummy, BUFSIZ, fp) == NULL) {
if (feof(fp))
break;
else
return (-1);
}
if (fputs(dummy, tfp) == EOF)
return (-1);
}
}
return (0);
}
static void
check_ref(void)
{
int i;
struct Gdef *np;
np = &Gdef[0];
for (i = 0; i < Ndefs; i++, np++) {
if (find_def(np->g_nextid) == NULL) {
(void) printf("Warning -- nextlabel <%s> of <%s> "
"does not reference any existing ttylabel.\n",
np->g_nextid, np->g_id);
}
}
}
void
log(const char *msg, ...)
{
va_list ap;
if (lflg) {
va_start(ap, msg);
(void) vprintf(msg, ap);
va_end(ap);
(void) printf("\n");
} else {
va_start(ap, msg);
(void) vfprintf(stderr, msg, ap);
va_end(ap);
(void) fprintf(stderr, "\n");
}
}