Move program control to thread structure

This commit is contained in:
Sebastian Huber 2013-10-17 10:38:34 +02:00
parent c333babc98
commit d01564c473
14 changed files with 558 additions and 115 deletions

View File

@ -70,6 +70,7 @@ LIB_C_FILES += rtemsbsd/rtems/rtems-bsd-page.c
LIB_C_FILES += rtemsbsd/rtems/rtems-bsd-panic.c
LIB_C_FILES += rtemsbsd/rtems/rtems-bsd-pci_bus.c
LIB_C_FILES += rtemsbsd/rtems/rtems-bsd-pci_cfgreg.c
LIB_C_FILES += rtemsbsd/rtems/rtems-bsd-program.c
LIB_C_FILES += rtemsbsd/rtems/rtems-bsd-rwlock.c
LIB_C_FILES += rtemsbsd/rtems/rtems-bsd-shell.c
LIB_C_FILES += rtemsbsd/rtems/rtems-bsd-signal.c
@ -86,10 +87,8 @@ LIB_C_FILES += rtemsbsd/rtems/rtems-bsd-taskqueue.c
LIB_C_FILES += rtemsbsd/rtems/rtems-bsd-thread.c
LIB_C_FILES += rtemsbsd/rtems/rtems-bsd-timesupport.c
LIB_C_FILES += rtemsbsd/rtems/rtems-bsd-vm_glue.c
LIB_C_FILES += rtemsbsd/rtems/rtems-getprogname.c
LIB_C_FILES += rtemsbsd/rtems/rtems-kvm.c
LIB_C_FILES += rtemsbsd/rtems/rtems-net-setup.c
LIB_C_FILES += rtemsbsd/rtems/rtems-shell.c
LIB_C_FILES += rtemsbsd/rtems/rtems-syslog-initialize.c
LIB_C_FILES += rtemsbsd/rtems/rtems-syspoll.c
LIB_C_FILES += rtemsbsd/rtems/rtems-uthread_kevent.c

View File

@ -627,6 +627,7 @@ rtems.addRTEMSSourceFiles(
'rtems/rtems-bsd-panic.c',
'rtems/rtems-bsd-pci_bus.c',
'rtems/rtems-bsd-pci_cfgreg.c',
'rtems/rtems-bsd-program.c',
'rtems/rtems-bsd-rwlock.c',
'rtems/rtems-bsd-shell.c',
'rtems/rtems-bsd-signal.c',
@ -643,10 +644,8 @@ rtems.addRTEMSSourceFiles(
'rtems/rtems-bsd-thread.c',
'rtems/rtems-bsd-timesupport.c',
'rtems/rtems-bsd-vm_glue.c',
'rtems/rtems-getprogname.c',
'rtems/rtems-kvm.c',
'rtems/rtems-net-setup.c',
'rtems/rtems-shell.c',
'rtems/rtems-syslog-initialize.c',
'rtems/rtems-syspoll.c',
'rtems/rtems-uthread_kevent.c',

View File

@ -47,19 +47,6 @@
#include <sys/cdefs.h>
#include <rtems/bsd/sys/_types.h>
#ifdef __rtems__
#include <setjmp.h>
typedef struct rtems_shell_globals_s {
jmp_buf exit_jmp;
int exit_code;
} rtems_shell_globals_t;
extern rtems_shell_globals_t *rtems_shell_globals;
void rtems_shell_exit (int code);
#define exit rtems_shell_exit
#endif
__BEGIN_DECLS
void err(int, const char *, ...) __dead2 __printf0like(2, 3);
void verr(int, const char *, __va_list) __dead2 __printf0like(2, 0);
@ -74,8 +61,10 @@ void warnc(int, const char *, ...) __printf0like(2, 3);
void vwarnc(int, const char *, __va_list) __printf0like(2, 0);
void warnx(const char *, ...) __printflike(1, 2);
void vwarnx(const char *, __va_list) __printflike(1, 0);
#ifndef __rtems__
void err_set_file(void *);
void err_set_exit(void (*)(int));
#endif /* __rtems__ */
__END_DECLS
#endif /* !_ERR_H_ */

View File

@ -46,9 +46,16 @@ __FBSDID("$FreeBSD$");
#include "libc_private.h"
#ifndef __rtems__
static FILE *err_file; /* file to use for error output */
static void (*err_exit)(int);
#else /* __rtems__ */
#include <machine/rtems-bsd-program.h>
#define err_file stderr
#define err_set_file(x) do { } while (0)
#endif /* __rtems__ */
#ifndef __rtems__
/*
* This is declared to take a `void *' so that the caller is not required
* to include <stdio.h> first. However, it is really a `FILE *', and the
@ -68,6 +75,7 @@ err_set_exit(void (*ef)(int))
{
err_exit = ef;
}
#endif /* __rtems__ */
__weak_reference(_err, err);
@ -109,8 +117,10 @@ verrc(int eval, int code, const char *fmt, va_list ap)
fprintf(err_file, ": ");
}
fprintf(err_file, "%s\n", strerror(code));
#ifndef __rtems__
if (err_exit)
err_exit(eval);
#endif /* __rtems__ */
exit(eval);
}
@ -132,8 +142,10 @@ verrx(int eval, const char *fmt, va_list ap)
if (fmt != NULL)
vfprintf(err_file, fmt, ap);
fprintf(err_file, "\n");
#ifndef __rtems__
if (err_exit)
err_exit(eval);
#endif /* __rtems__ */
exit(eval);
}

