os_calls changes

- Add g_pipe()
- Add g_file_duplicate_on()
- Rework struct exit_status to make it easier to parse
- Add optional status return to g_waitchild()
This commit is contained in:
matt335672 2023-03-10 15:52:07 +00:00
parent b53060e734
commit 8b9f9b40c8
6 changed files with 132 additions and 43 deletions

View File

@ -1396,6 +1396,13 @@ g_sleep(int msecs)
#endif
}
/*****************************************************************************/
int
g_pipe(int fd[2])
{
return pipe(fd);
}
/*****************************************************************************/
int
g_sck_last_error_would_block(int sck)
@ -2344,6 +2351,24 @@ mode_t_to_hex(mode_t mode)
}
#endif
/*****************************************************************************/
/* Duplicates a file descriptor onto another one using the semantics
* of dup2() */
/* return boolean */
int
g_file_duplicate_on(int fd, int target_fd)
{
int rv = (dup2(fd, target_fd) >= 0);
if (rv < 0)
{
LOG(LOG_LEVEL_ERROR, "Can't clone file %d as file %d [%s]",
fd, target_fd, g_get_strerror());
}
return rv;
}
/*****************************************************************************/
/* returns error */
int
@ -3051,9 +3076,11 @@ g_set_allusercontext(int uid)
#endif
/*****************************************************************************/
/* does not work in win32
returns pid of process that exits or zero if signal occurred */
returns pid of process that exits or zero if signal occurred
an exit_status struct can optionally be passed in to get the
exit status of the child */
int
g_waitchild(void)
g_waitchild(struct exit_status *e)
{
#if defined(_WIN32)
return 0;
@ -3061,15 +3088,36 @@ g_waitchild(void)
int wstat;
int rv;
struct exit_status dummy;
if (e == NULL)
{
e = &dummy; // Set this, then throw it away
}
e->reason = E_XR_UNEXPECTED;
e->val = 0;
rv = waitpid(0, &wstat, WNOHANG);
if (rv == -1)
{
if (errno == EINTR) /* signal occurred */
if (errno == EINTR)
{
/* This shouldn't happen as signal handlers use SA_RESTART */
rv = 0;
}
}
else if (WIFEXITED(wstat))
{
e->reason = E_XR_STATUS_CODE;
e->val = WEXITSTATUS(wstat);
}
else if (WIFSIGNALED(wstat))
{
e->reason = E_XR_SIGNAL;
e->val = WTERMSIG(wstat);
}
return rv;
#endif
@ -3077,7 +3125,10 @@ g_waitchild(void)
/*****************************************************************************/
/* does not work in win32
returns pid of process that exits or <= 0 if no process was found */
returns pid of process that exits or <= 0 if no process was found
Note that signal handlers are established with BSD-style semantics,
so this call is NOT interrupted by a signal */
int
g_waitpid(int pid)
{
@ -3101,25 +3152,21 @@ g_waitpid(int pid)
/*****************************************************************************/
/* does not work in win32
returns exit status code of child process with pid */
returns exit status code of child process with pid
Note that signal handlers are established with BSD-style semantics,
so this call is NOT interrupted by a signal */
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;
struct exit_status exit_status = {.reason = E_XR_UNEXPECTED, .val = 0};
#if !defined(_WIN32)
if (pid > 0)
{
int rv;
int status;
LOG(LOG_LEVEL_DEBUG, "waiting for pid %d to exit", pid);
rv = waitpid(pid, &status, 0);
@ -3127,11 +3174,13 @@ g_waitpid_status(int pid)
{
if (WIFEXITED(status))
{
exit_status.exit_code = WEXITSTATUS(status);
exit_status.reason = E_XR_STATUS_CODE;
exit_status.val = WEXITSTATUS(status);
}
if (WIFSIGNALED(status))
{
exit_status.signal_no = WTERMSIG(status);
exit_status.reason = E_XR_SIGNAL;
exit_status.val = WTERMSIG(status);
}
}
else
@ -3140,8 +3189,8 @@ g_waitpid_status(int pid)
}
}
return exit_status;
#endif
return exit_status;
}
/*****************************************************************************/

View File

