Merge remote branch 'rjy/clientids'
This commit is contained in:
		
						commit
						8e4c3ce55b
					
				|  | @ -40,6 +40,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |||
| #include "propertyst.h" | ||||
| #include "extnsionst.h" | ||||
| #include "xacestr.h" | ||||
| #include "client.h" | ||||
| #include "../os/osdep.h" | ||||
| #define _XSELINUX_NEED_FLASK_MAP | ||||
| #include "xselinuxint.h" | ||||
|  | @ -129,26 +130,25 @@ SELinuxLabelClient(ClientPtr client) | |||
| 
 | ||||
|     /* For local clients, try and determine the executable name */ | ||||
|     if (XaceIsLocal(client)) { | ||||
| 	struct ucred creds; | ||||
| 	socklen_t len = sizeof(creds); | ||||
| 	char path[PATH_MAX + 1]; | ||||
| 	size_t bytes; | ||||
| 	/* Get cached command name if CLIENTIDS is enabled. */ | ||||
| 	const char *cmdname = GetClientCmdName(client); | ||||
| 	Bool cached = (cmdname != NULL); | ||||
| 	/* If CLIENTIDS is disabled, figure out the command name from
 | ||||
| 	 * scratch. */ | ||||
| 	if (!cmdname) | ||||
| 	{ | ||||
| 	    pid_t pid = DetermineClientPid(client); | ||||
| 	    if (pid != -1) | ||||
| 		DetermineClientCmd(pid, &cmdname, NULL); | ||||
| 	} | ||||
| 
 | ||||
| 	memset(&creds, 0, sizeof(creds)); | ||||
| 	if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &creds, &len) < 0) | ||||
| 	if (!cmdname) | ||||
| 	    goto finish; | ||||
| 
 | ||||
| 	snprintf(path, PATH_MAX + 1, "/proc/%d/cmdline", creds.pid); | ||||
| 	fd = open(path, O_RDONLY); | ||||
| 	if (fd < 0) | ||||
| 	    goto finish; | ||||
| 	strncpy(subj->command, cmdname, COMMAND_LEN - 1); | ||||
| 
 | ||||
| 	bytes = read(fd, path, PATH_MAX + 1); | ||||
| 	close(fd); | ||||
| 	if (bytes <= 0) | ||||
| 	    goto finish; | ||||
| 
 | ||||
| 	strncpy(subj->command, path, COMMAND_LEN - 1); | ||||
| 	if (!cached) | ||||
| 	    free((void *) cmdname); /* const char * */ | ||||
|     } | ||||
| 
 | ||||
| finish: | ||||
|  |  | |||
							
								
								
									
										28
									
								
								configure.ac
								
								
								
								
							
							
						
						
									
										28
									
								
								configure.ac
								
								
								
								
							|  | @ -312,19 +312,6 @@ AC_CHECK_HEADER([execinfo.h],[ | |||
|     ])] | ||||
| ) | ||||
| 
 | ||||
| dnl ARM needs additional compiler flags for proper backtraces if GCC is | ||||
| dnl used. Compile a dummy program with the -mapcs-frame option. If it | ||||
| dnl succeeds, we know that we are building for ARM with GCC. | ||||
| old_CFLAGS="$CFLAGS" | ||||
| CFLAGS="-mapcs-frame" | ||||
| AC_COMPILE_IFELSE( | ||||
|         AC_LANG_PROGRAM([[ ]]), | ||||
|         ARM_BACKTRACE_CFLAGS="$CFLAGS", | ||||
|         ARM_BACKTRACE_CFLAGS="" | ||||
| ) | ||||
| CFLAGS="$old_CFLAGS" | ||||
| AC_SUBST(ARM_BACKTRACE_CFLAGS) | ||||
| 
 | ||||
