summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rwxr-xr-xinit.d/bootmisc.sh6
-rwxr-xr-xinit.d/syslog6
-rw-r--r--src/Makefile10
-rw-r--r--src/atomicio.c62
-rw-r--r--src/atomicio.h39
-rw-r--r--src/lib.c183
-rw-r--r--src/lib.h26
-rw-r--r--src/sendbug.c574
9 files changed, 900 insertions, 10 deletions
diff --git a/Makefile b/Makefile
index 45430a5..070796d 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-VERSION=1.5.0
+VERSION=1.5.1
PV =alpine-baselayout-$(VERSION)
TARBALL =$(PV).tar.gz
@@ -8,7 +8,7 @@ GENERATED_FILES =TZ hosts profile
ETC_FILES =$(GENERATED_FILES) group fstab inittab nsswitch.conf \
passwd protocols services shadow shells issue mdev.conf \
crontab sysctl.conf modprobe.conf
-CONFD_FILES = $(addprefix conf.d/, cron localinit rdate tuntap vlan watchdog)
+CONFD_FILES = $(addprefix conf.d/, cron localinit rdate syslog tuntap vlan watchdog)
SBIN_FILES =runscript-alpine.sh functions.sh rc_add rc_delete rc_status\
modules-update ifenslave
RC_SH_FILES =rc-services.sh
diff --git a/init.d/bootmisc.sh b/init.d/bootmisc.sh
index 846f236..6629ea6 100755
--- a/init.d/bootmisc.sh
+++ b/init.d/bootmisc.sh
@@ -1,7 +1,5 @@
#!/bin/sh
-#
-# Save kernel messages in /var/log/dmesg
-#
-dmesg -s 65536 > /var/log/dmesg
+mkdir -p /var/run
+dmesg -s 65536 > /var/run/dmesg.boot
diff --git a/init.d/syslog b/init.d/syslog
index f60a981..ad7361d 100755
--- a/init.d/syslog
+++ b/init.d/syslog
@@ -2,12 +2,14 @@
start() {
ebegin "Starting system logging"
- syslogd && klogd
+ klogd ${KLOGD_OPTS}
+ syslogd ${SYSLOGD_OPTS}
eend $?
}
stop () {
ebegin "Stopping system logging"
- killall klogd && killall syslogd
+ killall klogd
+ killall syslogd
eend $?
}
diff --git a/src/Makefile b/src/Makefile
index 006fd76..e5c4a25 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -3,7 +3,8 @@ CC = gcc
LD = gcc
SBIN_TARGETS = runscript readahead cttyhack
-TARGET = $(BIN_TARGETS) $(SBIN_TARGETS)
+USR_BIN_TARGETS = sendbug
+TARGET = $(BIN_TARGETS) $(SBIN_TARGETS) $(USR_BIN_TARGETS)
.PHONY: all clean
all: $(TARGET)
@@ -11,12 +12,17 @@ all: $(TARGET)
%: %.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
+sendbug: atomicio.o sendbug.o lib.o
+ $(CC) $(LDFLAGS) -o $@ $^
+
clean:
rm -f $(TARGET) *.o core *~
install: $(TARGET)
install -m 0755 -d $(DESTDIR)/bin
install -m 0755 -d $(DESTDIR)/sbin
-# install -m 0755 $(BIN_TARGETS) $(DESTDIR)/bin
+# install -m 0755 -d $(DESTDIR)/usr
+# install -m 0755 -d $(DESTDIR)/usr/bin
+# install -m 0755 $(USR_BIN_TARGETS) $(DESTDIR)/usr/bin
install -m 0755 $(SBIN_TARGETS) $(DESTDIR)/sbin
diff --git a/src/atomicio.c b/src/atomicio.c
new file mode 100644
index 0000000..d580010
--- /dev/null
+++ b/src/atomicio.c
@@ -0,0 +1,62 @@
+/* $OpenBSD: atomicio.c,v 1.1.1.1 2007/03/23 01:47:11 ray Exp $ */
+/*
+ * Copyright (c) 2006 Damien Miller. All rights reserved.
+ * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved.
+ * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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.
+ *
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <sys/uio.h>
+
+#include <errno.h>
+#include <string.h>
+
+#include "atomicio.h"
+
+/*
+ * ensure all of data on socket comes through. f==read || f==vwrite
+ */
+size_t
+atomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n)
+{
+ char *s = _s;
+ size_t pos = 0;
+ ssize_t res;
+
+ while (n > pos) {
+ res = (f) (fd, s + pos, n - pos);
+ switch (res) {
+ case -1:
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ return 0;
+ case 0:
+ errno = EPIPE;
+ return pos;
+ default:
+ pos += (size_t)res;
+ }
+ }
+ return (pos);
+}
diff --git a/src/atomicio.h b/src/atomicio.h
new file mode 100644
index 0000000..72595db
--- /dev/null
+++ b/src/atomicio.h
@@ -0,0 +1,39 @@
+/* $OpenBSD: atomicio.h,v 1.1.1.1 2007/03/23 01:47:11 ray Exp $ */
+
+/*
+ * Copyright (c) 2006 Damien Miller. All rights reserved.
+ * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef _ATOMICIO_H
+#define _ATOMICIO_H
+
+/*
+ * Ensure all of data on socket comes through. f==read || f==vwrite
+ */
+size_t atomicio(ssize_t (*)(int, void *, size_t), int, void *, size_t);
+
+#define vwrite (ssize_t (*)(int, void *, size_t))write
+
+#endif /* _ATOMICIO_H */
diff --git a/src/lib.c b/src/lib.c
new file mode 100644
index 0000000..03433c8
--- /dev/null
+++ b/src/lib.c
@@ -0,0 +1,183 @@
+/* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 2004 Ted Unangst and Todd Miller
+ * Copyright (c) 2007 Natanael Copa <natanael.copa@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+# define LLONG_MAX 9223372036854775807LL
+# define LLONG_MIN (-LLONG_MAX - 1LL)
+
+
+#define INVALID 1
+#define TOOSMALL 2
+#define TOOLARGE 3
+
+#include <sysexits.h>
+#include "lib.h"
+
+#ifndef HAVE_XREALLOC
+void *
+xrealloc(void *ptr, size_t size)
+{
+ ptr = realloc(ptr, size);
+ if (ptr == NULL)
+ err(EX_OSERR, "realloc");
+ return ptr;
+}
+#endif
+
+
+#ifndef HAVE_STRLCAT
+/*
+ * Appends src to string dst of size siz (unlike strncat, siz is the
+ * full size of dst, not space left). At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
+ * Returns strlen(src) + MIN(siz, strlen(initial dst)).
+ * If retval >= siz, truncation occurred.
+ */
+size_t
+strlcat(char *dst, const char *src, size_t siz)
+{
+ char *d = dst;
+ const char *s = src;
+ size_t n = siz;
+ size_t dlen;
+
+ /* Find the end of dst and adjust bytes left but don't go past end */
+ while (n-- != 0 && *d != '\0')
+ d++;
+ dlen = d - dst;
+ n = siz - dlen;
+
+ if (n == 0)
+ return(dlen + strlen(s));
+ while (*s != '\0') {
+ if (n != 1) {
+ *d++ = *s;
+ n--;
+ }
+ s++;
+ }
+ *d = '\0';
+
+ return(dlen + (s - src)); /* count does not include NUL */
+}
+#endif /* HAVE_STRLCAT */
+
+#ifdef HAVE_STRLCPY
+/*
+ * Copy src to string dst of size siz. At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t
+strlcpy(char *dst, const char *src, size_t siz)
+{
+ char *d = dst;
+ const char *s = src;
+ size_t n = siz;
+
+ /* Copy as many bytes as will fit */
+ if (n != 0) {
+ while (--n != 0) {
+ if ((*d++ = *s++) == '\0')
+ break;
+ }
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src */
+ if (n == 0) {
+ if (siz != 0)
+ *d = '\0'; /* NUL-terminate dst */
+ while (*s++)
+ ;
+ }
+
+ return(s - src - 1); /* count does not include NUL */
+}
+#endif /* HAVE_STRLCPY */
+
+#ifdef HAVE_STRTONUM
+long long
+strtonum(const char *numstr, long long minval, long long maxval,
+ const char **errstrp)
+{
+ long long ll = 0;
+ char *ep;
+ int error = 0;
+ struct errval {
+ const char *errstr;
+ int err;
+ } ev[4] = {
+ { NULL, 0 },
+ { "invalid", EINVAL },
+ { "too small", ERANGE },
+ { "too large", ERANGE },
+ };
+
+ ev[0].err = errno;
+ errno = 0;
+ if (minval > maxval)
+ error = INVALID;
+ else {
+ ll = strtoll(numstr, &ep, 10);
+ if (numstr == ep || *ep != '\0')
+ error = INVALID;
+ else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
+ error = TOOSMALL;
+ else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
+ error = TOOLARGE;
+ }
+ if (errstrp != NULL)
+ *errstrp = ev[error].errstr;
+ errno = ev[error].err;
+ if (error)
+ ll = 0;
+
+ return (ll);
+}
+#endif /* HAVE_STRTONUM */
+
+#ifndef HAVE_FGETLN
+char *fgetln(FILE *fh, size_t *len) {
+ int c, size = 0;
+ char *buf = NULL;
+ int i = 0;
+
+ while ((c = getc(fh)) != EOF) {
+ if (i >= size)
+ buf = xrealloc(buf, size += 128);
+ buf[i++] = (char) c;
+ if (c == '\n')
+ break;
+ }
+ if (buf) {
+ buf = xrealloc(buf, i + 1);
+ buf[i] = '\0';
+ }
+ if (len)
+ *len = i;
+ return buf;
+}
+#endif /* HAVE_FGETLN */
diff --git a/src/lib.h b/src/lib.h
new file mode 100644
index 0000000..fbf8f2b
--- /dev/null
+++ b/src/lib.h
@@ -0,0 +1,26 @@
+#ifndef RCS_LIB_H
+#define RCS_LIB_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <stdio.h>
+
+/* strlcpy and strlcat */
+#ifndef HAVE_STRLCPY
+size_t strlcpy(char *, const char *, size_t);
+#endif
+
+#ifndef HAVE_STRLCPY
+size_t strlcat(char *, const char *, size_t);
+#endif
+
+#ifndef HAVE_STRTONUM
+long long strtonum(const char *, long long, long long, const char **);
+#endif
+
+#ifndef HAVE_FGETLN
+char *fgetln(FILE *, size_t *);
+#endif
+
+#endif /* RCS_LIB_H */
diff --git a/src/sendbug.c b/src/sendbug.c
new file mode 100644
index 0000000..e9e754d
--- /dev/null
+++ b/src/sendbug.c
@@ -0,0 +1,574 @@
+/* $OpenBSD: sendbug.c,v 1.49 2007/05/11 02:07:47 ray Exp $ */
+
+/*
+ * Written by Ray Lai <ray@cyth.net>.
+ * Public domain.
+ */
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/utsname.h>
+#include <sys/wait.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <paths.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "atomicio.h"
+#include "lib.h"
+
+#define _PATH_DMESG "/var/run/dmesg.boot"
+
+int checkfile(const char *);
+void dmesg(FILE *);
+int editit(const char *);
+void init(void);
+int matchline(const char *, const char *, size_t);
+int prompt(void);
+int send_file(const char *, int);
+int sendmail(const char *);
+void template(FILE *);
+
+const char *categories = "acf aports base doc misc hosting";
+char *version = "4.2";
+
+struct passwd *pw;
+//char os[BUFSIZ], rel[BUFSIZ],
+char release[BUFSIZ];
+//char details[BUFSIZ];
+struct utsname uts;
+char *fullname, *tmppath;
+int Dflag, wantcleanup;
+
+static void
+usage(void)
+{
+ extern char *__progname;
+
+ fprintf(stderr, "usage: %s [-DLPV]\n", __progname);
+ exit(1);
+}
+
+void
+cleanup()
+{
+ if (wantcleanup && tmppath && unlink(tmppath) == -1)
+ warn("unlink");
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ int ch, c, fd, ret = 1;
+ const char *tmpdir;
+ struct stat sb;
+ char *pr_form;
+ time_t mtime;
+ FILE *fp;
+
+ while ((ch = getopt(argc, argv, "DLPV")) != -1)
+ switch (ch) {
+ case 'D':
+ Dflag = 1;
+ break;
+ case 'L':
+ printf("Known categories:\n");
+ printf("%s\n\n", categories);
+ exit(0);
+ case 'P':
+ init();
+ template(stdout);
+ exit(0);
+ case 'V':
+ printf("%s\n", version);
+ exit(0);
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 0)
+ usage();
+
+ if ((tmpdir = getenv("TMPDIR")) == NULL || tmpdir[0] == '\0')
+ tmpdir = _PATH_TMP;
+ if (asprintf(&tmppath, "%s%sp.XXXXXXXXXX", tmpdir,
+ tmpdir[strlen(tmpdir) - 1] == '/' ? "" : "/") == -1)
+ err(1, "asprintf");
+ if ((fd = mkstemp(tmppath)) == -1)
+ err(1, "mkstemp");
+ wantcleanup = 1;
+ atexit(cleanup);
+ if ((fp = fdopen(fd, "w+")) == NULL)
+ err(1, "fdopen");
+
+ init();
+
+ pr_form = getenv("PR_FORM");
+ if (pr_form) {
+ char buf[BUFSIZ];
+ size_t len;
+ FILE *frfp;
+
+ frfp = fopen(pr_form, "r");
+ if (frfp == NULL) {
+ warn("can't seem to read your template file "
+ "(`%s'), ignoring PR_FORM", pr_form);
+ template(fp);
+ } else {
+ while (!feof(frfp)) {
+ len = fread(buf, 1, sizeof buf, frfp);
+ if (len == 0)
+ break;
+ if (fwrite(buf, 1, len, fp) != len)
+ break;
+ }
+ fclose(frfp);
+ }
+ } else
+ template(fp);
+
+ if (fflush(fp) == EOF || fstat(fd, &sb) == -1 || fclose(fp) == EOF)
+ err(1, "error creating template");
+ mtime = sb.st_mtime;
+
+ edit:
+ if (editit(tmppath) == -1)
+ err(1, "error running editor");
+
+ if (stat(tmppath, &sb) == -1)
+ err(1, "stat");
+ if (mtime == sb.st_mtime)
+ errx(1, "report unchanged, nothing sent");
+
+ prompt:
+ if (!checkfile(tmppath))
+ fprintf(stderr, "fields are blank, must be filled in\n");
+ c = prompt();
+ switch (c) {
+ case 'a':
+ case EOF:
+ wantcleanup = 0;
+ errx(1, "unsent report in %s", tmppath);
+ case 'e':
+ goto edit;
+ case 's':
+ if (sendmail(tmppath) == -1)
+ goto quit;
+ break;
+ default:
+ goto prompt;
+ }
+
+ ret = 0;
+quit:
+ return (ret);
+}
+
+void
+dmesg(FILE *fp)
+{
+ char buf[BUFSIZ];
+ FILE *dfp;
+ off_t offset = -1;
+
+ dfp = fopen(_PATH_DMESG, "r");
+ if (dfp == NULL) {
+ warn("can't read dmesg");
+ return;
+ }
+
+ fputs("\n"
+ "<dmesg is attached.>\n"
+ "<Feel free to delete or use the -D flag if it contains "
+ "sensitive information.>\n", fp);
+ if (offset != -1) {
+ size_t len;
+
+ clearerr(dfp);
+ fseeko(dfp, offset, SEEK_SET);
+ while (offset != -1 && !feof(dfp)) {
+ len = fread(buf, 1, sizeof buf, dfp);
+ if (len == 0)
+ break;
+ if (fwrite(buf, 1, len, fp) != len)
+ break;
+ }
+ }
+ fclose(dfp);
+}
+
+/*
+ * Execute an editor on the specified pathname, which is interpreted
+ * from the shell. This means flags may be included.
+ *
+ * Returns -1 on error, or the exit value on success.
+ */
+int
+editit(const char *pathname)
+{
+ char *argp[] = {"sh", "-c", NULL, NULL}, *ed, *p;
+ sig_t sighup, sigint, sigquit;
+ pid_t pid;
+ int saved_errno, st;
+
+ ed = getenv("VISUAL");
+ if (ed == NULL || ed[0] == '\0')
+ ed = getenv("EDITOR");
+ if (ed == NULL || ed[0] == '\0')
+ ed = _PATH_VI;
+ if (asprintf(&p, "%s %s", ed, pathname) == -1)
+ return (-1);
+ argp[2] = p;
+
+ sighup = signal(SIGHUP, SIG_IGN);
+ sigint = signal(SIGINT, SIG_IGN);
+ sigquit = signal(SIGQUIT, SIG_IGN);
+ if ((pid = fork()) == -1)
+ goto fail;
+ if (pid == 0) {
+ execv(_PATH_BSHELL, argp);
+ _exit(127);
+ }
+ while (waitpid(pid, &st, 0) == -1)
+ if (errno != EINTR)
+ goto fail;
+ free(p);
+ (void)signal(SIGHUP, sighup);
+ (void)signal(SIGINT, sigint);
+ (void)signal(SIGQUIT, sigquit);
+ if (!WIFEXITED(st)) {
+ errno = EINTR;
+ return (-1);
+ }
+ return (WEXITSTATUS(st));
+
+ fail:
+ saved_errno = errno;
+ (void)signal(SIGHUP, sighup);
+ (void)signal(SIGINT, sigint);
+ (void)signal(SIGQUIT, sigquit);
+ free(p);
+ errno = saved_errno;
+ return (-1);
+}
+
+int
+prompt(void)
+{
+ int c, ret;
+
+// fpurge(stdin);
+ fprintf(stderr, "a)bort, e)dit, or s)end: ");
+ fflush(stderr);
+ ret = getchar();
+ if (ret == EOF || ret == '\n')
+ return (ret);
+ do {
+ c = getchar();
+ } while (c != EOF && c != '\n');
+ return (ret);
+}
+
+int
+sendmail(const char *pathname)
+{
+ int filedes[2];
+
+ if (pipe(filedes) == -1) {
+ warn("pipe: unsent report in %s", pathname);
+ return (-1);
+ }
+ switch (fork()) {
+ case -1:
+ warn("fork error: unsent report in %s",
+ pathname);
+ return (-1);
+ case 0:
+ close(filedes[1]);
+ if (dup2(filedes[0], STDIN_FILENO) == -1) {
+ warn("dup2 error: unsent report in %s",
+ pathname);
+ return (-1);
+ }
+ close(filedes[0]);
+ execl("/usr/sbin/sendmail", "sendmail",
+ "-oi", "-t", (void *)NULL);
+ warn("sendmail error: unsent report in %s",
+ pathname);
+ return (-1);
+ default:
+ close(filedes[0]);
+ /* Pipe into sendmail. */
+ if (send_file(pathname, filedes[1]) == -1) {
+ warn("send_file error: unsent report in %s",
+ pathname);
+ return (-1);
+ }
+ close(filedes[1]);
+ wait(NULL);
+ break;
+ }
+ return (0);
+}
+
+static void readfile(const char *filename, char *buf, size_t size)
+{
+ int count;
+ int fd = open(filename, O_RDONLY);
+ buf[0] = '\0';
+ if (fd < 0)
+ return;
+ count = read(fd, buf, size-1);
+ if (count < 0)
+ return;
+ buf[count] = '\0';
+ close(fd);
+ return;
+}
+
+void
+init(void)
+{
+ size_t amp, len, gecoslen, namelen;
+ int sysname[2];
+ char ch, *cp;
+
+ if ((pw = getpwuid(getuid())) == NULL)
+ err(1, "getpwuid");
+ namelen = strlen(pw->pw_name);
+
+ /* Count number of '&'. */
+ for (amp = 0, cp = pw->pw_gecos; *cp && *cp != ','; ++cp)
+ if (*cp == '&')
+ ++amp;
+
+ /* Truncate gecos to full name. */
+ gecoslen = cp - pw->pw_gecos;
+ pw->pw_gecos[gecoslen] = '\0';
+
+ /* Expanded str = orig str - '&' chars + concatenated logins. */
+ len = gecoslen - amp + (amp * namelen) + 1;
+ if ((fullname = malloc(len)) == NULL)
+ err(1, "malloc");
+
+ /* Upper case first char of login. */
+ ch = pw->pw_name[0];
+ pw->pw_name[0] = toupper((unsigned char)pw->pw_name[0]);
+
+ cp = pw->pw_gecos;
+ fullname[0] = '\0';
+ while (cp != NULL) {
+ char *token;
+
+ token = strsep(&cp, "&");
+ if (token != pw->pw_gecos &&
+ strlcat(fullname, pw->pw_name, len) >= len)
+ errx(1, "truncated string");
+ if (strlcat(fullname, token, len) >= len)
+ errx(1, "truncated string");
+ }
+ /* Restore case of first char of login. */
+ pw->pw_name[0] = ch;
+
+ uname(&uts);
+
+/*
+ readfile("/proc/sys/kernel/ostype", os, sizeof(os)-1);
+ readfile("/proc/sys/kernel/osrelease", rel, sizeof(rel)-1);
+ readfile("/proc/sys/kernel/version", details, sizeof(details)-1);
+ cp = strchr(details, '\n');
+ if (cp) {
+ cp++;
+ if (*cp)
+ *cp++ = '\t';
+ if (*cp)
+ *cp++ = '\t';
+ if (*cp)
+ *cp++ = '\t';
+ }
+*/
+
+ readfile("/etc/alpine-release", release, sizeof(release)-1);
+}
+
+int
+send_file(const char *file, int dst)
+{
+ int blank = 0;
+ size_t len;
+ char *buf;
+ FILE *fp;
+
+ if ((fp = fopen(file, "r")) == NULL)
+ return (-1);
+ while ((buf = fgetln(fp, &len))) {
+ /* Skip lines starting with "SENDBUG". */
+ if (len >= sizeof("SENDBUG") - 1 &&
+ memcmp(buf, "SENDBUG", sizeof("SENDBUG") - 1) == 0)
+ continue;
+ if (len == 1 && buf[0] == '\n')
+ blank = 1;
+ /* Skip comments, but only if we encountered a blank line. */
+ while (len) {
+ char *sp = NULL, *ep = NULL;
+ size_t copylen;
+
+ if (blank && (sp = memchr(buf, '<', len)) != NULL)
+ ep = memchr(sp, '>', len - (sp - buf + 1));
+ /* Length of string before comment. */
+ if (ep)
+ copylen = sp - buf;
+ else
+ copylen = len;
+ if (atomicio(vwrite, dst, buf, copylen) != copylen) {
+ int saved_errno = errno;
+
+ fclose(fp);
+ errno = saved_errno;
+ return (-1);
+ }
+ if (!ep)
+ break;
+ /* Skip comment. */
+ len -= ep - buf + 1;
+ buf = ep + 1;
+ }
+ }
+ fclose(fp);
+ return (0);
+}
+
+/*
+ * Does line start with `s' and end with non-comment and non-whitespace?
+ * Note: Does not treat `line' as a C string.
+ */
+int
+matchline(const char *s, const char *line, size_t linelen)
+{
+ size_t slen;
+ int comment;
+
+ slen = strlen(s);
+ /* Is line shorter than string? */
+ if (linelen <= slen)
+ return (0);
+ /* Does line start with string? */
+ if (memcmp(line, s, slen) != 0)
+ return (0);
+ /* Does line contain anything but comments and whitespace? */
+ line += slen;
+ linelen -= slen;
+ comment = 0;
+ while (linelen) {
+ if (comment) {
+ if (*line == '>')
+ comment = 0;
+ } else if (*line == '<')
+ comment = 1;
+ else if (!isspace((unsigned char)*line))
+ return (1);
+ ++line;
+ --linelen;
+ }
+ return (0);
+}
+
+/*
+ * Are all required fields filled out?
+ */
+int
+checkfile(const char *pathname)
+{
+ FILE *fp;
+ size_t len;
+ int category, class, priority, release, severity, synopsis;
+ char *buf;
+
+ if ((fp = fopen(pathname, "r")) == NULL) {
+ warn("%s", pathname);
+ return (0);
+ }
+ category = class = priority = release = severity = synopsis = 0;
+ while ((buf = fgetln(fp, &len))) {
+ if (matchline(">Category:", buf, len))
+ category = 1;
+ else if (matchline(">Class:", buf, len))
+ class = 1;
+ else if (matchline(">Priority:", buf, len))
+ priority = 1;
+ else if (matchline(">Release:", buf, len))
+ release = 1;
+ else if (matchline(">Severity:", buf, len))
+ severity = 1;
+ else if (matchline(">Synopsis:", buf, len))
+ synopsis = 1;
+ }
+ fclose(fp);
+ return (category && class && priority && release && severity &&
+ synopsis);
+}
+
+void
+template(FILE *fp)
+{
+ char *sender = getenv("SENDBUG_FROM");
+ if (sender == NULL)
+ sender = pw->pw_name;
+
+ fprintf(fp, "SENDBUG: -*- sendbug -*-\n");
+ fprintf(fp, "SENDBUG: Lines starting with `SENDBUG' will"
+ " be removed automatically, as\n");
+ fprintf(fp, "SENDBUG: will all comments (text enclosed in `<' and `>').\n");
+ fprintf(fp, "SENDBUG:\n");
+ fprintf(fp, "To: %s\n", "bugs@alpinelinux.org");
+ fprintf(fp, "Subject: \n");
+ fprintf(fp, "From: %s\n", sender);
+ fprintf(fp, "Cc: %s\n", sender);
+ fprintf(fp, "Reply-To: %s\n", sender);
+ fprintf(fp, "X-sendbug-version: %s\n", version);
+ fprintf(fp, "\n");
+ fprintf(fp, "\n");
+ fprintf(fp, ">Submitter-Id:\tcurrent-users\n");
+ fprintf(fp, ">Originator:\t%s\n", fullname);
+ fprintf(fp, ">Organization:\n");
+ fprintf(fp, ">Synopsis:\t<synopsis of the problem (one line)>\n");
+ fprintf(fp, ">Severity:\t"
+ "<[ non-critical | serious | critical ] (one line)>\n");
+ fprintf(fp, ">Priority:\t<[ low | medium | high ] (one line)>\n");
+ fprintf(fp, ">Category:\t"
+ "<[ acf | aports | base | doc | misc | hosting ] (one line)>\n");
+ fprintf(fp, ">Class:\t\t"
+ "<[ sw-bug | doc-bug | change-request | support ] (one line)>\n");
+ fprintf(fp, ">Release:\t%s\n",release);
+ fprintf(fp, ">Environment:\n");
+ fprintf(fp, "\t<machine, os, target, libraries (multiple lines)>\n");
+ fprintf(fp, "\tSystem : %s %s\n", uts.sysname);
+ fprintf(fp, "\tVersion : %s\n", uts.version);
+ fprintf(fp, "\tMachine : %s\n", uts.machine);
+ fprintf(fp, "\tRelease : %s\n", uts.release);
+ fprintf(fp, ">Description:\n");
+ fprintf(fp, "\t<precise description of the problem (multiple lines)>\n");
+ fprintf(fp, ">How-To-Repeat:\n");
+ fprintf(fp, "\t<code/input/activities to reproduce the problem"
+ " (multiple lines)>\n");
+ fprintf(fp, ">Fix:\n");
+ fprintf(fp, "\t<how to correct or work around the problem,"
+ " if known (multiple lines)>\n");
+
+ if (!Dflag)
+ dmesg(fp);
+}