diff options
-rw-r--r-- | usr.bin/sendbug/Makefile | 7 | ||||
-rw-r--r-- | usr.bin/sendbug/atomicio.c | 62 | ||||
-rw-r--r-- | usr.bin/sendbug/atomicio.h | 39 | ||||
-rw-r--r-- | usr.bin/sendbug/sendbug.1 | 47 | ||||
-rw-r--r-- | usr.bin/sendbug/sendbug.c | 315 |
5 files changed, 470 insertions, 0 deletions
diff --git a/usr.bin/sendbug/Makefile b/usr.bin/sendbug/Makefile new file mode 100644 index 00000000000..bfa4e82f116 --- /dev/null +++ b/usr.bin/sendbug/Makefile @@ -0,0 +1,7 @@ +# $OpenBSD: Makefile,v 1.1 2007/03/23 01:47:11 ray Exp $ + +PROG=sendbug +SRCS=atomicio.c sendbug.c +COPTS+=-Wall -W + +.include <bsd.prog.mk> diff --git a/usr.bin/sendbug/atomicio.c b/usr.bin/sendbug/atomicio.c new file mode 100644 index 00000000000..8f2f2ee58c3 --- /dev/null +++ b/usr.bin/sendbug/atomicio.c @@ -0,0 +1,62 @@ +/* $OpenBSD: atomicio.c,v 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/usr.bin/sendbug/atomicio.h b/usr.bin/sendbug/atomicio.h new file mode 100644 index 00000000000..72595dba99f --- /dev/null +++ b/usr.bin/sendbug/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/usr.bin/sendbug/sendbug.1 b/usr.bin/sendbug/sendbug.1 new file mode 100644 index 00000000000..cea68d06f6c --- /dev/null +++ b/usr.bin/sendbug/sendbug.1 @@ -0,0 +1,47 @@ +.\" $OpenBSD: sendbug.1,v 1.1 2007/03/23 01:47:11 ray Exp $ +.\" +.\" Written by Raymond Lai <ray@cyth.net>. +.\" Public domain. +.\" +.Dd March 22, 2007 +.Dt SENDBUG 1 +.Os +.Sh NAME +.Nm sendbug +.Nd report a bug in +.Ox +.Sh SYNOPSIS +.Nm +.Sh DESCRIPTION +.Nm +is used to send bug reports to +.Ox . +Some system information is filled out in a temporary file, +which is then opened by an editor. +See +.Ev EDITOR +below, +for details of which editor, if any, is invoked. +.Pp +Once the bug report is filled out, +it is e-mailed to the +.Ox +developers. +.Sh ENVIRONMENT +.Bl -tag -width Ds +.It Ev EDITOR +Specifies an editor to use. +If +.Ev EDITOR +is not set, +the default is +.Xr vi 1 . +.It Ev TMPDIR +Specifies a directory for temporary files to be created. +The default is +.Pa /tmp . +.El +.Sh AUTHORS +.Nm +was written from scratch for the public domain by +.An Ray Lai Aq ray@cyth.net . diff --git a/usr.bin/sendbug/sendbug.c b/usr.bin/sendbug/sendbug.c new file mode 100644 index 00000000000..8a8e2850731 --- /dev/null +++ b/usr.bin/sendbug/sendbug.c @@ -0,0 +1,315 @@ +/* $OpenBSD: sendbug.c,v 1.1 2007/03/23 01:47:11 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/wait.h> + +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <paths.h> +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "atomicio.h" + +int init(void); +int prompt(void); +int send_file(const char *, int dst); +int sendmail(const char *); +void template(FILE *); + +struct passwd *pw; +const char *categories = "system user library documentation ports kernel " + "alpha amd64 arm i386 m68k m88k mips ppc sgi sparc sparc64 vax"; +char os[BUFSIZ], rel[BUFSIZ], mach[BUFSIZ]; +char *fullname; + +int +main(int argc, char *argv[]) +{ + struct stat sb; + FILE *fp; + const char *editor, *tmpdir; + char *tmppath = NULL; + time_t mtime; + int c, fd, ret = 1; + + if ((tmpdir = getenv("TMPDIR")) == NULL || tmpdir[0] == '\0') + tmpdir = _PATH_TMP; + if (asprintf(&tmppath, "%s/p.XXXXXXXXXX", tmpdir) == -1) { + warn("asprintf"); + goto quit; + } + if ((fd = mkstemp(tmppath)) == -1) + err(1, "mkstemp"); + if ((fp = fdopen(fd, "w+")) == NULL) { + warn("fdopen"); + goto cleanup; + } + + if (init() == -1) + goto cleanup; + + template(fp); + + if (fflush(fp) == EOF || fstat(fd, &sb) == -1 || fclose(fp) == EOF) { + warn("error creating template"); + goto cleanup; + } + mtime = sb.st_mtime; + + edit: + if ((editor = getenv("EDITOR")) == NULL) + editor = "vi"; + switch (fork()) { + case -1: + warn("fork"); + goto cleanup; + case 0: + execlp(editor, editor, tmppath, NULL); + err(1, "execlp"); + default: + wait(NULL); + break; + } + + if (stat(tmppath, &sb) == -1) { + warn("stat"); + goto cleanup; + } + if (mtime == sb.st_mtime) { + warnx("report unchanged, nothing sent"); + goto cleanup; + } + + prompt: + c = prompt(); + switch (c) { + case 'a': case EOF: + warnx("unsent report in %s", tmppath); + goto quit; + case 'e': + goto edit; + case 's': + if (sendmail(tmppath) == -1) + goto quit; + break; + default: + goto prompt; + } + + ret = 0; + + cleanup: + if (tmppath && unlink(tmppath) == -1) + warn("unlink"); + + quit: + return (ret); +} + +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 *tmppath) +{ + int filedes[2]; + + if (pipe(filedes) == -1) { + warn("pipe: unsent report in %s", tmppath); + return (-1); + } + switch (fork()) { + case -1: + warn("fork error: unsent report in %s", + tmppath); + return (-1); + case 0: + close(filedes[1]); + if (dup2(filedes[0], STDIN_FILENO) == -1) { + warn("dup2 error: unsent report in %s", + tmppath); + return (-1); + } + close(filedes[0]); + execl("/usr/sbin/sendmail", "sendmail", + "-oi", "-t", NULL); + warn("sendmail error: unsent report in %s", + tmppath); + return (-1); + default: + close(filedes[0]); + /* Pipe into sendmail. */ + if (send_file(tmppath, filedes[1]) == -1) { + warn("send_file error: unsent report in %s", + tmppath); + return (-1); + } + close(filedes[1]); + wait(NULL); + break; + } + return (0); +} + +int +init(void) +{ + size_t len; + int sysname[2]; + + if ((pw = getpwuid(getuid())) == NULL) { + warn("getpwuid"); + return (-1); + } + + /* Get full name. */ + len = strcspn(pw->pw_gecos, ","); + if ((fullname = malloc(len + 1)) == NULL) { + warn("malloc"); + return (-1); + } + memcpy(fullname, pw->pw_gecos, len); + fullname[len] = '\0'; + + sysname[0] = CTL_KERN; + sysname[1] = KERN_OSTYPE; + len = sizeof(os) - 1; + if (sysctl(sysname, 2, &os, &len, NULL, 0) == -1) { + warn("sysctl"); + return (-1); + } + + sysname[0] = CTL_KERN; + sysname[1] = KERN_OSRELEASE; + len = sizeof(rel) - 1; + if (sysctl(sysname, 2, &rel, &len, NULL, 0) == -1) { + warn("sysctl"); + return (-1); + } + + sysname[0] = CTL_HW; + sysname[1] = HW_MACHINE; + len = sizeof(mach) - 1; + if (sysctl(sysname, 2, &mach, &len, NULL, 0) == -1) { + warn("sysctl"); + return (-1); + } + + return (0); +} + +int +send_file(const char *file, int dst) +{ + FILE *fp; + char *buf; + size_t len; + int blank = 0; + + 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, *ep = NULL; + size_t copylen; + + if (blank && (sp = memchr(buf, '<', len)) != NULL) + ep = memchr(sp, '>', len - (sp - buf + 1)); + /* Length of string before comment. */ + copylen = ep ? sp - buf : 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); +} + +void +template(FILE *fp) +{ + 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, "SENDBUG: Choose from the following categories:\n"); + fprintf(fp, "SENDBUG:\n"); + fprintf(fp, "SENDBUG: %s\n", categories); + fprintf(fp, "SENDBUG:\n"); + fprintf(fp, "SENDBUG:\n"); + fprintf(fp, "To: %s\n", "gnats@openbsd.org"); + fprintf(fp, "Subject: \n"); + fprintf(fp, "From: %s\n", pw->pw_name); + fprintf(fp, "Cc: \n"); + fprintf(fp, "Reply-To: %s\n", pw->pw_name); + fprintf(fp, "X-sendbug-version: 4.2\n"); + fprintf(fp, "\n"); + fprintf(fp, "\n"); + fprintf(fp, ">Submitter-Id:\tnet\n"); + fprintf(fp, ">Originator:\t%s\n", fullname); + fprintf(fp, ">Organization:\n"); + fprintf(fp, "net\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<PR category (one line)>\n"); + fprintf(fp, ">Class:\t\t<[ sw-bug | doc-bug | change-request | support ] (one line)>\n"); + fprintf(fp, ">Release:\t<release number or tag (one line)>\n"); + fprintf(fp, ">Environment:\n"); + fprintf(fp, "\t<machine, os, target, libraries (multiple lines)>\n"); + fprintf(fp, "\tSystem : %s %s\n", os, rel); + fprintf(fp, "\tArchitecture: %s.%s\n", os, mach); + fprintf(fp, "\tMachine : %s\n", mach); + 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"); +} |