365 lines
6.9 KiB
C
365 lines
6.9 KiB
C
/*
|
|
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2015
|
|
* The President and Fellows of Harvard College.
|
|
*
|
|
* 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.
|
|
* 3. Neither the name of the University nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``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 UNIVERSITY OR CONTRIBUTORS 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/types.h>
|
|
#include <sys/stat.h>
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <err.h>
|
|
#include <assert.h>
|
|
|
|
#include "config.h"
|
|
#include "test.h"
|
|
|
|
#define RESULT_COLUMN 72
|
|
|
|
/* current screen column (0-based) */
|
|
static size_t horizpos;
|
|
|
|
/* saved screen column for subreports */
|
|
static size_t subpos;
|
|
|
|
/* pending output buffer */
|
|
static char outbuf[256];
|
|
static size_t outbufpos;
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
/*
|
|
* Print things.
|
|
*/
|
|
static
|
|
void
|
|
vsay(const char *fmt, va_list ap)
|
|
{
|
|
size_t begin, i;
|
|
|
|
assert(outbufpos < sizeof(outbuf));
|
|
|
|
begin = outbufpos;
|
|
vsnprintf(outbuf + outbufpos, sizeof(outbuf) - outbufpos, fmt, ap);
|
|
outbufpos = strlen(outbuf);
|
|
|
|
for (i=begin; i<outbufpos; i++) {
|
|
if (outbuf[i] == '\n') {
|
|
horizpos = 0;
|
|
}
|
|
else {
|
|
horizpos++;
|
|
}
|
|
}
|
|
}
|
|
|
|
static
|
|
void
|
|
say(const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
vsay(fmt, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
/*
|
|
* Indent to a given horizontal position.
|
|
*/
|
|
static
|
|
void
|
|
indent_to(size_t pos)
|
|
{
|
|
while (horizpos < pos) {
|
|
assert(outbufpos < sizeof(outbuf) - 1);
|
|
outbuf[outbufpos++] = ' ';
|
|
outbuf[outbufpos] = 0;
|
|
horizpos++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Flush the output.
|
|
*/
|
|
static
|
|
void
|
|
flush(void)
|
|
{
|
|
write(STDOUT_FILENO, outbuf, outbufpos);
|
|
outbufpos = 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
/*
|
|
* Begin a test. This flushes the description so it can be seen before
|
|
* the test happens, in case the test explodes or deadlocks the system.
|
|
*/
|
|
void
|
|
report_begin(const char *descfmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
say("badcall: ");
|
|
va_start(ap, descfmt);
|
|
vsay(descfmt, ap);
|
|
va_end(ap);
|
|
say("... ");
|
|
flush();
|
|
}
|
|
|
|
/*
|
|
* Prepare to be able to print subreports.
|
|
*/
|
|
void
|
|
report_hassubs(void)
|
|
{
|
|
subpos = horizpos;
|
|
say("\n");
|
|
flush();
|
|
}
|
|
|
|
/*
|
|
* Begin a subreport. This does *not* flush because sometimes the
|
|
* subreports are in subprocesses and we want each one to print a
|
|
* whole line at once to avoid output interleaving.
|
|
*/
|
|
void
|
|
report_beginsub(const char *descfmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
assert(horizpos == 0);
|
|
say(" ");
|
|
va_start(ap, descfmt);
|
|
vsay(descfmt, ap);
|
|
va_end(ap);
|
|
indent_to(subpos);
|
|
}
|
|
|
|
/*
|
|
* Print a warning message (when within a test). This generates an
|
|
* extra line for the warning. The warnx form is the same but doesn't
|
|
* add errno.
|
|
*/
|
|
void
|
|
report_warn(const char *fmt, ...)
|
|
{
|
|
size_t pos;
|
|
const char *errmsg;
|
|
va_list ap;
|
|
|
|
pos = horizpos;
|
|
errmsg = strerror(errno);
|
|
say("\n OOPS: ");
|
|
va_start(ap, fmt);
|
|
vsay(fmt, ap);
|
|
va_end(ap);
|
|
say(": %s\n", errmsg);
|
|
indent_to(pos);
|
|
flush();
|
|
}
|
|
|
|
void
|
|
report_warnx(const char *fmt, ...)
|
|
{
|
|
size_t pos;
|
|
va_list ap;
|
|
|
|
pos = horizpos;
|
|
say("\n oops: ");
|
|
va_start(ap, fmt);
|
|
vsay(fmt, ap);
|
|
va_end(ap);
|
|
say("\n");
|
|
indent_to(pos);
|
|
flush();
|
|
}
|
|
|
|
/*
|
|
* Report a system call result.
|
|
*/
|
|
void
|
|
report_result(int rv, int error)
|
|
{
|
|
if (rv == -1) {
|
|
say("%s ", strerror(error));
|
|
}
|
|
else {
|
|
say("Success ");
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Deal with ENOSYS. The kernel prints "Unknown syscall NN\n" if you
|
|
* call a system call that the system call dispatcher doesn't know
|
|
* about. This is not the only way to get ENOSYS, but it's the most
|
|
* common. So, if we see ENOSYS assume that the kernel's injected a
|
|
* newline.
|
|
*
|
|
* XXX this is pretty gross.
|
|
*/
|
|
void
|
|
report_saw_enosys(void)
|
|
{
|
|
size_t pos = horizpos;
|
|
|
|
horizpos = 0;
|
|
indent_to(pos);
|
|
}
|
|
|
|
/*
|
|
* End a test. These print "passed", "FAILURE", "------", or "ABORTED"
|
|
* in the result column, and add the final newline.
|
|
*/
|
|
|
|
static
|
|
void
|
|
report_end(const char *msg)
|
|
{
|
|
indent_to(RESULT_COLUMN);
|
|
say("%s\n", msg);
|
|
flush();
|
|
}
|
|
|
|
void
|
|
report_passed(int *status)
|
|
{
|
|
report_end("passed");
|
|
*status = SUCCESS;
|
|
}
|
|
|
|
void
|
|
report_failure(int *status)
|
|
{
|
|
report_end("FAILURE");
|
|
*status = FAILED;
|
|
}
|
|
|
|
void
|
|
report_skipped(int *status)
|
|
{
|
|
report_end("------");
|
|
*status = SKIPPED;
|
|
}
|
|
|
|
void
|
|
report_aborted(int *status)
|
|
{
|
|
report_end("ABORTED");
|
|
*status = ABORTED;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
/*
|
|
* Combination functions that call report_result and also
|
|
* end the test, judging success based on whether the result
|
|
* matches one or more expected results.
|
|
*/
|
|
|
|
void
|
|
report_survival(int rv, int error, int *result)
|
|
{
|
|
/* allow any error as long as we survive */
|
|
report_result(rv, error);
|
|
report_passed(result);
|
|
}
|
|
|
|
static
|
|
int
|
|
report_checkN(int rv, int error, int *right_errors, int right_num)
|
|
{
|
|
int i, goterror;
|
|
int result = 1;
|
|
|
|
if (rv==-1) {
|
|
goterror = error;
|
|
}
|
|
else {
|
|
goterror = 0;
|
|
}
|
|
|
|
for (i=0; i<right_num; i++) {
|
|
if (goterror == right_errors[i]) {
|
|
report_result(rv, error);
|
|
report_passed(&result);
|
|
return result;
|
|
}
|
|
}
|
|
|
|
if (goterror == ENOSYS) {
|
|
report_saw_enosys();
|
|
say("(unimplemented) ");
|
|
report_skipped(&result);
|
|
}
|
|
else {
|
|
report_result(rv, error);
|
|
report_failure(&result);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int
|
|
report_check(int rv, int error, int right_error)
|
|
{
|
|
return report_checkN(rv, error, &right_error, 1);
|
|
}
|
|
|
|
int
|
|
report_check2(int rv, int error, int okerr1, int okerr2)
|
|
{
|
|
int ok[2];
|
|
|
|
ok[0] = okerr1;
|
|
ok[1] = okerr2;
|
|
return report_checkN(rv, error, ok, 2);
|
|
}
|
|
|
|
int
|
|
report_check3(int rv, int error, int okerr1, int okerr2, int okerr3)
|
|
{
|
|
int ok[3];
|
|
|
|
ok[0] = okerr1;
|
|
ok[1] = okerr2;
|
|
ok[2] = okerr3;
|
|
return report_checkN(rv, error, ok, 3);
|
|
}
|
|
|
|
void
|
|
handle_result(int result, int *lost_points)
|
|
{
|
|
if(result)
|
|
*lost_points = *lost_points + 1;
|
|
}
|
|
|