Merge pull request #1843 from aquesnel/add_logging_session_c
Adding logs to sesman/session.c (#1843) Unit test framework check also added (https://libcheck.github.io/check/)
This commit is contained in:
commit
3a9d62b05c
@ -6,7 +6,7 @@ FreeBSD_task:
|
||||
freebsd_instance:
|
||||
image_family: freebsd-12-2
|
||||
prepare_script:
|
||||
- pkg install -y $SSL git autoconf automake libtool pkgconf opus jpeg-turbo fdk-aac pixman libX11 libXfixes libXrandr nasm fusefs-libs
|
||||
- pkg install -y $SSL git autoconf automake libtool pkgconf opus jpeg-turbo fdk-aac pixman libX11 libXfixes libXrandr nasm fusefs-libs check
|
||||
- git submodule update --init --recursive
|
||||
configure_script:
|
||||
- ./bootstrap
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -42,7 +42,9 @@ sesman/xrdp-sesman
|
||||
sesman/sesman.ini
|
||||
*.so
|
||||
stamp-h1
|
||||
tap-driver.sh
|
||||
test-driver
|
||||
tests/common/test_common
|
||||
tests/memtest/memtest
|
||||
tools/devel/tcp_proxy/tcp_proxy
|
||||
*.trs
|
||||
|
@ -32,7 +32,10 @@ if XRDP_DEBUG
|
||||
AM_CPPFLAGS += -DXRDP_DEBUG
|
||||
endif
|
||||
|
||||
AM_CFLAGS = $(OPENSSL_CFLAGS)
|
||||
# -no-suppress is an automake-specific flag which is needed
|
||||
# to prevent us missing compiler errors in some circumstances
|
||||
# (see https://github.com/neutrinolabs/xrdp/pull/1843 )
|
||||
AM_CFLAGS = -no-suppress $(OPENSSL_CFLAGS)
|
||||
|
||||
module_LTLIBRARIES = \
|
||||
libcommon.la
|
||||
|
@ -2591,16 +2591,41 @@ g_get_errno(void)
|
||||
|
||||
/*****************************************************************************/
|
||||
/* does not work in win32 */
|
||||
|
||||
#define ARGS_STR_LEN 1024
|
||||
|
||||
int
|
||||
g_execvp(const char *p1, char *args[])
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return 0;
|
||||
#else
|
||||
|
||||
int rv;
|
||||
char args_str[ARGS_STR_LEN];
|
||||
int args_len;
|
||||
|
||||
args_len = 0;
|
||||
while (args[args_len] != NULL)
|
||||
{
|
||||
args_len++;
|
||||
}
|
||||
|
||||
g_strnjoin(args_str, ARGS_STR_LEN, " ", (const char **) args, args_len);
|
||||
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"Calling exec (excutable: %s, arguments: %s)",
|
||||
p1, args_str);
|
||||
|
||||
g_rm_temp_dir();
|
||||
rv = execvp(p1, args);
|
||||
|
||||
/* should not get here */
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"Error calling exec (excutable: %s, arguments: %s) "
|
||||
"returned errno: %d, description: %s",
|
||||
p1, args_str, g_get_errno(), g_get_strerror());
|
||||
|
||||
g_mk_socket_path(0);
|
||||
return rv;
|
||||
#endif
|
||||
@ -2615,9 +2640,24 @@ g_execlp3(const char *a1, const char *a2, const char *a3)
|
||||
return 0;
|
||||
#else
|
||||
int rv;
|
||||
const char *args[] = {a2, a3, NULL};
|
||||
char args_str[ARGS_STR_LEN];
|
||||
|
||||
g_strnjoin(args_str, ARGS_STR_LEN, " ", args, 2);
|
||||
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"Calling exec (excutable: %s, arguments: %s)",
|
||||
a1, args_str);
|
||||
|
||||
g_rm_temp_dir();
|
||||
rv = execlp(a1, a2, a3, (void *)0);
|
||||
|
||||
/* should not get here */
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"Error calling exec (excutable: %s, arguments: %s) "
|
||||
"returned errno: %d, description: %s",
|
||||
a1, args_str, g_get_errno(), g_get_strerror());
|
||||
|
||||
g_mk_socket_path(0);
|
||||
return rv;
|
||||
#endif
|
||||
@ -2716,6 +2756,12 @@ g_fork(void)
|
||||
{
|
||||
g_mk_socket_path(0);
|
||||
}
|
||||
else if (rv == -1) /* error */
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"Process fork failed with errno: %d, description: %s",
|
||||
g_get_errno(), g_get_strerror());
|
||||
}
|
||||
|
||||
return rv;
|
||||
#endif
|
||||
@ -2876,6 +2922,51 @@ g_waitpid(int pid)
|
||||
#endif
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* does not work in win32
|
||||
returns exit status code of child process with pid */
|
||||
struct exit_status
|
||||
g_waitpid_status(int pid)
|
||||
{
|
||||
struct exit_status exit_status;
|
||||
|
||||
#if defined(_WIN32)
|
||||
exit_status.exit_code = -1;
|
||||
exit_status.signal_no = 0;
|
||||
return exit_status;
|
||||
#else
|
||||
int rv;
|
||||
int status;
|
||||
|
||||
exit_status.exit_code = -1;
|
||||
exit_status.signal_no = 0;
|
||||
|
||||
if (pid > 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, "waiting for pid %d to exit", pid);
|
||||
rv = waitpid(pid, &status, 0);
|
||||
|
||||
if (rv != -1)
|
||||
{
|
||||
if (WIFEXITED(status))
|
||||
{
|
||||
exit_status.exit_code = WEXITSTATUS(status);
|
||||
}
|
||||
if (WIFSIGNALED(status))
|
||||
{
|
||||
exit_status.signal_no = WTERMSIG(status);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING, "wait for pid %d returned unknown result", pid);
|
||||
}
|
||||
}
|
||||
|
||||
return exit_status;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* does not work in win32 */
|
||||
void
|
||||
|
@ -23,6 +23,15 @@
|
||||
|
||||
#include "arch.h"
|
||||
|
||||
struct exit_status
|
||||
{
|
||||
/* set to -1 when the process exited via a signal */
|
||||
uint8_t exit_code;
|
||||
|
||||
/* set to 0 when the process exited normally */
|
||||
uint8_t signal_no;
|
||||
};
|
||||
|
||||
#define g_tcp_can_recv g_sck_can_recv
|
||||
#define g_tcp_can_send g_sck_can_send
|
||||
#define g_tcp_recv g_sck_recv
|
||||
@ -145,6 +154,7 @@ int g_getlogin(char *name, unsigned int len);
|
||||
int g_setlogin(const char *name);
|
||||
int g_waitchild(void);
|
||||
int g_waitpid(int pid);
|
||||
struct exit_status g_waitpid_status(int pid);
|
||||
void g_clearenv(void);
|
||||
int g_setenv(const char *name, const char *value, int rewrite);
|
||||
char *g_getenv(const char *name);
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "log.h"
|
||||
#include "os_calls.h"
|
||||
#include "string_calls.h"
|
||||
#include "defines.h"
|
||||
|
||||
unsigned int
|
||||
g_format_info_string(char *dest, unsigned int len,
|
||||
@ -806,3 +807,50 @@ g_strtrim(char *str, int trim_flags)
|
||||
free(text1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
char *
|
||||
g_strnjoin(char *dest, int dest_len, const char *joiner, const char *src[], int src_len)
|
||||
{
|
||||
int len = 0;
|
||||
int joiner_len;
|
||||
int i = 0;
|
||||
int dest_remaining;
|
||||
char *dest_pos = dest;
|
||||
char *dest_end;
|
||||
|
||||
if (dest == NULL || dest_len < 1)
|
||||
{
|
||||
return dest;
|
||||
}
|
||||
if (src == NULL || src_len < 1)
|
||||
{
|
||||
dest[0] = '\0';
|
||||
return dest;
|
||||
}
|
||||
|
||||
dest[0] = '\0';
|
||||
dest_end = dest + dest_len - 1;
|
||||
joiner_len = g_strlen(joiner);
|
||||
for (i = 0; i < src_len - 1 && dest_pos < dest_end; i++)
|
||||
{
|
||||
len = g_strlen(src[i]);
|
||||
dest_remaining = dest_end - dest_pos;
|
||||
g_strncat(dest_pos, src[i], dest_remaining);
|
||||
dest_pos += MIN(len, dest_remaining);
|
||||
|
||||
if (dest_pos < dest_end)
|
||||
{
|
||||
dest_remaining = dest_end - dest_pos;
|
||||
g_strncat(dest_pos, joiner, dest_remaining);
|
||||
dest_pos += MIN(joiner_len, dest_remaining);
|
||||
}
|
||||
}
|
||||
|
||||
if (i == src_len - 1 && dest_pos < dest_end)
|
||||
{
|
||||
g_strncat(dest_pos, src[i], dest_end - dest_pos);
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
@ -80,6 +80,33 @@ g_bool2text(int value);
|
||||
int
|
||||
g_text2bool(const char *s);
|
||||
|
||||
/**
|
||||
* Joins an array of strings into a single string.
|
||||
*
|
||||
* Note: The joiner is placed between each source string. The joiner is not
|
||||
* placed after the last source string. If there is only one source string,
|
||||
* then the result string will be equal to the source string.
|
||||
*
|
||||
* Note: any content that is present in dest will be overwritten with the new
|
||||
* joined string.
|
||||
*
|
||||
* Note: If the destination array is not large enough to hold the entire
|
||||
* contents of the joined string, then the joined string will be truncated
|
||||
* to fit in the destination array.
|
||||
*
|
||||
* @param[out] dest The destination array to write the joined string into.
|
||||
* @param[in] dest_len The max number of characters to write to the destination
|
||||
* array including the terminating null. Must be > 0
|
||||
* @param[in] joiner The string to concatenate between each source string.
|
||||
* The joiner string may be NULL which is processed as a zero length string.
|
||||
* @param[in] src An array of strings to join. The array must be non-null.
|
||||
* Array items may be NULL and are processed as zero length strings.
|
||||
* @param[in] src_len The number of strings to join in the src array. Must be > 0
|
||||
* @return A pointer to the begining of the joined string (ie. returns dest).
|
||||
*/
|
||||
char *
|
||||
g_strnjoin(char *dest, int dest_len, const char *joiner, const char *src[], int src_len);
|
||||
|
||||
/**
|
||||
* Converts a binary array into a hux dump suitable for displaying to a user.
|
||||
*
|
||||
|
@ -357,6 +357,11 @@ AC_CHECK_HEADER([X11/extensions/Xrandr.h], [],
|
||||
|
||||
CFLAGS="$save_CFLAGS"
|
||||
|
||||
# checking for libcheck (used for unit testing)
|
||||
PKG_CHECK_MODULES([CHECK], [check >= 0.10.0])
|
||||
AC_CHECK_HEADER([check.h], [],
|
||||
[AC_MSG_ERROR([please install check])])
|
||||
|
||||
AC_SUBST([moduledir], '${libdir}/xrdp')
|
||||
|
||||
AC_ARG_ENABLE([strict-locations],
|
||||
@ -398,6 +403,7 @@ AC_CONFIG_FILES([
|
||||
sesman/Makefile
|
||||
sesman/tools/Makefile
|
||||
tests/Makefile
|
||||
tests/common/Makefile
|
||||
tests/memtest/Makefile
|
||||
tools/Makefile
|
||||
tools/devel/Makefile
|
||||
@ -409,6 +415,7 @@ AC_CONFIG_FILES([
|
||||
xup/Makefile
|
||||
])
|
||||
|
||||
AC_REQUIRE_AUX_FILE([tap-driver.sh])
|
||||
AC_OUTPUT
|
||||
|
||||
echo ""
|
||||
|
@ -1,21 +1,19 @@
|
||||
#!/bin/sh
|
||||
set -eufx
|
||||
|
||||
FEATURE_SET="$1"
|
||||
ARCH="$2"
|
||||
shift
|
||||
shift
|
||||
FEATURE_SET=min
|
||||
ARCH=amd64
|
||||
|
||||
if [ $# -ge 1 ]; then
|
||||
FEATURE_SET="$1"
|
||||
shift
|
||||
fi
|
||||
if [ $# -ge 1 ]; then
|
||||
ARCH="$1"
|
||||
shift
|
||||
fi
|
||||
APT_EXTRA_ARGS="$@"
|
||||
|
||||
if [ -z "$FEATURE_SET" ]; then
|
||||
FEATURE_SET=min
|
||||
fi
|
||||
|
||||
if [ -z "$ARCH" ]; then
|
||||
ARCH=amd64
|
||||
fi
|
||||
|
||||
|
||||
# common build tools for all architectures and feature sets
|
||||
PACKAGES=" \
|
||||
autoconf \
|
||||
@ -26,7 +24,8 @@ PACKAGES=" \
|
||||
libtool \
|
||||
make \
|
||||
nasm \
|
||||
pkg-config\
|
||||
pkg-config \
|
||||
check \
|
||||
"
|
||||
|
||||
case "$ARCH"
|
||||
|
330
sesman/session.c
330
sesman/session.c
@ -116,23 +116,19 @@ session_get_bydata(const char *name, int width, int height, int bpp, int type,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
LOG(LOG_LEVEL_INFO,
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"session_get_bydata: search policy %d U %s W %d H %d bpp %d T %d IP %s",
|
||||
policy, name, width, height, bpp, type, client_ip);
|
||||
#endif
|
||||
|
||||
while (tmp != 0)
|
||||
{
|
||||
#if 0
|
||||
LOG(LOG_LEVEL_INFO,
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"session_get_bydata: try %p U %s W %d H %d bpp %d T %d IP %s",
|
||||
tmp->item,
|
||||
tmp->item->name,
|
||||
tmp->item->width, tmp->item->height,
|
||||
tmp->item->bpp, tmp->item->type,
|
||||
tmp->item->client_ip);
|
||||
#endif
|
||||
|
||||
if (g_strncmp(name, tmp->item->name, 255) == 0 &&
|
||||
(!(policy & SESMAN_CFG_SESS_POLICY_D) ||
|
||||
@ -173,12 +169,14 @@ x_server_running_check_ports(int display)
|
||||
|
||||
if (!x_running)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text);
|
||||
g_sprintf(text, "/tmp/.X%d-lock", display);
|
||||
x_running = g_file_exist(text);
|
||||
}
|
||||
|
||||
if (!x_running) /* check 59xx */
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text);
|
||||
if ((sck = g_tcp_socket()) != -1)
|
||||
{
|
||||
g_sprintf(text, "59%2.2d", display);
|
||||
@ -189,6 +187,7 @@ x_server_running_check_ports(int display)
|
||||
|
||||
if (!x_running) /* check 60xx */
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text);
|
||||
if ((sck = g_tcp_socket()) != -1)
|
||||
{
|
||||
g_sprintf(text, "60%2.2d", display);
|
||||
@ -199,6 +198,7 @@ x_server_running_check_ports(int display)
|
||||
|
||||
if (!x_running) /* check 62xx */
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text);
|
||||
if ((sck = g_tcp_socket()) != -1)
|
||||
{
|
||||
g_sprintf(text, "62%2.2d", display);
|
||||
@ -209,34 +209,44 @@ x_server_running_check_ports(int display)
|
||||
|
||||
if (!x_running)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text);
|
||||
g_sprintf(text, XRDP_CHANSRV_STR, display);
|
||||
x_running = g_file_exist(text);
|
||||
}
|
||||
|
||||
if (!x_running)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text);
|
||||
g_sprintf(text, CHANSRV_PORT_OUT_STR, display);
|
||||
x_running = g_file_exist(text);
|
||||
}
|
||||
|
||||
if (!x_running)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text);
|
||||
g_sprintf(text, CHANSRV_PORT_IN_STR, display);
|
||||
x_running = g_file_exist(text);
|
||||
}
|
||||
|
||||
if (!x_running)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text);
|
||||
g_sprintf(text, CHANSRV_API_STR, display);
|
||||
x_running = g_file_exist(text);
|
||||
}
|
||||
|
||||
if (!x_running)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text);
|
||||
g_sprintf(text, XRDP_X11RDP_STR, display);
|
||||
x_running = g_file_exist(text);
|
||||
}
|
||||
|
||||
if (x_running)
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "Found X server running at %s", text);
|
||||
}
|
||||
|
||||
return x_running;
|
||||
}
|
||||
|
||||
@ -259,10 +269,20 @@ x_server_running(int display)
|
||||
|
||||
if (!x_running)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text);
|
||||
g_sprintf(text, "/tmp/.X%d-lock", display);
|
||||
x_running = g_file_exist(text);
|
||||
}
|
||||
|
||||
if (x_running)
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "Found X server running at %s", text);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text);
|
||||
}
|
||||
|
||||
return x_running;
|
||||
}
|
||||
|
||||
@ -314,7 +334,9 @@ session_get_avail_display_from_chain(void)
|
||||
display++;
|
||||
}
|
||||
|
||||
LOG(LOG_LEVEL_ERROR, "X server -- no display in range is available");
|
||||
LOG(LOG_LEVEL_ERROR, "X server -- no display in range (%d to %d) is available",
|
||||
g_cfg->sess.x11_display_offset,
|
||||
g_cfg->sess.x11_display_offset + g_cfg->sess.max_sessions);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -328,14 +350,16 @@ wait_for_xserver(int display)
|
||||
/* wait up to 10 secs for x server to start */
|
||||
i = 0;
|
||||
|
||||
LOG(LOG_LEVEL_DEBUG, "Waiting for X server to start on display %d", display);
|
||||
|
||||
while (!x_server_running(display))
|
||||
{
|
||||
i++;
|
||||
|
||||
if (i > 40)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"X server for display %d startup timeout",
|
||||
LOG(LOG_LEVEL_WARNING,
|
||||
"Timed out waiting for X server on display %d to startup",
|
||||
display);
|
||||
break;
|
||||
}
|
||||
@ -357,6 +381,9 @@ session_start_chansrv(char *username, int display)
|
||||
chansrv_pid = g_fork();
|
||||
if (chansrv_pid == 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO,
|
||||
"Starting the xrdp channel server for display %d", display);
|
||||
|
||||
chansrv_params = list_create();
|
||||
chansrv_params->auto_free = 1;
|
||||
|
||||
@ -373,9 +400,8 @@ session_start_chansrv(char *username, int display)
|
||||
|
||||
/* executing chansrv */
|
||||
g_execvp(exe_path, (char **) (chansrv_params->items));
|
||||
|
||||
/* should not get here */
|
||||
LOG(LOG_LEVEL_ALWAYS, "error starting chansrv "
|
||||
"- user %s - pid %d", username, g_getpid());
|
||||
list_delete(chansrv_params);
|
||||
g_exit(1);
|
||||
}
|
||||
@ -390,13 +416,12 @@ session_start_fork(tbus data, tui8 type, struct SCP_CONNECTION *c,
|
||||
{
|
||||
int display = 0;
|
||||
int pid = 0;
|
||||
int i = 0;
|
||||
char geometry[32];
|
||||
char depth[32];
|
||||
char screen[32]; /* display number */
|
||||
char text[256];
|
||||
char execvpparams[2048];
|
||||
char *xserver; /* absolute/relative path to Xorg/X11rdp/Xvnc */
|
||||
char *xserver = NULL; /* absolute/relative path to Xorg/X11rdp/Xvnc */
|
||||
char *passwd_file;
|
||||
char **pp1 = (char **)NULL;
|
||||
struct session_chain *temp = (struct session_chain *)NULL;
|
||||
@ -421,7 +446,7 @@ session_start_fork(tbus data, tui8 type, struct SCP_CONNECTION *c,
|
||||
/* check to limit concurrent sessions */
|
||||
if (g_session_count >= g_cfg->sess.max_sessions)
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "max concurrent session limit "
|
||||
LOG(LOG_LEVEL_ERROR, "max concurrent session limit "
|
||||
"exceeded. login for user %s denied", s->username);
|
||||
return 0;
|
||||
}
|
||||
@ -430,8 +455,8 @@ session_start_fork(tbus data, tui8 type, struct SCP_CONNECTION *c,
|
||||
|
||||
if (temp == 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "cannot create new chain "
|
||||
"element - user %s", s->username);
|
||||
LOG(LOG_LEVEL_ERROR, "Out of memory error: cannot create new session "
|
||||
"chain element - user %s", s->username);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -440,7 +465,7 @@ session_start_fork(tbus data, tui8 type, struct SCP_CONNECTION *c,
|
||||
if (temp->item == 0)
|
||||
{
|
||||
g_free(temp);
|
||||
LOG(LOG_LEVEL_ERROR, "cannot create new session "
|
||||
LOG(LOG_LEVEL_ERROR, "Out of memory error: cannot create new session "
|
||||
"item - user %s", s->username);
|
||||
return 0;
|
||||
}
|
||||
@ -459,11 +484,16 @@ session_start_fork(tbus data, tui8 type, struct SCP_CONNECTION *c,
|
||||
|
||||
if (pid == -1)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"[session start] (display %d): Failed to fork for scp with "
|
||||
"errno: %d, description: %s",
|
||||
display, g_get_errno(), g_get_strerror());
|
||||
}
|
||||
else if (pid == 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "calling auth_start_session from pid %d",
|
||||
g_getpid());
|
||||
LOG(LOG_LEVEL_INFO,
|
||||
"[session start] (display %d): calling auth_start_session from pid %d",
|
||||
display, g_getpid());
|
||||
auth_start_session(data, display);
|
||||
g_delete_wait_obj(g_term_event);
|
||||
g_tcp_close(g_sck);
|
||||
@ -494,15 +524,16 @@ session_start_fork(tbus data, tui8 type, struct SCP_CONNECTION *c,
|
||||
*/
|
||||
if (g_setsid() < 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"setsid failed - pid %d", g_getpid());
|
||||
LOG(LOG_LEVEL_WARNING,
|
||||
"[session start] (display %d): setsid failed - pid %d",
|
||||
display, g_getpid());
|
||||
}
|
||||
|
||||
if (g_setlogin(s->username) < 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"setlogin failed for user %s - pid %d", s->username,
|
||||
g_getpid());
|
||||
LOG(LOG_LEVEL_WARNING,
|
||||
"[session start] (display %d): setlogin failed for user %s - pid %d",
|
||||
display, s->username, g_getpid());
|
||||
}
|
||||
}
|
||||
|
||||
@ -521,6 +552,8 @@ session_start_fork(tbus data, tui8 type, struct SCP_CONNECTION *c,
|
||||
child forks wm, and waits, todo */
|
||||
if (window_manager_pid == -1)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"Failed to fork for the window manager on display %d", display);
|
||||
}
|
||||
else if (window_manager_pid == 0)
|
||||
{
|
||||
@ -540,79 +573,74 @@ session_start_fork(tbus data, tui8 type, struct SCP_CONNECTION *c,
|
||||
g_set_current_dir(s->directory);
|
||||
}
|
||||
}
|
||||
if (s->program != 0)
|
||||
if (s->program != 0 && s->program[0] != 0)
|
||||
{
|
||||
if (s->program[0] != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"starting program with parameters: %s ",
|
||||
s->program);
|
||||
if (g_strchr(s->program, ' ') != 0 || g_strchr(s->program, '\t') != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO,
|
||||
"Starting user requested window manager on "
|
||||
"display %d with embeded arguments using a shell: %s",
|
||||
display, s->program);
|
||||
const char *params[] = {"sh", "-c", s->program, NULL};
|
||||
g_execvp("/bin/sh", (char **)params);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO,
|
||||
"Starting user requested window manager on "
|
||||
"display %d: %s", display, s->program);
|
||||
g_execlp3(s->program, s->program, 0);
|
||||
}
|
||||
LOG(LOG_LEVEL_ALWAYS,
|
||||
"error starting program %s for user %s - pid %d",
|
||||
s->program, s->username, g_getpid());
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, "The user session on display %d did "
|
||||
"not request a specific window manager", display);
|
||||
}
|
||||
|
||||
/* try to execute user window manager if enabled */
|
||||
if (g_cfg->enable_user_wm)
|
||||
{
|
||||
g_sprintf(text, "%s/%s", g_getenv("HOME"), g_cfg->user_wm);
|
||||
if (g_file_exist(text))
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO,
|
||||
"Starting window manager on display %d"
|
||||
"from user home directory: %s", display, text);
|
||||
g_execlp3(text, g_cfg->user_wm, 0);
|
||||
LOG(LOG_LEVEL_ALWAYS, "error starting user "
|
||||
"wm for user %s - pid %d", s->username, g_getpid());
|
||||
/* logging parameters */
|
||||
LOG(LOG_LEVEL_DEBUG, "errno: %d, "
|
||||
"description: %s", g_get_errno(), g_get_strerror());
|
||||
LOG(LOG_LEVEL_DEBUG, "execlp3 parameter "
|
||||
"list:");
|
||||
LOG(LOG_LEVEL_DEBUG, " argv[0] = %s",
|
||||
text);
|
||||
LOG(LOG_LEVEL_DEBUG, " argv[1] = %s",
|
||||
g_cfg->user_wm);
|
||||
}
|
||||
}
|
||||
/* if we're here something happened to g_execlp3
|
||||
so we try running the default window manager */
|
||||
g_execlp3(g_cfg->default_wm, g_cfg->default_wm, 0);
|
||||
|
||||
LOG(LOG_LEVEL_ALWAYS, "error starting default "
|
||||
"wm for user %s - pid %d", s->username, g_getpid());
|
||||
/* logging parameters */
|
||||
LOG(LOG_LEVEL_DEBUG, "errno: %d, description: "
|
||||
"%s", g_get_errno(), g_get_strerror());
|
||||
LOG(LOG_LEVEL_DEBUG, "execlp3 parameter list:");
|
||||
LOG(LOG_LEVEL_DEBUG, " argv[0] = %s",
|
||||
g_cfg->default_wm);
|
||||
LOG(LOG_LEVEL_DEBUG, " argv[1] = %s",
|
||||
g_cfg->default_wm);
|
||||
|
||||
/* still a problem starting window manager just start xterm */
|
||||
g_execlp3("xterm", "xterm", 0);
|
||||
|
||||
/* should not get here */
|
||||
LOG(LOG_LEVEL_ALWAYS, "error starting xterm "
|
||||
"for user %s - pid %d", s->username, g_getpid());
|
||||
/* logging parameters */
|
||||
LOG(LOG_LEVEL_DEBUG, "errno: %d, description: "
|
||||
"%s", g_get_errno(), g_get_strerror());
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "another Xserver might "
|
||||
"already be active on display %d - see log", display);
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"The user home directory window manager configuration "
|
||||
"is enabled but window manager program does not exist: %s",
|
||||
text);
|
||||
}
|
||||
}
|
||||
|
||||
LOG(LOG_LEVEL_DEBUG, "aborting connection...");
|
||||
LOG(LOG_LEVEL_INFO,
|
||||
"Starting the default window manager on display %d: %s",
|
||||
display, g_cfg->default_wm);
|
||||
g_execlp3(g_cfg->default_wm, g_cfg->default_wm, 0);
|
||||
|
||||
/* still a problem starting window manager just start xterm */
|
||||
LOG(LOG_LEVEL_WARNING,
|
||||
"No window manager on display %d started, "
|
||||
"so falling back to starting xterm for user debugging",
|
||||
display);
|
||||
g_execlp3("xterm", "xterm", 0);
|
||||
|
||||
/* should not get here */
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"There is no X server active on display %d", display);
|
||||
}
|
||||
|
||||
LOG(LOG_LEVEL_ERROR, "A fatal error has occured attempting to start "
|
||||
"the window manager on display %d, aborting connection",
|
||||
display);
|
||||
g_exit(0);
|
||||
}
|
||||
else
|
||||
@ -621,6 +649,8 @@ session_start_fork(tbus data, tui8 type, struct SCP_CONNECTION *c,
|
||||
child becomes X */
|
||||
if (display_pid == -1)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"Failed to fork for the X server on display %d", display);
|
||||
}
|
||||
else if (display_pid == 0) /* child */
|
||||
{
|
||||
@ -641,7 +671,7 @@ session_start_fork(tbus data, tui8 type, struct SCP_CONNECTION *c,
|
||||
g_cfg->env_values);
|
||||
}
|
||||
|
||||
|
||||
/* setting Xserver environment variables */
|
||||
g_snprintf(text, 255, "%d", g_cfg->sess.max_idle_time);
|
||||
g_setenv("XRDP_SESMAN_MAX_IDLE_TIME", text, 1);
|
||||
g_snprintf(text, 255, "%d", g_cfg->sess.max_disc_time);
|
||||
@ -663,6 +693,13 @@ session_start_fork(tbus data, tui8 type, struct SCP_CONNECTION *c,
|
||||
/* Add the entry in XAUTHORITY file or exit if error */
|
||||
if (add_xauth_cookie(display, authfile) != 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"Error setting the xauth cookie for display %d in file %s",
|
||||
display, authfile);
|
||||
|
||||
LOG(LOG_LEVEL_ERROR, "A fatal error has occured attempting to start "
|
||||
"the X server on display %d, aborting connection",
|
||||
display);
|
||||
g_exit(1);
|
||||
}
|
||||
|
||||
@ -678,8 +715,9 @@ session_start_fork(tbus data, tui8 type, struct SCP_CONNECTION *c,
|
||||
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING,
|
||||
"Failed to disable setuid on X server: %s",
|
||||
g_get_strerror());
|
||||
"[session start] (display %d): Failed to disable "
|
||||
"setuid on X server: %s",
|
||||
display, g_get_strerror());
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -703,17 +741,12 @@ session_start_fork(tbus data, tui8 type, struct SCP_CONNECTION *c,
|
||||
|
||||
pp1 = (char **) xserver_params->items;
|
||||
|
||||
LOG(LOG_LEVEL_INFO, "%s", dumpItemsToString(xserver_params, execvpparams, 2048));
|
||||
|
||||
/* some args are passed via env vars */
|
||||
g_sprintf(geometry, "%d", s->width);
|
||||
g_setenv("XRDP_START_WIDTH", geometry, 1);
|
||||
|
||||
g_sprintf(geometry, "%d", s->height);
|
||||
g_setenv("XRDP_START_HEIGHT", geometry, 1);
|
||||
|
||||
/* fire up Xorg */
|
||||
g_execvp(xserver, pp1);
|
||||
}
|
||||
else if (type == SESMAN_SESSION_TYPE_XVNC)
|
||||
{
|
||||
@ -748,8 +781,6 @@ session_start_fork(tbus data, tui8 type, struct SCP_CONNECTION *c,
|
||||
/* make sure it ends with a zero */
|
||||
list_add_item(xserver_params, 0);
|
||||
pp1 = (char **)xserver_params->items;
|
||||
LOG(LOG_LEVEL_INFO, "%s", dumpItemsToString(xserver_params, execvpparams, 2048));
|
||||
g_execvp(xserver, pp1);
|
||||
}
|
||||
else if (type == SESMAN_SESSION_TYPE_XRDP)
|
||||
{
|
||||
@ -777,31 +808,27 @@ session_start_fork(tbus data, tui8 type, struct SCP_CONNECTION *c,
|
||||
/* make sure it ends with a zero */
|
||||
list_add_item(xserver_params, 0);
|
||||
pp1 = (char **)xserver_params->items;
|
||||
LOG(LOG_LEVEL_INFO, "%s", dumpItemsToString(xserver_params, execvpparams, 2048));
|
||||
g_execvp(xserver, pp1);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_ALWAYS, "bad session type - "
|
||||
"user %s - pid %d", s->username, g_getpid());
|
||||
LOG(LOG_LEVEL_ERROR, "Unknown session type: %d", type);
|
||||
LOG(LOG_LEVEL_ERROR, "A fatal error has occured attempting "
|
||||
"to start the X server on display %d, aborting connection",
|
||||
display);
|
||||
g_exit(1);
|
||||
}
|
||||
|
||||
/* fire up X server */
|
||||
LOG(LOG_LEVEL_INFO, "Starting X server on display %d: %s",
|
||||
display, dumpItemsToString(xserver_params, execvpparams, 2048));
|
||||
g_execvp(xserver, pp1);
|
||||
|
||||
/* should not get here */
|
||||
LOG(LOG_LEVEL_ALWAYS, "error starting X server "
|
||||
"- user %s - pid %d", s->username, g_getpid());
|
||||
|
||||
/* logging parameters */
|
||||
LOG(LOG_LEVEL_DEBUG, "errno: %d, description: "
|
||||
"%s", g_get_errno(), g_get_strerror());
|
||||
LOG(LOG_LEVEL_DEBUG, "execve parameter list size: "
|
||||
"%d", (xserver_params)->count);
|
||||
|
||||
for (i = 0; i < (xserver_params->count); i++)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, " argv[%d] = %s",
|
||||
i, (char *)list_get_item(xserver_params, i));
|
||||
}
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"Error starting X server on display %d", display);
|
||||
LOG(LOG_LEVEL_ERROR, "A fatal error has occured attempting "
|
||||
"to start the X server on display %d, aborting connection",
|
||||
display);
|
||||
|
||||
list_delete(xserver_params);
|
||||
g_exit(1);
|
||||
@ -809,40 +836,77 @@ session_start_fork(tbus data, tui8 type, struct SCP_CONNECTION *c,
|
||||
else
|
||||
{
|
||||
int wm_wait_time;
|
||||
struct exit_status wm_exit_status;
|
||||
struct exit_status xserver_exit_status;
|
||||
struct exit_status chansrv_exit_status;
|
||||
|
||||
wait_for_xserver(display);
|
||||
chansrv_pid = session_start_chansrv(s->username, display);
|
||||
|
||||
LOG(LOG_LEVEL_INFO,
|
||||
"Session started successfully for user %s on display %d",
|
||||
s->username, display);
|
||||
|
||||
/* Monitor the amount of time we wait for the
|
||||
* window manager. This is approximately how long the window
|
||||
* manager was running for */
|
||||
LOG(LOG_LEVEL_INFO, "waiting for window manager "
|
||||
"(pid %d) to exit", window_manager_pid);
|
||||
LOG(LOG_LEVEL_INFO, "Session in progress on display %d, waiting "
|
||||
"until the window manager (pid %d) exits to end the session",
|
||||
display, window_manager_pid);
|
||||
wm_wait_time = g_time1();
|
||||
g_waitpid(window_manager_pid);
|
||||
wm_exit_status = g_waitpid_status(window_manager_pid);
|
||||
wm_wait_time = g_time1() - wm_wait_time;
|
||||
if (wm_exit_status.exit_code > 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING, "Window manager (pid %d, display %d) "
|
||||
"exited with non-zero exit code %d and signal %d. This "
|
||||
"could indicate a window manager config problem",
|
||||
window_manager_pid, display, wm_exit_status.exit_code,
|
||||
wm_exit_status.signal_no);
|
||||
}
|
||||
if (wm_wait_time < 10)
|
||||
{
|
||||
/* This could be a config issue. Log a significant error */
|
||||
LOG(LOG_LEVEL_ALWAYS, "window manager exited quickly "
|
||||
"(%d secs). Window manager config problem?",
|
||||
wm_wait_time);
|
||||
LOG(LOG_LEVEL_WARNING, "Window manager (pid %d, display %d) "
|
||||
"exited quickly (%d secs). This could indicate a window "
|
||||
"manager config problem",
|
||||
window_manager_pid, display, wm_wait_time);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "window manager (pid %d) was running "
|
||||
"for approximately %d seconds.",
|
||||
window_manager_pid, wm_wait_time);
|
||||
LOG(LOG_LEVEL_DEBUG, "Window manager (pid %d, display %d) "
|
||||
"was running for %d seconds.",
|
||||
window_manager_pid, display, wm_wait_time);
|
||||
}
|
||||
LOG(LOG_LEVEL_INFO, "Cleaning up session. Calling "
|
||||
"auth_stop_session and auth_end from pid %d", g_getpid());
|
||||
LOG(LOG_LEVEL_INFO,
|
||||
"Calling auth_stop_session and auth_end from pid %d",
|
||||
g_getpid());
|
||||
auth_stop_session(data);
|
||||
auth_end(data);
|
||||
|
||||
LOG(LOG_LEVEL_INFO,
|
||||
"Terminating X server (pid %d) on display %d",
|
||||
display_pid, display);
|
||||
g_sigterm(display_pid);
|
||||
|
||||
LOG(LOG_LEVEL_INFO, "Terminating the xrdp channel server (pid %d) "
|
||||
"on display %d", chansrv_pid, display);
|
||||
g_sigterm(chansrv_pid);
|
||||
|
||||
/* make sure socket cleanup happen after child process exit */
|
||||
g_waitpid(display_pid);
|
||||
g_waitpid(chansrv_pid);
|
||||
xserver_exit_status = g_waitpid_status(display_pid);
|
||||
LOG(LOG_LEVEL_INFO,
|
||||
"X server on display %d (pid %d) returned exit code %d "
|
||||
"and signal number %d",
|
||||
display, display_pid, xserver_exit_status.exit_code,
|
||||
xserver_exit_status.signal_no);
|
||||
|
||||
chansrv_exit_status = g_waitpid_status(chansrv_pid);
|
||||
LOG(LOG_LEVEL_INFO,
|
||||
"xrdp channel server for display %d (pid %d) "
|
||||
"exit code %d and signal number %d",
|
||||
display, chansrv_pid, chansrv_exit_status.exit_code,
|
||||
chansrv_exit_status.signal_no);
|
||||
|
||||
cleanup_sockets(display);
|
||||
g_deinit();
|
||||
@ -852,6 +916,10 @@ session_start_fork(tbus data, tui8 type, struct SCP_CONNECTION *c,
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "Starting session: session_pid %d, "
|
||||
"display :%d.0, width %d, height %d, bpp %d, client ip %s, "
|
||||
"user name %s",
|
||||
pid, display, s->width, s->height, s->bpp, s->client_ip, s->username);
|
||||
temp->item->pid = pid;
|
||||
temp->item->display = display;
|
||||
temp->item->width = s->width;
|
||||
@ -898,6 +966,7 @@ session_reconnect_fork(int display, char *username, long data)
|
||||
|
||||
if (pid == -1)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "Failed to fork for session reconnection script");
|
||||
}
|
||||
else if (pid == 0)
|
||||
{
|
||||
@ -910,9 +979,25 @@ session_reconnect_fork(int display, char *username, long data)
|
||||
|
||||
if (g_file_exist(g_cfg->reconnect_sh))
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO,
|
||||
"Starting session reconnection script on display %d: %s",
|
||||
display, g_cfg->reconnect_sh);
|
||||
g_execlp3(g_cfg->reconnect_sh, g_cfg->reconnect_sh, 0);
|
||||
|
||||
/* should not get here */
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"Error starting session reconnection script on display %d: %s",
|
||||
display, g_cfg->reconnect_sh);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_WARNING,
|
||||
"Session reconnection script file does not exist: %s",
|
||||
g_cfg->reconnect_sh);
|
||||
}
|
||||
|
||||
/* TODO: why is this existing with a success error code when the
|
||||
reconnect script failed to be executed? */
|
||||
g_exit(0);
|
||||
}
|
||||
|
||||
@ -972,7 +1057,9 @@ session_kill(int pid)
|
||||
if (tmp->item->pid == pid)
|
||||
{
|
||||
/* deleting the session */
|
||||
LOG(LOG_LEVEL_INFO, "++ terminated session: username %s, display :%d.0, session_pid %d, ip %s", tmp->item->name, tmp->item->display, tmp->item->pid, tmp->item->client_ip);
|
||||
LOG(LOG_LEVEL_INFO,
|
||||
"++ terminated session: username %s, display :%d.0, session_pid %d, ip %s",
|
||||
tmp->item->name, tmp->item->display, tmp->item->pid, tmp->item->client_ip);
|
||||
g_free(tmp->item);
|
||||
|
||||
if (prev == 0)
|
||||
@ -1011,8 +1098,7 @@ session_sigkill_all(void)
|
||||
{
|
||||
if (tmp->item == 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "found null session "
|
||||
"descriptor!");
|
||||
LOG(LOG_LEVEL_ERROR, "found null session descriptor!");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1045,8 +1131,7 @@ session_get_bypid(int pid)
|
||||
{
|
||||
if (tmp->item == 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "session descriptor for "
|
||||
"pid %d is null!", pid);
|
||||
LOG(LOG_LEVEL_ERROR, "session descriptor for pid %d is null!", pid);
|
||||
g_free(dummy);
|
||||
return 0;
|
||||
}
|
||||
@ -1078,13 +1163,12 @@ session_get_byuser(const char *user, int *cnt, unsigned char flags)
|
||||
|
||||
tmp = g_sessions;
|
||||
|
||||
LOG(LOG_LEVEL_DEBUG, "searching for session by user: %s", user);
|
||||
while (tmp != 0)
|
||||
{
|
||||
LOG_DEVEL(LOG_LEVEL_DEBUG, "user: %s", user);
|
||||
|
||||
if ((NULL == user) || (!g_strncasecmp(user, tmp->item->name, 256)))
|
||||
{
|
||||
LOG_DEVEL(LOG_LEVEL_DEBUG, "session_get_byuser: status=%d, flags=%d, "
|
||||
LOG(LOG_LEVEL_DEBUG, "session_get_byuser: status=%d, flags=%d, "
|
||||
"result=%d", (tmp->item->status), flags,
|
||||
((tmp->item->status) & flags));
|
||||
|
||||
@ -1169,7 +1253,7 @@ session_get_byuser(const char *user, int *cnt, unsigned char flags)
|
||||
int
|
||||
cleanup_sockets(int display)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG, "cleanup_sockets:");
|
||||
LOG(LOG_LEVEL_INFO, "cleanup_sockets:");
|
||||
char file[256];
|
||||
int error;
|
||||
|
||||
|
@ -3,4 +3,5 @@ EXTRA_DIST = \
|
||||
readme.txt
|
||||
|
||||
SUBDIRS = \
|
||||
common \
|
||||
memtest
|
||||
|
23
tests/common/Makefile.am
Normal file
23
tests/common/Makefile.am
Normal file
@ -0,0 +1,23 @@
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_builddir) \
|
||||
-I$(top_srcdir)/common
|
||||
|
||||
if XRDP_DEBUG
|
||||
AM_CPPFLAGS += -DXRDP_DEBUG
|
||||
endif
|
||||
|
||||
LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) \
|
||||
$(top_srcdir)/tap-driver.sh
|
||||
|
||||
TESTS = test_common
|
||||
check_PROGRAMS = test_common
|
||||
|
||||
test_common_SOURCES = \
|
||||
test_common.h \
|
||||
test_common_main.c \
|
||||
test_string_calls.c
|
||||
|
||||
test_common_LDADD = \
|
||||
$(top_builddir)/common/libcommon.la \
|
||||
@CHECK_LIBS@
|
9
tests/common/test_common.h
Normal file
9
tests/common/test_common.h
Normal file
@ -0,0 +1,9 @@
|
||||
|
||||
#ifndef TEST_COMMON_H
|
||||
#define TEST_COMMON_H
|
||||
|
||||
#include <check.h>
|
||||
|
||||
Suite *make_suite_test_string(void);
|
||||
|
||||
#endif /* TEST_COMMON_H */
|
23
tests/common/test_common_main.c
Normal file
23
tests/common/test_common_main.c
Normal file
@ -0,0 +1,23 @@
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include "config_ac.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <check.h>
|
||||
#include "test_common.h"
|
||||
|
||||
int main (void)
|
||||
{
|
||||
int number_failed;
|
||||
SRunner *sr;
|
||||
|
||||
sr = srunner_create (make_suite_test_string());
|
||||
// srunner_add_suite(sr, make_list_suite());
|
||||
|
||||
srunner_set_tap(sr, "-");
|
||||
srunner_run_all (sr, CK_ENV);
|
||||
number_failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
240
tests/common/test_string_calls.c
Normal file
240
tests/common/test_string_calls.c
Normal file
@ -0,0 +1,240 @@
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include "config_ac.h"
|
||||
#endif
|
||||
|
||||
#include "test_common.h"
|
||||
#include "string_calls.h"
|
||||
|
||||
#define RESULT_LEN 1024
|
||||
|
||||
START_TEST(test_strnjoin__when_src_is_null__returns_empty_string)
|
||||
{
|
||||
/* setup */
|
||||
|
||||
const char **src = NULL;
|
||||
char result[RESULT_LEN];
|
||||
result[0] = '\0';
|
||||
|
||||
/* test */
|
||||
|
||||
g_strnjoin(result, RESULT_LEN, " ", src, 0);
|
||||
|
||||
/* verify */
|
||||
|
||||
ck_assert_str_eq(result, "");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_strnjoin__when_src_has_null_item__returns_joined_string)
|
||||
{
|
||||
/* setup */
|
||||
|
||||
const char *test_value = "test_value";
|
||||
const char *src[] = { test_value, NULL };
|
||||
char result[RESULT_LEN];
|
||||
result[0] = '\0';
|
||||
|
||||
/* test */
|
||||
|
||||
g_strnjoin(result, RESULT_LEN, " ", src, 2);
|
||||
|
||||
/* verify */
|
||||
|
||||
ck_assert_str_eq(result, "test_value ");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_strnjoin__when_src_has_one_item__returns_copied_source_string)
|
||||
{
|
||||
/* setup */
|
||||
|
||||
const char *expected_value = "test_value";
|
||||
const char *src[] = { expected_value };
|
||||
char result[RESULT_LEN];
|
||||
result[0] = '\0';
|
||||
|
||||
/* test */
|
||||
|
||||
g_strnjoin(result, RESULT_LEN, " ", src, 1);
|
||||
|
||||
/* verify */
|
||||
|
||||
ck_assert_str_eq(result, expected_value);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_strnjoin__when_src_has_two_items__returns_joined_string)
|
||||
{
|
||||
/* setup */
|
||||
|
||||
const char *test_value = "test_value";
|
||||
const char *src[] = { test_value, test_value };
|
||||
char result[RESULT_LEN];
|
||||
result[0] = '\0';
|
||||
|
||||
/* test */
|
||||
|
||||
g_strnjoin(result, RESULT_LEN, " ", src, 2);
|
||||
|
||||
/* verify */
|
||||
|
||||
ck_assert_str_eq(result, "test_value test_value");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_strnjoin__when_joiner_is_empty_string__returns_joined_string)
|
||||
{
|
||||
/* setup */
|
||||
|
||||
const char *test_value = "test_value";
|
||||
const char *src[] = { test_value, test_value };
|
||||
char result[RESULT_LEN];
|
||||
result[0] = '\0';
|
||||
|
||||
/* test */
|
||||
|
||||
g_strnjoin(result, RESULT_LEN, "", src, 2);
|
||||
|
||||
/* verify */
|
||||
|
||||
ck_assert_str_eq(result, "test_valuetest_value");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_strnjoin__when_joiner_is_NULL__returns_joined_string)
|
||||
{
|
||||
/* setup */
|
||||
|
||||
const char *test_value = "test_value";
|
||||
const char *src[] = { test_value, test_value };
|
||||
char result[RESULT_LEN];
|
||||
result[0] = '\0';
|
||||
|
||||
/* test */
|
||||
|
||||
g_strnjoin(result, RESULT_LEN, NULL, src, 2);
|
||||
|
||||
/* verify */
|
||||
|
||||
ck_assert_str_eq(result, "test_valuetest_value");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_strnjoin__when_destination_is_NULL__returns_NULL)
|
||||
{
|
||||
/* setup */
|
||||
|
||||
const char *test_value = "test_value";
|
||||
const char *src[] = { test_value };
|
||||
char *result = NULL;
|
||||
|
||||
/* test */
|
||||
|
||||
g_strnjoin(result, 0, " ", src, 1);
|
||||
|
||||
/* verify */
|
||||
|
||||
ck_assert_ptr_eq(result, NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_strnjoin__when_destination_is_shorter_than_src__returns_partial_src_string)
|
||||
{
|
||||
/* setup */
|
||||
|
||||
const char *test_value = "test_value";
|
||||
const char *src[] = { test_value };
|
||||
char result[5];
|
||||
result[0] = '\0';
|
||||
|
||||
/* test */
|
||||
|
||||
g_strnjoin(result, 5, " ", src, 1);
|
||||
|
||||
/* verify */
|
||||
|
||||
ck_assert_str_eq(result, "test");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_strnjoin__when_destination_is_shorter_than_src_plus_joiner__returns_partial_joined_string)
|
||||
{
|
||||
/* setup */
|
||||
|
||||
const char *test_value = "test_value";
|
||||
const char *src[] = { test_value, test_value};
|
||||
char result[16];
|
||||
result[0] = '\0';
|
||||
|
||||
/* test */
|
||||
|
||||
g_strnjoin(result, 16, " joiner ", src, 2);
|
||||
|
||||
/* verify */
|
||||
|
||||
ck_assert_str_eq(result, "test_value join");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_strnjoin__when_destination_has_contents__returns_joined_string_with_content_overwritten)
|
||||
{
|
||||
/* setup */
|
||||
|
||||
const char *test_value = "test_value";
|
||||
const char *src[] = { test_value, test_value};
|
||||
char result[RESULT_LEN] = "1234567890";
|
||||
|
||||
/* test */
|
||||
|
||||
g_strnjoin(result, RESULT_LEN, " ", src, 2);
|
||||
|
||||
/* verify */
|
||||
|
||||
ck_assert_str_eq(result, "test_value test_value");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_strnjoin__when_always__then_doesnt_write_beyond_end_of_destination)
|
||||
{
|
||||
/* setup */
|
||||
|
||||
const char *src[] = { "a","b","c"};
|
||||
char result[5+1+1]; /* a-b-c + term null + guard value */
|
||||
|
||||
/* test */
|
||||
|
||||
result[6] = '\x7f';
|
||||
g_strnjoin(result, 5 + 1, "-", src, 3);
|
||||
|
||||
/* verify */
|
||||
|
||||
ck_assert_int_eq(result[6], '\x7f');
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/******************************************************************************/
|
||||
Suite *
|
||||
make_suite_test_string(void)
|
||||
{
|
||||
Suite *s;
|
||||
TCase *tc_strnjoin;
|
||||
|
||||
s = suite_create("String");
|
||||
|
||||
tc_strnjoin = tcase_create("strnjoin");
|
||||
suite_add_tcase(s, tc_strnjoin);
|
||||
tcase_add_test(tc_strnjoin, test_strnjoin__when_src_is_null__returns_empty_string);
|
||||
tcase_add_test(tc_strnjoin, test_strnjoin__when_src_has_null_item__returns_joined_string);
|
||||
tcase_add_test(tc_strnjoin, test_strnjoin__when_src_has_one_item__returns_copied_source_string);
|
||||
tcase_add_test(tc_strnjoin, test_strnjoin__when_src_has_two_items__returns_joined_string);
|
||||
tcase_add_test(tc_strnjoin, test_strnjoin__when_joiner_is_empty_string__returns_joined_string);
|
||||
tcase_add_test(tc_strnjoin, test_strnjoin__when_joiner_is_NULL__returns_joined_string);
|
||||
tcase_add_test(tc_strnjoin, test_strnjoin__when_destination_is_NULL__returns_NULL);
|
||||
tcase_add_test(tc_strnjoin, test_strnjoin__when_destination_is_shorter_than_src__returns_partial_src_string);
|
||||
tcase_add_test(tc_strnjoin, test_strnjoin__when_destination_is_shorter_than_src_plus_joiner__returns_partial_joined_string);
|
||||
tcase_add_test(tc_strnjoin, test_strnjoin__when_destination_has_contents__returns_joined_string_with_content_overwritten);
|
||||
tcase_add_test(tc_strnjoin, test_strnjoin__when_always__then_doesnt_write_beyond_end_of_destination);
|
||||
|
||||
return s;
|
||||
}
|
@ -9,6 +9,9 @@ endif
|
||||
noinst_PROGRAMS = \
|
||||
memtest
|
||||
|
||||
check_PROGRAMS = \
|
||||
memtest
|
||||
|
||||
memtest_SOURCES = \
|
||||
libmem.h \
|
||||
libmem.c \
|
||||
|
Loading…
Reference in New Issue
Block a user