View File

@ -114,25 +114,6 @@ static struct afswtch *af_getbyname(const char *name);
static struct afswtch *af_getbyfamily(int af);
static void af_other_status(int);
#ifdef __rtems__
static int main_ifconfig(int argc, char *argv[]);
static int rtems_shell_main_ifconfig(int argc, char *argv[])
{
rtems_shell_globals_t ifconfig_globals;
rtems_shell_globals = &ifconfig_globals;
memset (rtems_shell_globals, 0, sizeof (ifconfig_globals));
descr = NULL;
descrlen = 64;
newaddr = 1;
supmedia = 0;
printkeys = 0;
ifconfig_globals.exit_code = 1;
if (setjmp (ifconfig_globals.exit_jmp) == 0)
return main_ifconfig ( argc, argv);
return ifconfig_globals.exit_code;
}
#endif
#ifdef __rtems__
static struct ifconfig_option *opts = NULL;
@ -182,12 +163,23 @@ usage(void)
}
#ifdef __rtems__
int
main_ifconfig(int argc, char *argv[])
#else
#include <machine/rtems-bsd-program.h>
static int main(int argc, char *argv[]);
static int rtems_shell_main_ifconfig(int argc, char *argv[])
{
descr = NULL;
descrlen = 64;
newaddr = 1;
supmedia = 0;
printkeys = 0;
return rtems_bsd_program_call_main("ifconfig", main, argc, argv);
}
#endif /* __rtems__ */
int
main(int argc, char *argv[])
#endif
{
int c, all, namesonly, downonly, uponly;
const struct afswtch *afp = NULL;

View File

@ -218,12 +218,12 @@ static void tvsub(struct timeval *, struct timeval *);
static void usage(void) __dead2;
#ifdef __rtems__
static int main_ping(int argc, char *const *argv);
#include <machine/rtems-bsd-program.h>
static int main(int argc, char **argv);
static int rtems_shell_main_ping(int argc, char *argv[])
{
rtems_shell_globals_t ping_globals;
rtems_shell_globals = &ping_globals;
memset (rtems_shell_globals, 0, sizeof (ping_globals));
BBELL = '\a';
BSPACE = '\b';
DOT = '.';
@ -239,23 +239,18 @@ static int rtems_shell_main_ping(int argc, char *argv[])
tmax = 0.0;
tsum = 0.0;
tsumsq = 0.0;
ping_globals.exit_code = 1;
if (setjmp (ping_globals.exit_jmp) == 0)
return main_ping (argc, argv);
return ping_globals.exit_code;
return rtems_bsd_program_call_main("ping", main, argc, argv);
}
#endif
#endif /* __rtems__ */
int
#ifdef __rtems__
main_ping(argc, argv)
#else
main(argc, argv)
#endif
int argc;
#ifndef __rtems__
char *const *argv;
#else /* __rtems__ */
char **argv;
#endif /* __rtems__ */
{
struct sockaddr_in from, sock_in;
struct in_addr ifaddr;

View File

@ -116,24 +116,6 @@ extern char *iso_ntoa();
void usage(const char *) __dead2;
#ifdef __rtems__
static int main_route(int argc, char **argv);
static int rtems_shell_main_route(int argc, char *argv[])
{
rtems_shell_globals_t route_globals;
rtems_shell_globals = &route_globals;
memset (rtems_shell_globals, 0, sizeof (route_globals));
route_globals.exit_code = 1;
if (setjmp (route_globals.exit_jmp) == 0)
return main_route ( argc, argv);
return route_globals.exit_code;
}
#endif
void
usage(cp)
const char *cp;
@ -147,11 +129,17 @@ usage(cp)
}
#ifdef __rtems__
#include <machine/rtems-bsd-program.h>
static int main(int argc, char **argv);
static int rtems_shell_main_route(int argc, char *argv[])
{
return rtems_bsd_program_call_main("route", main, argc, argv);
}
#endif /* __rtems__ */
int
main_route(argc, argv)
#else
main(argc, argv)
#endif
int argc;
char **argv;
{

View File

@ -201,6 +201,7 @@ struct thread {
#ifdef __rtems__
rtems_chain_node td_node;
Thread_Control *td_thread;
struct rtems_bsd_program_control *td_prog_ctrl;
char td_name [16];
#endif /* __rtems__ */
#ifndef __rtems__

View File

@ -153,8 +153,10 @@ struct ucred;
struct uio;
struct _jmp_buf;
#ifndef __rtems__
int setjmp(struct _jmp_buf *);
void longjmp(struct _jmp_buf *, int) __dead2;
#endif /* __rtems__ */
int dumpstatus(vm_offset_t addr, off_t count);
int nullop(void);
int eopnotsupp(void);

View File

@ -361,15 +361,14 @@ int unit; /* unit number for above */
int af; /* address family */
int live; /* true if we are examining a live system */
#ifdef __rtems__
static int main_netstat(int argc, char *argv[]);
#include <machine/rtems-bsd-program.h>
static int main(int argc, char *argv[]);
static int rtems_shell_main_netstat(int argc, char *argv[])
{
int i;
rtems_shell_globals_t netstat_globals;
rtems_shell_globals = &netstat_globals;
memset (rtems_shell_globals, 0, sizeof (netstat_globals));
i = 0;
protox[i].pr_index = N_TCBINFO;
@ -728,19 +727,11 @@ static int rtems_shell_main_netstat(int argc, char *argv[])
#endif
noutputs = 0;
netstat_globals.exit_code = 1;
if (setjmp (netstat_globals.exit_jmp) == 0)
return main_netstat (argc, argv);
return netstat_globals.exit_code;
return rtems_bsd_program_call_main("netstat", main, argc, argv);
}
#endif
#endif /* __rtems__ */
int
#ifdef __rtems__
main_netstat(int argc, char *argv[])
#else
main(int argc, char *argv[])
#endif
{
struct protox *tp = NULL; /* for printing cblocks & stats */
int ch;

View File

@ -0,0 +1,85 @@
/**
* @file
*
* @ingroup rtems_bsd_machine
*
* @brief TODO.
*/
/*
* Copyright (c) 2013 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Dornierstr. 4
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* 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 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 AUTHOR 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.
*/
#ifndef _RTEMS_BSD_MACHINE_RTEMS_BSD_PROGRAM_H_
#define _RTEMS_BSD_MACHINE_RTEMS_BSD_PROGRAM_H_
#include <sys/cdefs.h>
#include <stdbool.h>
#include <stdio.h>
__BEGIN_DECLS
int
rtems_bsd_program_call(const char *name, int (*prog)(void *), void *context);
int
rtems_bsd_program_call_main(const char *name, int (*main)(int, char **),
int argc, char **argv);
void
rtems_bsd_program_exit(int exit_code) __dead2;
const char *
rtems_bsd_program_get_name(void);
void *
rtems_bsd_program_get_context(void) __pure2;
void
rtems_bsd_program_lock(void);
void
rtems_bsd_program_unlock(void);
#ifndef RTEMS_BSD_PROGRAM_NO_EXIT_WRAP
#define exit(code) rtems_bsd_program_exit(code)
#endif
#ifndef RTEMS_BSD_PROGRAM_NO_GETPROGNAME_WRAP
#define getprogname() rtems_bsd_program_get_name()
#endif
#ifndef RTEMS_BSD_PROGRAM_NO_PRINTF_WRAP
#define printf(...) fprintf(stdout, __VA_ARGS__)
#endif
__END_DECLS
#endif /* _RTEMS_BSD_MACHINE_RTEMS_BSD_PROGRAM_H_ */

View File

@ -0,0 +1,202 @@
/**
* @file
*
* @ingroup rtems_bsd_rtems
*
* @brief TODO.
*/
/*
* Copyright (c) 2013 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Dornierstr. 4
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* 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 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 AUTHOR 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 <machine/rtems-bsd-config.h>
#include <machine/rtems-bsd-thread.h>
#include <rtems/bsd/sys/param.h>
#include <rtems/bsd/sys/types.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/malloc.h>
#include <rtems/bsd/sys/lock.h>
#include <sys/mutex.h>
#include <setjmp.h>
#include <stdlib.h>
struct rtems_bsd_program_control {
void *context;
int exit_code;
const char *name;
jmp_buf return_context;
};
int
rtems_bsd_program_call(const char *name, int (*prog)(void *), void *context)
{
struct thread *td = rtems_bsd_get_curthread_or_null();
int exit_code = EXIT_FAILURE;
if (td != NULL) {
struct rtems_bsd_program_control *prog_ctrl = td->td_prog_ctrl;
if (prog_ctrl == NULL) {
prog_ctrl = malloc(sizeof(*prog_ctrl), M_TEMP, 0);
if (prog_ctrl != NULL) {
td->td_prog_ctrl = prog_ctrl;
prog_ctrl->context = context;
prog_ctrl->name = name;
prog_ctrl->exit_code = exit_code;
if (setjmp(prog_ctrl->return_context) == 0) {
exit_code = (*prog)(context);
} else {
exit_code = prog_ctrl->exit_code;
}
td->td_prog_ctrl = NULL;
free(prog_ctrl, M_TEMP);
} else {
errno = ENOMEM;
}
} else {
panic("unexpected BSD program state");
}
} else {
errno = ENOMEM;
}
return exit_code;
}
void
rtems_bsd_program_exit(int exit_code)
{
struct thread *td = rtems_bsd_get_curthread_or_null();
if (td != NULL) {
struct rtems_bsd_program_control *prog_ctrl = td->td_prog_ctrl;
if (prog_ctrl != NULL) {
prog_ctrl->exit_code = exit_code;
longjmp(prog_ctrl->return_context, 1);
}
}
panic("unexpected BSD program exit");
}
const char *
rtems_bsd_program_get_name(void)
{
struct thread *td = rtems_bsd_get_curthread_or_null();
const char *name = "?";
if (td != NULL) {
struct rtems_bsd_program_control *prog_ctrl = td->td_prog_ctrl;
if (prog_ctrl != NULL) {
name = prog_ctrl->name;
}
}
return name;
}
void *
rtems_bsd_program_get_context(void)
{
struct thread *td = rtems_bsd_get_curthread_or_null();
void *context = NULL;
if (td != NULL) {
struct rtems_bsd_program_control *prog_ctrl = td->td_prog_ctrl;
if (prog_ctrl != NULL) {
context = prog_ctrl->context;
}
}
return context;
}
struct main_context {
int argc;
char **argv;
int (*main)(int, char **);
};
static int
call_main(void *ctx)
{
const struct main_context *mc = ctx;
return (*mc->main)(mc->argc, mc->argv);
}
int
rtems_bsd_program_call_main(const char *name, int (*main)(int, char **),
int argc, char **argv)
{
struct main_context mc = {
.argc = argc,
.argv = argv,
.main = main
};
int exit_code;
if (argv[argc] == NULL) {
exit_code = rtems_bsd_program_call(name, call_main, &mc);
} else {
errno = EFAULT;
exit_code = EXIT_FAILURE;
}
return exit_code;
}
static struct mtx program_mtx;
MTX_SYSINIT(rtems_bsd_program, &program_mtx, "BSD program", MTX_DEF);
void
rtems_bsd_program_lock(void)
{
mtx_lock(&program_mtx);
}
void
rtems_bsd_program_unlock(void)
{
mtx_unlock(&program_mtx);
}

View File

@ -1,8 +0,0 @@
/*
* RTEMS version of
*/
const char *getprogname(void)
{
return "RTEMS";
}

View File

@ -36,6 +36,7 @@
#include <sys/filio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <err.h>
#include <assert.h>
#include <errno.h>
@ -45,6 +46,10 @@
#include <string.h>
#include <unistd.h>
#define RTEMS_BSD_PROGRAM_NO_EXIT_WRAP
#define RTEMS_BSD_PROGRAM_NO_PRINTF_WRAP
#include <machine/rtems-bsd-program.h>
#include <rtems/libcsupport.h>
#define TEST_NAME "LIBBSD SYSCALLS 1"
@ -1201,6 +1206,193 @@ test_socket_recv_and_recvfrom_and_recvmsg(void)
assert(rtems_resource_snapshot_check(&snapshot));
}
static const char prog_name[] = "prog";
static int
invalid_prog(void *ctx)
{
(void) ctx;
assert(0);
}
static int
invalid_main(int argc, char **argv)
{
(void) argc;
(void) argv;
assert(0);
}
static void *const some_context = (void *) 0xcafe;
static int
some_prog(void *ctx)
{
assert(ctx == some_context);
assert(strcmp(rtems_bsd_program_get_name(), prog_name) == 0);
assert(rtems_bsd_program_get_context() == some_context);
errno = 0;
rtems_bsd_program_exit(456);
}
static const int some_argc = 1;
static char *some_argv[] = { "a", NULL };
static int
some_main(int argc, char **argv)
{
assert(argc == some_argc);
assert(argv == some_argv);
assert(strcmp(rtems_bsd_program_get_name(), prog_name) == 0);
errno = 0;
rtems_bsd_program_exit(789);
}
static void
no_mem_bsd_program(int fd)
{
(void) fd;
assert(rtems_bsd_program_call(prog_name, invalid_prog, NULL)
== EXIT_FAILURE);
assert(rtems_bsd_program_call_main(prog_name, invalid_main, some_argc,
some_argv) == EXIT_FAILURE);
assert(strcmp(rtems_bsd_program_get_name(), "?") == 0);
assert(rtems_bsd_program_get_context() == NULL);
}
static void
test_bsd_program(void)
{
rtems_resource_snapshot snapshot;
int exit_code;
void *greedy;
char *invalid_argv[2] = { "a", "b" };
assert(rtems_configuration_get_unified_work_area());
puts("test BSD program");
rtems_resource_snapshot_take(&snapshot);
do_no_mem_test(no_mem_bsd_program, -1);
greedy = rtems_workspace_greedy_allocate(NULL, 0);
no_mem_bsd_program(-1);
rtems_workspace_greedy_free(greedy);
errno = 0;
exit_code = rtems_bsd_program_call_main(prog_name, NULL, 1, invalid_argv);
assert(errno == EFAULT);
assert(exit_code == EXIT_FAILURE);
errno = EINVAL;
exit_code = rtems_bsd_program_call(prog_name, some_prog, some_context);
assert(errno == 0);
assert(exit_code == 456);
assert(strcmp(rtems_bsd_program_get_name(), "?") == 0);
assert(rtems_bsd_program_get_context() == NULL);
errno = EINVAL;
exit_code = rtems_bsd_program_call_main(prog_name, some_main,
some_argc, some_argv);
assert(errno == 0);
assert(exit_code == 789);
assert(strcmp(rtems_bsd_program_get_name(), "?") == 0);
assert(rtems_bsd_program_get_context() == NULL);
assert(rtems_resource_snapshot_check(&snapshot));
}
static void
test_warn(void)
{
puts("test warn");
errno = EAGAIN;
warn("%s", "warn");
errno = ENAMETOOLONG;
warn(NULL);
errno = 0;
warnc(EDOM, "%s", "warnc");
errno = 0;
warnc(ERANGE, NULL);
warnx("%s", "warnx");
warnx(NULL);
}
static int
call_err(void *ctx)
{
errno = EAGAIN;
err(10, "%s", "call_err");
}
static int
call_err_null(void *ctx)
{
errno = ENAMETOOLONG;
err(11, NULL);
}
static int
call_errc(void *ctx)
{
errc(12, EDOM, "%s", "call_errc");
}
static int
call_errc_null(void *ctx)
{
errc(13, ERANGE, NULL);
}
static int
call_errx(void *ctx)
{
errx(14, "%s", "call_errx");
}
static int
call_errx_null(void *ctx)
{
errx(15, NULL);
}
static void
test_err(void)
{
int exit_code;
puts("test err");
exit_code = rtems_bsd_program_call("err", call_err, NULL);
assert(exit_code == 10);
exit_code = rtems_bsd_program_call("err", call_err_null, NULL);
assert(exit_code == 11);
exit_code = rtems_bsd_program_call("errc", call_errc, NULL);
assert(exit_code == 12);
exit_code = rtems_bsd_program_call("errc", call_errc_null, NULL);
assert(exit_code == 13);
exit_code = rtems_bsd_program_call("errx", call_errx, NULL);
assert(exit_code == 14);
exit_code = rtems_bsd_program_call("errx", call_errx_null, NULL);
assert(exit_code == 15);
}
static void
test_main(void)
{
@ -1221,6 +1413,10 @@ test_main(void)
test_socket_send_and_sendto_and_sendmsg();
test_socket_recv_and_recvfrom_and_recvmsg();
test_bsd_program();
test_warn();
test_err();
puts("*** END OF " TEST_NAME " TEST ***");
exit(0);
}