@ -23,13 +23,17 @@
#include "arch.h"
enum exit_reason
{
E_XR_STATUS_CODE = 0, ///< 'val' contains exit status
E_XR_SIGNAL, ///< 'val' contains a signal number
E_XR_UNEXPECTED
};
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;
enum exit_reason reason;
int val;
};
struct list;
@ -178,6 +182,8 @@ const char *
g_sck_get_peer_description(int sck,
char *desc, unsigned int bytes);
void g_sleep(int msecs);
int g_pipe(int fd[2]);
tintptr g_create_wait_obj(const char *name);
tintptr g_create_wait_obj_from_socket(tintptr socket, int write);
void g_delete_wait_obj_from_socket(tintptr wait_obj);
@ -213,6 +219,7 @@ int g_file_read(int fd, char *ptr, int len);
int g_file_write(int fd, const char *ptr, int len);
int g_file_seek(int fd, int offset);
int g_file_lock(int fd, int start, int len);
int g_file_duplicate_on(int fd, int target_fd);
int g_chmod_hex(const char *filename, int flags);
int g_umask_hex(int flags);
int g_chown(const char *name, int uid, int gid);
@ -273,7 +280,7 @@ int g_setlogin(const char *name);
*/
int g_set_allusercontext(int uid);
#endif
int g_waitchild(void);
int g_waitchild(struct exit_status *e);
int g_waitpid(int pid);
struct exit_status g_waitpid_status(int pid);
void g_clearenv(void);

View File

@ -1522,7 +1522,7 @@ child_signal_handler(int sig)
LOG_DEVEL(LOG_LEVEL_INFO, "child_signal_handler:");
do
{
pid = g_waitchild();
pid = g_waitchild(NULL);
LOG_DEVEL(LOG_LEVEL_INFO, "child_signal_handler: child pid %d", pid);
if ((pid == g_exec_pid) && (pid > 0))
{

View File

@ -401,6 +401,33 @@ username_from_uid(int uid, char *uname, int uname_len)
return rv;
}
/******************************************************************************/
static void
exit_status_to_str(const struct exit_status *e, char buff[], int bufflen)
{
switch (e->reason)
{
case E_XR_STATUS_CODE:
if (e->val == 0)
{
g_snprintf(buff, bufflen, "exit code zero");
}
else
{
g_snprintf(buff, bufflen, "non-zero exit code %d", e->val);
}
break;
case E_XR_SIGNAL:
g_snprintf(buff, bufflen, "signal %d", e->val);
break;
default:
g_snprintf(buff, bufflen, "an unexpected error");
break;
}
}
/******************************************************************************/
enum scp_screate_status
@ -841,7 +868,7 @@ session_start(struct auth_info *auth_info,
struct exit_status wm_exit_status;
struct exit_status xserver_exit_status;
struct exit_status chansrv_exit_status;
char reason[128];
chansrv_pid = session_start_chansrv(s->uid, display);
LOG(LOG_LEVEL_INFO,
@ -857,13 +884,20 @@ session_start(struct auth_info *auth_info,
wm_wait_time = g_time1();
wm_exit_status = g_waitpid_status(window_manager_pid);
wm_wait_time = g_time1() - wm_wait_time;
if (wm_exit_status.exit_code > 0)
if (wm_exit_status.reason == E_XR_STATUS_CODE &&
wm_exit_status.val == 0)
{
LOG(LOG_LEVEL_WARNING, "Window manager (pid %d, display %d) "
"exited with non-zero exit code %d and signal %d. This "
// Normal exit
}
else
{
exit_status_to_str(&wm_exit_status, reason, sizeof(reason));
LOG(LOG_LEVEL_WARNING,
"Window manager (pid %d, display %d) "
"exited with %s. This "
"could indicate a window manager config problem",
window_manager_pid, display, wm_exit_status.exit_code,
wm_exit_status.signal_no);
window_manager_pid, display, reason);
}
if (wm_wait_time < 10)
{
@ -898,18 +932,17 @@ session_start(struct auth_info *auth_info,
/* make sure socket cleanup happen after child process exit */
xserver_exit_status = g_waitpid_status(display_pid);
exit_status_to_str(&xserver_exit_status, reason, sizeof(reason));
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);
"X server on display %d (pid %d) exited with %s",
display, display_pid, reason);
chansrv_exit_status = g_waitpid_status(chansrv_pid);
exit_status_to_str(&chansrv_exit_status, reason, sizeof(reason));
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);
"xrdp channel server for display %d (pid %d)"
" exited with %s",
display, chansrv_pid, reason);
cleanup_sockets(display);
g_deinit();

View File

@ -105,7 +105,7 @@ sig_sesman_session_end(void)
LOG(LOG_LEVEL_DEBUG, "receiving SIGCHLD");
do
{
pid = g_waitchild();
pid = g_waitchild(NULL);
if (pid > 0)
{

View File

@ -89,7 +89,7 @@ xrdp_shutdown(int sig)
static void
xrdp_child(int sig)
{
while (g_waitchild() > 0)
while (g_waitchild(NULL) > 0)
{
}
}