| dnl --------------------------------------------------------------------------- | ||||
| dnl Bus options and CPU capabilities.  Replaces logic in | ||||
| dnl hw/xfree86/os-support/bus/Makefile.am, among others. | ||||
|  | @ -641,6 +628,7 @@ AC_ARG_ENABLE(vbe,            AS_HELP_STRING([--enable-vbe], [Build Xorg with VB | |||
| AC_ARG_ENABLE(int10-module,     AS_HELP_STRING([--enable-int10-module], [Build Xorg with int10 module (default: enabled)]), [INT10MODULE=$enableval], [INT10MODULE=yes]) | ||||
| AC_ARG_ENABLE(windowswm,      AS_HELP_STRING([--enable-windowswm], [Build XWin with WindowsWM extension (default: no)]), [WINDOWSWM=$enableval], [WINDOWSWM=no]) | ||||
| AC_ARG_ENABLE(libdrm,         AS_HELP_STRING([--enable-libdrm], [Build Xorg with libdrm support (default: enabled)]), [DRM=$enableval],[DRM=yes]) | ||||
| AC_ARG_ENABLE(clientids,      AS_HELP_STRING([--disable-clientids], [Build Xorg with client ID tracking (default: enabled)]), [CLIENTIDS=$enableval], [CLIENTIDS=yes]) | ||||
| 
 | ||||
| dnl DDXes. | ||||
| AC_ARG_ENABLE(xorg,    	      AS_HELP_STRING([--enable-xorg], [Build Xorg server (default: auto)]), [XORG=$enableval], [XORG=auto]) | ||||
|  | @ -994,6 +982,18 @@ if test "x$RES" = xyes; then | |||
| 	REQUIRED_MODULES="$REQUIRED_MODULES $RESOURCEPROTO" | ||||
| fi | ||||
| 
 | ||||
| # The XRes extension may support client ID tracking only if it has | ||||
| # been specifically enabled. Client ID tracking is implicitly not | ||||
| # supported if XRes extension is disabled. | ||||
| AC_MSG_CHECKING([whether to track client ids]) | ||||
| if test "x$RES" = xyes && test "x$CLIENTIDS" = xyes; then | ||||
| 	AC_DEFINE(CLIENTIDS, 1, [Support client ID tracking]) | ||||
| else | ||||
| 	CLIENTIDS=no | ||||
| fi | ||||
| AC_MSG_RESULT([$CLIENTIDS]) | ||||
| AM_CONDITIONAL(CLIENTIDS, [test "x$CLIENTIDS" = xyes]) | ||||
| 
 | ||||
| if test "x$GLX" = xyes; then | ||||
| 	PKG_CHECK_MODULES([XLIB], [x11]) | ||||
| 	PKG_CHECK_MODULES([GL], $GLPROTO $LIBGL) | ||||
|  | @ -1525,7 +1525,7 @@ if test "x$XNEST" = xyes; then | |||
| 	if test "x$have_xnest" = xno; then | ||||
| 		AC_MSG_ERROR([Xnest build explicitly requested, but required modules not found.]) | ||||
| 	fi | ||||
| 	XNEST_LIBS="$FB_LIB $FIXES_LIB $MI_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $DIX_LIB $MAIN_LIB $OS_LIB" | ||||
| 	XNEST_LIBS="$FB_LIB $FIXES_LIB $MI_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $MAIN_LIB $DIX_LIB $OS_LIB" | ||||
| 	XNEST_SYS_LIBS="$XNESTMODULES_LIBS $GLX_SYS_LIBS" | ||||
| 	AC_SUBST([XNEST_LIBS]) | ||||
| 	AC_SUBST([XNEST_SYS_LIBS]) | ||||
|  |  | |||
|  | @ -130,6 +130,7 @@ int ProcInitialConnection(); | |||
| #include "inputstr.h" | ||||
| #include "xkbsrv.h" | ||||
| #include "site.h" | ||||
| #include "client.h" | ||||
| 
 | ||||
| #ifdef XSERVER_DTRACE | ||||
| #include "registry.h" | ||||
|  | @ -3459,6 +3460,9 @@ CloseDownClient(ClientPtr client) | |||
| 	    CallCallbacks((&ClientStateCallback), (pointer)&clientinfo); | ||||
| 	} 	     | ||||
| 	FreeClientResources(client); | ||||
| 	/* Disable client ID tracking. This must be done after
 | ||||
| 	 * ClientStateCallback. */ | ||||
| 	ReleaseClientIds(client); | ||||
| #ifdef XSERVER_DTRACE | ||||
| 	XSERVER_CLIENT_DISCONNECT(client->index); | ||||
| #endif	 | ||||
|  | @ -3496,6 +3500,7 @@ void InitClient(ClientPtr client, int i, pointer ospriv) | |||
|     client->smart_start_tick = SmartScheduleTime; | ||||
|     client->smart_stop_tick = SmartScheduleTime; | ||||
|     client->smart_check_tick = SmartScheduleTime; | ||||
|     client->clientIds = NULL; | ||||
| } | ||||
| 
 | ||||
| /************************
 | ||||
|  | @ -3535,6 +3540,11 @@ ClientPtr NextAvailableClient(pointer ospriv) | |||
| 	currentMaxClients++; | ||||
|     while ((nextFreeClientID < MAXCLIENTS) && clients[nextFreeClientID]) | ||||
| 	nextFreeClientID++; | ||||
| 
 | ||||
|     /* Enable client ID tracking. This must be done before
 | ||||
|      * ClientStateCallback. */ | ||||
|     ReserveClientIds(client); | ||||
| 
 | ||||
|     if (ClientStateCallback) | ||||
|     { | ||||
| 	NewClientInfoRec clientinfo; | ||||
|  |  | |||
|  | @ -104,6 +104,7 @@ Equipment Corporation. | |||
| #include "extnsionst.h" | ||||
| #include "privates.h" | ||||
| #include "registry.h" | ||||
| #include "client.h" | ||||
| #ifdef PANORAMIX | ||||
| #include "panoramiXsrv.h" | ||||
| #else | ||||
|  | @ -258,6 +259,7 @@ int main(int argc, char *argv[], char *envp[]) | |||
|         InitCoreDevices(); | ||||
| 	InitInput(argc, argv); | ||||
| 	InitAndStartDevices(); | ||||
| 	ReserveClientIds(serverClient); | ||||
| 
 | ||||
| 	dixSaveScreens(serverClient, SCREEN_SAVER_FORCER, ScreenSaverReset); | ||||
| 
 | ||||
|  | @ -323,6 +325,7 @@ int main(int argc, char *argv[], char *envp[]) | |||
| 	    screenInfo.numScreens = i; | ||||
| 	} | ||||
| 
 | ||||
| 	ReleaseClientIds(serverClient); | ||||
| 	dixFreePrivates(serverClient->devPrivates, PRIVATE_CLIENT); | ||||
| 	serverClient->devPrivates = NULL; | ||||
| 
 | ||||
|  |  | |||
|  | @ -259,6 +259,7 @@ cat > sdksyms.c << EOF | |||
| #include "colormap.h" | ||||
| #include "colormapst.h" | ||||
| #include "hotplug.h" | ||||
| #include "client.h" | ||||
| #include "cursor.h" | ||||
| #include "cursorstr.h" | ||||
| #include "dix.h" | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ sdk_HEADERS =		\ | |||
| 	XIstubs.h	\
 | ||||
| 	Xprintf.h	\
 | ||||
| 	callback.h	\
 | ||||
| 	client.h	\
 | ||||
| 	closestr.h	\
 | ||||
| 	closure.h	\
 | ||||
| 	colormap.h	\
 | ||||
|  |  | |||
|  | @ -0,0 +1,59 @@ | |||
| /*
 | ||||
|  * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). All | ||||
|  * rights reserved. | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
| 
 | ||||
| /* Author: Rami Ylimäki <rami.ylimaki@vincit.fi> */ | ||||
| 
 | ||||
| #ifndef CLIENT_H | ||||
| #define CLIENT_H | ||||
| 
 | ||||
| #ifdef HAVE_DIX_CONFIG_H | ||||
| #include <dix-config.h> | ||||
| #endif /* HAVE_DIX_CONFIG_H */ | ||||
| #include <X11/Xfuncproto.h> | ||||
| #include <sys/types.h> | ||||
| 
 | ||||
| /* Client IDs. Use GetClientPid, GetClientCmdName and GetClientCmdArgs
 | ||||
|  * instead of accessing the fields directly. */ | ||||
| typedef struct { | ||||
|     pid_t pid;           /* process ID, -1 if not available */ | ||||
|     const char *cmdname; /* process name, NULL if not available */ | ||||
|     const char *cmdargs; /* process arguments, NULL if not available */ | ||||
| } ClientIdRec, *ClientIdPtr; | ||||
| 
 | ||||
| struct _Client; | ||||
| 
 | ||||
| /* Initialize and clean up. */ | ||||
| void ReserveClientIds(struct _Client *client); | ||||
| void ReleaseClientIds(struct _Client *client); | ||||
| 
 | ||||
| /* Determine client IDs for caching. Exported on purpose for
 | ||||
|  * extensions such as SELinux. */ | ||||
| extern _X_EXPORT pid_t DetermineClientPid(struct _Client *client); | ||||
| extern _X_EXPORT void DetermineClientCmd(pid_t, const char **cmdname, const char **cmdargs); | ||||
| 
 | ||||
| /* Query cached client IDs. Exported on purpose for drivers. */ | ||||
| extern _X_EXPORT pid_t GetClientPid(struct _Client *client); | ||||
| extern _X_EXPORT const char *GetClientCmdName(struct _Client *client); | ||||
| extern _X_EXPORT const char *GetClientCmdArgs(struct _Client *client); | ||||
| 
 | ||||
| #endif /* CLIENT_H */ | ||||
|  | @ -279,6 +279,9 @@ | |||
| /* Support X resource extension */ | ||||
| #undef RES | ||||
| 
 | ||||
| /* Support client ID tracking in X resource extension */ | ||||
| #undef CLIENTIDS | ||||
| 
 | ||||
| /* Support MIT-SCREEN-SAVER extension */ | ||||
| #undef SCREENSAVER | ||||
| 
 | ||||
|  |  | |||
|  | @ -24,6 +24,7 @@ SOFTWARE. | |||
| #ifndef DIXSTRUCT_H | ||||
| #define DIXSTRUCT_H | ||||
| 
 | ||||
| #include "client.h" | ||||
| #include "dix.h" | ||||
| #include "resource.h" | ||||
| #include "cursor.h" | ||||
|  | @ -121,6 +122,7 @@ typedef struct _Client { | |||
|     long    smart_check_tick; | ||||
|      | ||||
|     DeviceIntPtr clientPtr; | ||||
|     ClientIdPtr  clientIds; | ||||
| }           ClientRec; | ||||
| 
 | ||||
| /*
 | ||||
|  |  | |||
|  | @ -1,25 +1,18 @@ | |||
| noinst_LTLIBRARIES = libos.la liblog.la | ||||
| noinst_LTLIBRARIES = libos.la | ||||
| 
 | ||||
| AM_CFLAGS = $(DIX_CFLAGS) $(SHA1_CFLAGS) | ||||
| 
 | ||||
| SECURERPC_SRCS = rpcauth.c | ||||
| XDMCP_SRCS = xdmcp.c | ||||
| STRLCAT_SRCS = strlcat.c strlcpy.c | ||||
| 
 | ||||
| # Build a convenience library liblog.la that will be added into
 | ||||
| # libos.la. The split is done so that log.c can be built with
 | ||||
| # different compiler options.
 | ||||
| liblog_la_SOURCES = log.c | ||||
| # Add flags needed for proper backtraces of functions marked with GCC
 | ||||
| # __attribute__((noreturn)). Currently those flags are needed for
 | ||||
| # FatalError and AbortServer in log.c.
 | ||||
| liblog_la_CFLAGS = $(AM_CFLAGS) $(ARM_BACKTRACE_CFLAGS) | ||||
| XORG_SRCS = log.c | ||||
| 
 | ||||
| libos_la_SOURCES = 	\
 | ||||
| 	WaitFor.c	\
 | ||||
| 	access.c	\
 | ||||
| 	auth.c		\
 | ||||
| 	backtrace.c	\
 | ||||
| 	client.c	\
 | ||||
| 	connection.c	\
 | ||||
| 	io.c		\
 | ||||
| 	mitauth.c	\
 | ||||
|  | @ -32,8 +25,9 @@ libos_la_SOURCES = 	\ | |||
| 	xdmauth.c	\
 | ||||
| 	xsha1.c		\
 | ||||
| 	xstrans.c	\
 | ||||
| 	xprintf.c | ||||
| libos_la_LIBADD = @SHA1_LIBS@ $(DLOPEN_LIBS) liblog.la | ||||
| 	xprintf.c	\
 | ||||
| 	$(XORG_SRCS) | ||||
| libos_la_LIBADD = @SHA1_LIBS@ $(DLOPEN_LIBS) | ||||
| 
 | ||||
| if SECURE_RPC | ||||
| libos_la_SOURCES += $(SECURERPC_SRCS) | ||||
|  |  | |||
|  | @ -0,0 +1,310 @@ | |||
| /*
 | ||||
|  * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). All | ||||
|  * rights reserved. | ||||
|  * Copyright (c) 1993, 2010, Oracle and/or its affiliates. All rights reserved. | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
| 
 | ||||
| /**
 | ||||
|  * @file | ||||
|  * | ||||
|  * This file contains functionality for identifying clients by various | ||||
|  * means. The primary purpose of identification is to simply aid in | ||||
|  * finding out which clients are using X server and how they are using | ||||
|  * it. For example, it's often necessary to monitor what requests | ||||
|  * clients are executing (to spot bad behaviour) and how they are | ||||
|  * allocating resources in X server (to spot excessive resource | ||||
|  * usage). | ||||
|  * | ||||
|  * This framework automatically allocates information, that can be | ||||
|  * used for client identification, when a client connects to the | ||||
|  * server. The information is freed when the client disconnects. The | ||||
|  * allocated information is just a collection of various IDs, such as | ||||
|  * PID and process name for local clients, that are likely to be | ||||
|  * useful in analyzing X server usage. | ||||
|  * | ||||
|  * Users of the framework can query ID information about clients at | ||||
|  * any time. To avoid repeated polling of IDs the users can also | ||||
|  * subscribe for notifications about the availability of ID | ||||
|  * information. IDs have been allocated before ClientStateCallback is | ||||
|  * called with ClientStateInitial state. Similarly the IDs will be | ||||
|  * released after ClientStateCallback is called with ClientStateGone | ||||
|  * state. | ||||
|  * | ||||
|  * Author: Rami Ylimäki <rami.ylimaki@vincit.fi> | ||||
|  */ | ||||
| 
 | ||||
| #include <sys/stat.h> | ||||
| #include <fcntl.h> | ||||
| #include <unistd.h> | ||||
| 
 | ||||
| #include "client.h" | ||||
| #include "os.h" | ||||
| #include "dixstruct.h" | ||||
| 
 | ||||
| /**
 | ||||
|  * Try to determine a PID for a client from its connection | ||||
|  * information. This should be called only once when new client has | ||||
|  * connected, use GetClientPid to determine the PID at other times. | ||||
|  * | ||||
|  * @param[in] client Connection linked to some process. | ||||
|  * | ||||
|  * @return PID of the client. Error (-1) if PID can't be determined | ||||
|  *         for the client. | ||||
|  * | ||||
|  * @see GetClientPid | ||||
|  */ | ||||
| pid_t DetermineClientPid(struct _Client *client) | ||||
| { | ||||
|     LocalClientCredRec *lcc = NULL; | ||||
|     pid_t pid = -1; | ||||
| 
 | ||||
|     if (client == NullClient) | ||||
|         return pid; | ||||
| 
 | ||||
|     if (client == serverClient) | ||||
|         return getpid(); | ||||
| 
 | ||||
|     if (GetLocalClientCreds(client, &lcc) != -1) | ||||
|     { | ||||
|         if (lcc->fieldsSet & LCC_PID_SET) | ||||
|             pid = lcc->pid; | ||||
|         FreeLocalClientCreds(lcc); | ||||
|     } | ||||
| 
 | ||||
|     return pid; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Try to determine a command line string for a client based on its | ||||
|  * PID. Note that mapping PID to a command hasn't been implemented for | ||||
|  * some operating systems. This should be called only once when a new | ||||
|  * client has connected, use GetClientCmdName/Args to determine the | ||||
|  * string at other times. | ||||
|  * | ||||
|  * @param[in]  pid     Process ID of a client. | ||||
| 
 | ||||
|  * @param[out] cmdname Client process name without arguments. You must | ||||
|  *                     release this by calling free. On error NULL is | ||||
|  *                     returned. Pass NULL if you aren't interested in | ||||
|  *                     this value. | ||||
|  * @param[out] cmdargs Arguments to client process. Useful for | ||||
|  *                     identifying a client that is executed from a | ||||
|  *                     launcher program. You must release this by | ||||
|  *                     calling free. On error NULL is returned. Pass | ||||
|  *                     NULL if you aren't interested in this value. | ||||
|  * | ||||
|  * @see GetClientCmdName/Args | ||||
|  */ | ||||
| void DetermineClientCmd(pid_t pid, const char **cmdname, const char **cmdargs) | ||||
| { | ||||
|     char path[PATH_MAX + 1]; | ||||
|     int totsize = 0; | ||||
|     int cmdsize = 0; | ||||
|     int argsize = 0; | ||||
|     int fd = 0; | ||||
| 
 | ||||
|     if (cmdname) | ||||
|         *cmdname = NULL; | ||||
|     if (cmdargs) | ||||
|         *cmdargs = NULL; | ||||
| 
 | ||||
|     if (pid == -1) | ||||
|         return; | ||||
| 
 | ||||
|     /* Check if /proc/pid/cmdline exists. It's not supported on all
 | ||||
|      * operating systems. */ | ||||
|     if (snprintf(path, sizeof(path), "/proc/%d/cmdline", pid) < 0) | ||||
|         return; | ||||
|     fd = open(path, O_RDONLY); | ||||
|     if (fd < 0) | ||||
|         return; | ||||
| 
 | ||||
|     /* Read the contents of /proc/pid/cmdline. It should contain the
 | ||||
|      * process name and arguments. */ | ||||
|     totsize = read(fd, path, sizeof(path)); | ||||
|     if (totsize <= 0) | ||||
|         return; | ||||
|     if (close(fd) < 0) | ||||
|         return; | ||||
|     path[totsize - 1] = '\0'; | ||||
| 
 | ||||
|     /* Contruct the process name without arguments. */ | ||||
|     cmdsize = strlen(path) + 1; | ||||
|     if (cmdname) | ||||
|     { | ||||
|         char *name = malloc(cmdsize); | ||||
|         if (name) | ||||
|         { | ||||
|             strncpy(name, path, cmdsize); | ||||
|             name[cmdsize - 1] = '\0'; | ||||
|             *cmdname = name; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /* Construct the arguments for client process. */ | ||||
|     argsize = totsize - cmdsize; | ||||
|     if (cmdargs && (argsize > 0)) | ||||
|     { | ||||
|         char *args = malloc(argsize); | ||||
|         if (args) | ||||
|         { | ||||
|             int i = 0; | ||||
|             for (i = 0; i < (argsize - 1); ++i) | ||||
|             { | ||||
|                 const char c = path[cmdsize + i]; | ||||
|                 args[i] = (c == '\0') ? ' ' : c; | ||||
|             } | ||||
|             args[argsize - 1] = '\0'; | ||||
|             *cmdargs = args; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Called when a new client connects. Allocates client ID information. | ||||
|  * | ||||
|  * @param[in] client Recently connected client. | ||||
|  */ | ||||
| void ReserveClientIds(struct _Client *client) | ||||
| { | ||||
| #ifdef CLIENTIDS | ||||
|     if (client == NullClient) | ||||
|         return; | ||||
| 
 | ||||
|     assert(!client->clientIds); | ||||
|     client->clientIds = calloc(1, sizeof(ClientIdRec)); | ||||
|     if (!client->clientIds) | ||||
|         return; | ||||
| 
 | ||||
|     client->clientIds->pid = DetermineClientPid(client); | ||||
|     if (client->clientIds->pid != -1) | ||||
|         DetermineClientCmd(client->clientIds->pid, &client->clientIds->cmdname, &client->clientIds->cmdargs); | ||||
| 
 | ||||
|     DebugF("client(%lx): Reserved pid(%d).\n", | ||||
|            client->clientAsMask, client->clientIds->pid); | ||||
|     DebugF("client(%lx): Reserved cmdname(%s) and cmdargs(%s).\n", | ||||
|            client->clientAsMask, | ||||
|            client->clientIds->cmdname ? client->clientIds->cmdname : "NULL", | ||||
|            client->clientIds->cmdargs ? client->clientIds->cmdargs : "NULL"); | ||||
| #endif /* CLIENTIDS */ | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Called when an existing client disconnects. Frees client ID | ||||
|  * information. | ||||
|  * | ||||
|  * @param[in] client Recently disconnected client. | ||||
|  */ | ||||
| void ReleaseClientIds(struct _Client *client) | ||||
| { | ||||
| #ifdef CLIENTIDS | ||||
|     if (client == NullClient) | ||||
|         return; | ||||
| 
 | ||||
|     if (!client->clientIds) | ||||
|         return; | ||||
| 
 | ||||
|     DebugF("client(%lx): Released pid(%d).\n", | ||||
|            client->clientAsMask, client->clientIds->pid); | ||||
|     DebugF("client(%lx): Released cmdline(%s) and cmdargs(%s).\n", | ||||
|            client->clientAsMask, | ||||
|            client->clientIds->cmdname ? client->clientIds->cmdname : "NULL", | ||||
|            client->clientIds->cmdargs ? client->clientIds->cmdargs : "NULL"); | ||||
| 
 | ||||
|     free((void *) client->clientIds->cmdname); /* const char * */ | ||||
|     free((void *) client->clientIds->cmdargs); /* const char * */ | ||||
|     free(client->clientIds); | ||||
|     client->clientIds = NULL; | ||||
| #endif /* CLIENTIDS */ | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Get cached PID of a client. | ||||
|  * | ||||
|  * param[in] client Client whose PID has been already cached. | ||||
|  * | ||||
|  * @return Cached client PID. Error (-1) if called: | ||||
|  *         - before ClientStateInitial client state notification | ||||
|  *         - after ClientStateGone client state notification | ||||
|  *         - for remote clients | ||||
|  * | ||||
|  * @see DetermineClientPid | ||||
|  */ | ||||
| pid_t GetClientPid(struct _Client *client) | ||||
| { | ||||
|     if (client == NullClient) | ||||
|         return -1; | ||||
| 
 | ||||
|     if (!client->clientIds) | ||||
|         return -1; | ||||
| 
 | ||||
|     return client->clientIds->pid; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Get cached command name string of a client. | ||||
|  * | ||||
|  * param[in] client Client whose command line string has been already | ||||
|  *                  cached. | ||||
|  * | ||||
|  * @return Cached client command name. Error (NULL) if called: | ||||
|  *         - before ClientStateInitial client state notification | ||||
|  *         - after ClientStateGone client state notification | ||||
|  *         - for remote clients | ||||
|  *         - on OS that doesn't support mapping of PID to command line | ||||
|  * | ||||
|  * @see DetermineClientCmd | ||||
|  */ | ||||
| const char *GetClientCmdName(struct _Client *client) | ||||
| { | ||||
|     if (client == NullClient) | ||||
|         return NULL; | ||||
| 
 | ||||
|     if (!client->clientIds) | ||||
|         return NULL; | ||||
| 
 | ||||
|     return client->clientIds->cmdname; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Get cached command arguments string of a client. | ||||
|  * | ||||
|  * param[in] client Client whose command line string has been already | ||||
|  *                  cached. | ||||
|  * | ||||
|  * @return Cached client command arguments. Error (NULL) if called: | ||||
|  *         - before ClientStateInitial client state notification | ||||
|  *         - after ClientStateGone client state notification | ||||
|  *         - for remote clients | ||||
|  *         - on OS that doesn't support mapping of PID to command line | ||||
|  * | ||||
|  * @see DetermineClientCmd | ||||
|  */ | ||||
| const char *GetClientCmdArgs(struct _Client *client) | ||||
| { | ||||
|     if (client == NullClient) | ||||
|         return NULL; | ||||
| 
 | ||||
|     if (!client->clientIds) | ||||
|         return NULL; | ||||
| 
 | ||||
|     return client->clientIds->cmdargs; | ||||
| } | ||||
		Loading…
	
		Reference in New Issue