Imported patches from Arch Linux's bootlogd to avoid special

characters in log file. Also makes parsing easier.
This commit is contained in:
Jesse Smith 2018-02-20 19:16:42 -04:00
parent 3e43bb7ccd
commit e80878c555

View File

@ -68,11 +68,6 @@ int didnl = 1;
int createlogfile = 0; int createlogfile = 0;
int syncalot = 0; int syncalot = 0;
struct line {
char buf[256];
int pos;
} line;
/* /*
* Console devices as listed on the kernel command line and * Console devices as listed on the kernel command line and
* the mapping to actual devices in /dev * the mapping to actual devices in /dev
@ -108,60 +103,59 @@ void handler(int sig)
/* /*
* Scan /dev and find the device name. * Scan /dev and find the device name.
*/ */
static int findtty(char *res, const char *startdir, size_t rlen, dev_t dev) static int findtty(char *res, const char *startdir, int rlen, dev_t dev)
{ {
DIR *dir; DIR *dir;
struct dirent *ent; struct dirent *ent;
struct stat st;
int r = -1; int r = -1;
char *olddir = getcwd(NULL, 0);
if ((dir = opendir(startdir)) == NULL) { if (chdir(startdir) < 0 || (dir = opendir(".")) == NULL) {
int msglen = strlen(startdir) + 11; int msglen = strlen(startdir) + 11;
char *msg = malloc(msglen); char *msg = malloc(msglen);
snprintf(msg, msglen, "bootlogd: %s", startdir); snprintf(msg, msglen, "bootlogd: %s", startdir);
perror(msg); perror(msg);
free(msg); free(msg);
chdir(olddir);
return -1; return -1;
} }
while ((ent = readdir(dir)) != NULL) { while ((ent = readdir(dir)) != NULL) {
struct stat st; if (lstat(ent->d_name, &st) != 0)
int pathlen = strlen(startdir) + strlen(ent->d_name) + 2;
char *path = malloc(pathlen);
snprintf(path, pathlen, "%s/%s", startdir, ent->d_name);
if (lstat(path, &st) != 0) {
free(path);
continue; continue;
}
if (S_ISDIR(st.st_mode) if (S_ISDIR(st.st_mode)
&& 0 != strcmp(".", ent->d_name) && 0 != strcmp(".", ent->d_name)
&& 0 != strcmp("..", ent->d_name)) { && 0 != strcmp("..", ent->d_name)) {
char *path = malloc(rlen);
snprintf(path, rlen, "%s/%s", startdir, ent->d_name);
r = findtty(res, path, rlen, dev); r = findtty(res, path, rlen, dev);
if (0 == r) { /* device found, return */
free(path); free(path);
if (0 == r) { /* device found, return */
closedir(dir); closedir(dir);
chdir(olddir);
return 0; return 0;
} }
free(path);
continue; continue;
} }
free(path);
path = NULL;
if (!S_ISCHR(st.st_mode)) if (!S_ISCHR(st.st_mode))
continue; continue;
if (st.st_rdev == dev) { if (st.st_rdev == dev) {
if ( (strlen(ent->d_name) + strlen(startdir) + 1) >= rlen) { if ( (int) (strlen(ent->d_name) + strlen(startdir) + 1) >= rlen) {
fprintf(stderr, "bootlogd: console device name too long\n"); fprintf(stderr, "bootlogd: console device name too long\n");
closedir(dir); closedir(dir);
chdir(olddir);
return -1; return -1;
} else { } else {
snprintf(res, rlen, "%s/%s", startdir, ent->d_name); snprintf(res, rlen, "%s/%s", startdir, ent->d_name);
closedir(dir); closedir(dir);
chdir(olddir);
return 0; return 0;
} }
} }
} }
closedir(dir); closedir(dir);
chdir(olddir);
return r; return r;
} }
@ -209,7 +203,7 @@ int findpty(int *master, int *slave, char *name)
* See if a console taken from the kernel command line maps * See if a console taken from the kernel command line maps
* to a character device we know about, and if we can open it. * to a character device we know about, and if we can open it.
*/ */
int isconsole(char *s, char *res, size_t rlen) int isconsole(char *s, char *res, int rlen)
{ {
struct consdev *c; struct consdev *c;
int l, sl, i, fd; int l, sl, i, fd;
@ -239,21 +233,17 @@ int isconsole(char *s, char *res, size_t rlen)
* Find out the _real_ console. Assume that stdin is connected to * Find out the _real_ console. Assume that stdin is connected to
* the console device (/dev/console). * the console device (/dev/console).
*/ */
int consolename(char *res, size_t rlen) int consolename(char *res, int rlen)
{ {
#ifdef TIOCGDEV #ifdef TIOCGDEV
unsigned int kdev; unsigned int kdev;
#endif #endif
struct stat st; struct stat st, st2;
int n;
#ifdef __linux__
char buf[256]; char buf[256];
char *p; char *p;
struct stat st2;
int didmount = 0; int didmount = 0;
int r; int n, r;
int fd; int fd;
#endif
fstat(0, &st); fstat(0, &st);
if (major(st.st_rdev) != 5 || minor(st.st_rdev) != 1) { if (major(st.st_rdev) != 5 || minor(st.st_rdev) != 1) {
@ -304,10 +294,9 @@ int consolename(char *res, size_t rlen)
perror("bootlogd: /proc/cmdline"); perror("bootlogd: /proc/cmdline");
} else { } else {
buf[0] = 0; buf[0] = 0;
if ((n = read(fd, buf, sizeof(buf) - 1)) >= 0) { if ((n = read(fd, buf, sizeof(buf) - 1)) >= 0)
r = 0; r = 0;
buf[sizeof(buf)-1] = 0; /* enforce null termination */ else
} else
perror("bootlogd: /proc/cmdline"); perror("bootlogd: /proc/cmdline");
close(fd); close(fd);
} }
@ -357,71 +346,75 @@ int consolename(char *res, size_t rlen)
*/ */
void writelog(FILE *fp, unsigned char *ptr, int len) void writelog(FILE *fp, unsigned char *ptr, int len)
{ {
int dosync = 0;
int i;
static int first_run = 1;
static int inside_esc = 0;
for (i = 0; i < len; i++) {
int ignore = 0;
/* prepend date to every line */
if (*(ptr-1) == '\n' || first_run) {
time_t t; time_t t;
char *s; char *s;
char tmp[8];
int olen = len;
int dosync = 0;
int tlen, opos;
while (len > 0) {
tmp[0] = 0;
if (didnl) {
time(&t); time(&t);
s = ctime(&t); s = ctime(&t);
fprintf(fp, "%.24s: ", s); fprintf(fp, "%.24s: ", s);
didnl = 0;
}
switch (*ptr) {
case 27: /* ESC */
strcpy(tmp, "^[");
break;
case '\r':
line.pos = 0;
break;
case 8: /* ^H */
if (line.pos > 0) line.pos--;
break;
case '\n':
didnl = 1;
dosync = 1; dosync = 1;
break; first_run = 0;
case '\t': }
opos = line.pos;
line.pos += ( (line.pos / 8) + 1) * 8; /* remove escape sequences, but do it in a way that allows us to stop
if (line.pos >= (int) sizeof(line.buf)) * in the middle in case the string was cut off */
line.pos = (int) sizeof(line.buf) - 1; if (inside_esc == 1) {
while (opos <= line.pos) /* first '[' is special because if we encounter it again, it should be considered the final byte */
{ if (*ptr == '[') {
memcpy(line.buf + opos, " ", 1); /* multi char sequence */
opos++; ignore = 1;
inside_esc = 2;
} else {
/* single char sequence */
if (*ptr >= 64 && *ptr <= 95) {
ignore = 1;
}
inside_esc = 0;
}
} else if (inside_esc == 2) {
switch (*ptr) {
case '0' ... '9': /* intermediate chars of escape sequence */
case ';':
case 32 ... 47:
if (inside_esc) {
ignore = 1;
} }
line.buf[line.pos] = '\0';
printf("%s\n", line.buf);
break; break;
case 32 ... 127: case 64 ... 126: /* final char of escape sequence */
case 161 ... 255: if (inside_esc) {
tmp[0] = *ptr; ignore = 1;
tmp[1] = 0; inside_esc = 0;
break; }
default:
sprintf(tmp, "\\%03o", *ptr);
break; break;
} }
} else {
switch (*ptr) {
case '\r':
ignore = 1;
break;
case 27: /* ESC */
ignore = 1;
inside_esc = 1;
break;
}
}
if (!ignore) {
fwrite(ptr, sizeof(char), 1, fp);
}
ptr++; ptr++;
len--;
tlen = strlen(tmp);
if (tlen && (line.pos + tlen < (int)sizeof(line.buf))) {
memcpy(line.buf + line.pos, tmp, tlen);
line.pos += tlen;
} }
if (didnl) {
fprintf(fp, "%s\n", line.buf);
memset(&line, 0, sizeof(line));
}
}
if (dosync) { if (dosync) {
fflush(fp); fflush(fp);
if (syncalot) { if (syncalot) {
@ -429,7 +422,7 @@ void writelog(FILE *fp, unsigned char *ptr, int len)
} }
} }
outptr += olen; outptr += len;
if (outptr >= endptr) if (outptr >= endptr)
outptr = ringbuf; outptr = ringbuf;
@ -496,9 +489,6 @@ int main(int argc, char **argv)
int realfd; int realfd;
int n, m, i; int n, m, i;
int todo; int todo;
#ifndef __linux__ /* BSD-style ioctl needs an argument. */
int on = 1;
#endif
fp = NULL; fp = NULL;
logfile = LOGFILE; logfile = LOGFILE;
@ -571,20 +561,15 @@ int main(int argc, char **argv)
return 1; return 1;
} }
#ifdef __linux__
(void)ioctl(0, TIOCCONS, NULL); (void)ioctl(0, TIOCCONS, NULL);
#if 1
/* Work around bug in 2.1/2.2 kernels. Fixed in 2.2.13 and 2.3.18 */ /* Work around bug in 2.1/2.2 kernels. Fixed in 2.2.13 and 2.3.18 */
if ((n = open("/dev/tty0", O_RDWR)) >= 0) { if ((n = open("/dev/tty0", O_RDWR)) >= 0) {
(void)ioctl(n, TIOCCONS, NULL); (void)ioctl(n, TIOCCONS, NULL);
close(n); close(n);
} }
#endif #endif
#ifdef __linux__ if (ioctl(pts, TIOCCONS, NULL) < 0) {
if (ioctl(pts, TIOCCONS, NULL) < 0)
#else /* BSD usage of ioctl TIOCCONS. */
if (ioctl(pts, TIOCCONS, &on) < 0)
#endif
{
fprintf(stderr, "bootlogd: ioctl(%s, TIOCCONS): %s\n", fprintf(stderr, "bootlogd: ioctl(%s, TIOCCONS): %s\n",
buf, strerror(errno)); buf, strerror(errno));
return 1; return 1;