Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'agent/tcf/services/sysmon.c')
-rw-r--r--agent/tcf/services/sysmon.c1634
1 files changed, 1634 insertions, 0 deletions
diff --git a/agent/tcf/services/sysmon.c b/agent/tcf/services/sysmon.c
new file mode 100644
index 00000000..6bbb32b2
--- /dev/null
+++ b/agent/tcf/services/sysmon.c
@@ -0,0 +1,1634 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+#include <config.h>
+
+#if SERVICE_SysMonitor
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <framework/protocol.h>
+#include <framework/exceptions.h>
+#include <framework/myalloc.h>
+#include <framework/json.h>
+#include <framework/context.h>
+#include <framework/errors.h>
+#include <services/sysmon.h>
+
+static const char SYS_MON[] = "SysMonitor";
+
+#if defined(_WRS_KERNEL)
+
+# error "SysMonitor service is not supported for VxWorks"
+
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+
+# error "SysMonitor service is not supported for BSD"
+
+#elif defined(__APPLE__)
+
+#include <unistd.h>
+#include <dirent.h>
+#include <pwd.h>
+#include <grp.h>
+#include <stdbool.h>
+#include <sys/sysctl.h>
+#include <mach/mach.h>
+#include <mach/task_info.h>
+#include <mach/thread_info.h>
+
+typedef struct kinfo_proc kinfo_proc;
+
+static void write_string_array(OutputStream * out, char **ap, int len) {
+ int cnt;
+
+ write_stream(out, '[');
+ for (cnt = 0; cnt < len; cnt++) {
+ if (cnt > 0) write_stream(out, ',');
+ json_write_string(out, ap[cnt]);
+ }
+ write_stream(out, ']');
+}
+
+static void free_array(char **ap, int len) {
+ int c;
+ for (c = 0; c < len; c++) {
+ free(*ap++);
+ }
+ free(ap);
+}
+
+/*
+ * Get kernel process information for all processes.
+ */
+static int get_allprocesses(kinfo_proc **kprocs, int *nprocs)
+{
+ size_t len;
+ kinfo_proc * kp;
+ int mib_name[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL};
+ int mib_len = 3;
+
+ if (sysctl(mib_name, mib_len, NULL, &len, NULL, 0) < 0) {
+ return -1;
+ }
+
+ kp = (struct kinfo_proc *)malloc(len);
+
+ if (sysctl(mib_name, mib_len, kp, &len, NULL, 0) < 0) {
+ free(kp);
+ return -1;
+ }
+
+ *kprocs = kp;
+ *nprocs = len / sizeof(kinfo_proc);
+ return 0;
+}
+
+/*
+ * Get kernel process information for a specified pid.
+ */
+static kinfo_proc *get_process(pid_t pid)
+{
+ kinfo_proc * kp;
+ int mib_name[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, 0};
+ int mib_len = 4;
+ size_t len = sizeof(kinfo_proc);
+
+ mib_name[3] = pid;
+
+ kp = malloc(len);
+ if (kp == NULL) {
+ return NULL;
+ }
+
+ if (sysctl(mib_name, mib_len, kp, &len, NULL, 0) < 0) {
+ free(kp);
+ return NULL;
+ }
+
+ return kp;
+}
+
+static void write_context(OutputStream * out, char * id, char * parent_id, kinfo_proc * p) {
+ struct passwd * pwd;
+ struct group * grp;
+
+ write_stream(out, '{');
+
+ json_write_string(out, "UID");
+ write_stream(out, ':');
+ json_write_long(out, p->kp_eproc.e_ucred.cr_uid);
+ write_stream(out, ',');
+
+ json_write_string(out, "UGID");
+ write_stream(out, ':');
+ json_write_long(out, p->kp_eproc.e_pcred.p_rgid);
+ write_stream(out, ',');
+
+ pwd = getpwuid(p->kp_eproc.e_ucred.cr_uid);
+ if (pwd != NULL) {
+ json_write_string(out, "UserName");
+ write_stream(out, ':');
+ json_write_string(out, pwd->pw_name);
+ write_stream(out, ',');
+ }
+
+ grp = getgrgid(p->kp_eproc.e_pcred.p_rgid);
+ if (grp != NULL) {
+ json_write_string(out, "GroupName");
+ write_stream(out, ':');
+ json_write_string(out, grp->gr_name);
+ write_stream(out, ',');
+ }
+
+ json_write_string(out, "File");
+ write_stream(out, ':');
+ json_write_string(out, p->kp_proc.p_comm);
+ write_stream(out, ',');
+
+ json_write_string(out, "PID");
+ write_stream(out, ':');
+ json_write_long(out, p->kp_proc.p_pid);
+ write_stream(out, ',');
+
+ json_write_string(out, "State");
+ write_stream(out, ':');
+ write_stream(out, '"');
+ json_write_char(out, p->kp_proc.p_stat);
+ write_stream(out, '"');
+ write_stream(out, ',');
+
+ if (p->kp_eproc.e_ppid > 0) {
+ json_write_string(out, "PPID");
+ write_stream(out, ':');
+ json_write_long(out, p->kp_eproc.e_ppid);
+ write_stream(out, ',');
+ }
+
+ json_write_string(out, "PGRP");
+ write_stream(out, ':');
+ json_write_long(out, p->kp_eproc.e_pgid);
+ write_stream(out, ',');
+
+ if (p->kp_eproc.e_tpgid > 0) {
+ json_write_string(out, "TGID");
+ write_stream(out, ':');
+ json_write_long(out, p->kp_eproc.e_tpgid);
+ write_stream(out, ',');
+ }
+
+ json_write_string(out, "Flags");
+ write_stream(out, ':');
+ json_write_long(out, p->kp_proc.p_flag);
+ write_stream(out, ',');
+
+ json_write_string(out, "UTime");
+ write_stream(out, ':');
+ json_write_uint64(out, p->kp_proc.p_uticks);
+ write_stream(out, ',');
+
+ json_write_string(out, "STime");
+ write_stream(out, ':');
+ json_write_uint64(out, p->kp_proc.p_sticks);
+ write_stream(out, ',');
+
+ json_write_string(out, "Priority");
+ write_stream(out, ':');
+ json_write_long(out, (long)p->kp_proc.p_priority);
+ write_stream(out, ',');
+
+ if (p->kp_proc.p_nice != 0) {
+ json_write_string(out, "Nice");
+ write_stream(out, ':');
+ json_write_long(out, (long)p->kp_proc.p_nice);
+ write_stream(out, ',');
+ }
+
+ if (parent_id != NULL && parent_id[0] != 0) {
+ json_write_string(out, "ParentID");
+ write_stream(out, ':');
+ json_write_string(out, parent_id);
+ write_stream(out, ',');
+ }
+
+ json_write_string(out, "ID");
+ write_stream(out, ':');
+ json_write_string(out, id);
+
+ write_stream(out, '}');
+}
+
+static void command_get_context(char * token, Channel * c) {
+ char id[256];
+ pid_t pid = 0;
+ pid_t parent = 0;
+ int err = 0;
+ kinfo_proc * p;
+
+ json_read_string(&c->inp, id, sizeof(id));
+ if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX);
+ if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+ write_stringz(&c->out, "R");
+ write_stringz(&c->out, token);
+
+ pid = id2pid(id, &parent);
+ p = get_process(pid);
+ if (p == NULL) err = errno;
+
+ write_errno(&c->out, err);
+
+ if (err == 0 && pid != 0) {
+ char *parent_id;
+ asprintf(&parent_id, "%d", parent);
+ write_context(&c->out, id, parent == 0 ? NULL : parent_id, p);
+ write_stream(&c->out, 0);
+ free(parent_id);
+ }
+ else {
+ write_stringz(&c->out, "null");
+ }
+
+ write_stream(&c->out, MARKER_EOM);
+}
+
+static void command_get_children(char * token, Channel * c) {
+ int err = 0;
+ char id[256];
+ pid_t pid = 0;
+ pid_t parent = 0;
+
+ json_read_string(&c->inp, id, sizeof(id));
+ if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX);
+ if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+ write_stringz(&c->out, "R");
+ write_stringz(&c->out, token);
+
+ pid = id2pid(id, &parent);
+
+ if (parent != 0) {
+ write_errno(&c->out, 0);
+ write_stringz(&c->out, "null");
+ }
+ else {
+ if (pid == 0) {
+ int np;
+ int i;
+ int n;
+ kinfo_proc * p;
+
+ if (get_allprocesses(&p, &np) < 0) {
+ write_errno(&c->out, errno);
+ write_stringz(&c->out, "null");
+ }
+ else {
+ write_errno(&c->out, 0);
+ write_stream(&c->out, '[');
+ for (n = 0, i = 0; i < np; i++) {
+ if (p->kp_proc.p_pid != 0) {
+ if (n > 0) write_stream(&c->out, ',');
+ json_write_string(&c->out, pid2id(p->kp_proc.p_pid, 0));
+ n++;
+ }
+ p++;
+ }
+ write_stream(&c->out, ']');
+ write_stream(&c->out, 0);
+ }
+ }
+ else {
+ kinfo_proc * p;
+
+ p = get_process(pid);
+ if (p == NULL) {
+ write_errno(&c->out, errno);
+ write_stringz(&c->out, "null");
+ }
+ else {
+ task_port_t task;
+
+ if (task_for_pid(mach_task_self(), pid, &task) != KERN_SUCCESS) {
+ /*
+ * User is probably not in procmod group
+ */
+ write_errno(&c->out, 0);
+ write_stringz(&c->out, "[]");
+ }
+ else {
+ unsigned int thread_count;
+ thread_port_array_t thread_list;
+
+ if (task_threads(task, &thread_list, &thread_count) != KERN_SUCCESS) {
+ write_errno(&c->out, errno);
+ write_stringz(&c->out, "null");
+ }
+ else {
+ int cnt;
+ write_errno(&c->out, 0);
+ write_stream(&c->out, '[');
+ for (cnt = 0; cnt < thread_count; cnt++) {
+ if (cnt > 0) write_stream(&c->out, ',');
+ json_write_string(&c->out, pid2id(thread_list[cnt], pid));
+ }
+ write_stream(&c->out, ']');
+ write_stream(&c->out, 0);
+ }
+ }
+ }
+ }
+ }
+
+ write_stream(&c->out, MARKER_EOM);
+}
+
+static void command_get_command_line(char * token, Channel * c) {
+ int err;
+ char id[256];
+ pid_t pid;
+ pid_t parent;
+ kinfo_proc * p;
+
+ json_read_string(&c->inp, id, sizeof(id));
+ if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX);
+ if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+ pid = id2pid(id, &parent);
+ if (pid != 0 && parent == 0) {
+ p = get_process(pid);
+ if (p == NULL) err = errno;
+ }
+ else {
+ err = ERR_INV_CONTEXT;
+ }
+
+ write_stringz(&c->out, "R");
+ write_stringz(&c->out, token);
+
+ write_errno(&c->out, err);
+
+ if (err != 0) {
+ write_stringz(&c->out, "null");
+ } else {
+ write_stringz(&c->out, p->kp_proc.p_comm);
+ }
+
+ write_stream(&c->out, MARKER_EOM);
+}
+
+static void command_get_environment(char * token, Channel * c) {
+ char id[256];
+
+ json_read_string(&c->inp, id, sizeof(id));
+ if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX);
+ if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+ write_stringz(&c->out, "R");
+ write_stringz(&c->out, token);
+ write_errno(&c->out, 0);
+ write_stringz(&c->out, "[]");
+
+ write_stream(&c->out, MARKER_EOM);
+}
+
+#elif defined(WIN32)
+
+#include <windows.h>
+#include <wchar.h>
+
+typedef struct _UNICODE_STRING {
+ USHORT Length;
+ USHORT MaximumLength;
+ PWSTR Buffer;
+} UNICODE_STRING;
+
+typedef enum _PROCESSINFOCLASS {
+ ProcessBasicInformation = 0,
+ ProcessWow64Information = 26
+} PROCESSINFOCLASS;
+
+typedef struct _RTL_DRIVE_LETTER_CURDIR {
+ USHORT Flags;
+ USHORT Length;
+ ULONG TimeStamp;
+ UNICODE_STRING DosPath;
+} RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR;
+
+typedef struct _RTL_USER_PROCESS_PARAMETERS {
+ ULONG MaximumLength;
+ ULONG Length;
+ ULONG Flags;
+ ULONG DebugFlags;
+ PVOID ConsoleHandle;
+ ULONG ConsoleFlags;
+ HANDLE StdInputHandle;
+ HANDLE StdOutputHandle;
+ HANDLE StdErrorHandle;
+ UNICODE_STRING CurrentDirectoryPath;
+ HANDLE CurrentDirectoryHandle;
+ UNICODE_STRING DllPath;
+ UNICODE_STRING ImagePathName;
+ UNICODE_STRING CommandLine;
+ PVOID Environment;
+ ULONG StartingPositionLeft;
+ ULONG StartingPositionTop;
+ ULONG Width;
+ ULONG Height;
+ ULONG CharWidth;
+ ULONG CharHeight;
+ ULONG ConsoleTextAttributes;
+ ULONG WindowFlags;
+ ULONG ShowWindowFlags;
+ UNICODE_STRING WindowTitle;
+ UNICODE_STRING DesktopName;
+ UNICODE_STRING ShellInfo;
+ UNICODE_STRING RuntimeData;
+ RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20];
+} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;
+
+typedef struct _PEB_LDR_DATA * PPEB_LDR_DATA;
+typedef struct _PEBLOCKROUTINE * PPEBLOCKROUTINE;
+typedef struct _PEB_FREE_BLOCK * PPEB_FREE_BLOCK;
+typedef PVOID * PPVOID;
+
+typedef struct _PROCESS_ENVIRONMENT_BLOCK {
+ BOOLEAN InheritedAddressSpace;
+ BOOLEAN ReadImageFileExecOptions;
+ BOOLEAN BeingDebugged;
+ BOOLEAN Spare;
+ HANDLE Mutant;
+ PVOID ImageBaseAddress;
+ PPEB_LDR_DATA LoaderData;
+ PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
+ PVOID SubSystemData;
+ PVOID ProcessHeap;
+ PVOID FastPebLock;
+ PPEBLOCKROUTINE FastPebLockRoutine;
+ PPEBLOCKROUTINE FastPebUnlockRoutine;
+ ULONG EnvironmentUpdateCount;
+ PPVOID KernelCallbackTable;
+ PVOID EventLogSection;
+ PVOID EventLog;
+ PPEB_FREE_BLOCK FreeList;
+ ULONG TlsExpansionCounter;
+ PVOID TlsBitmap;
+ ULONG TlsBitmapBits[0x2];
+ PVOID ReadOnlySharedMemoryBase;
+ PVOID ReadOnlySharedMemoryHeap;
+ PPVOID ReadOnlyStaticServerData;
+ PVOID AnsiCodePageData;
+ PVOID OemCodePageData;
+ PVOID UnicodeCaseTableData;
+ ULONG NumberOfProcessors;
+ ULONG NtGlobalFlag;
+ BYTE Spare2[0x4];
+ LARGE_INTEGER CriticalSectionTimeout;
+ ULONG HeapSegmentReserve;
+ ULONG HeapSegmentCommit;
+ ULONG HeapDeCommitTotalFreeThreshold;
+ ULONG HeapDeCommitFreeBlockThreshold;
+ ULONG NumberOfHeaps;
+ ULONG MaximumNumberOfHeaps;
+ PPVOID *ProcessHeaps;
+ PVOID GdiSharedHandleTable;
+ PVOID ProcessStarterHelper;
+ PVOID GdiDCAttributeList;
+ PVOID LoaderLock;
+ ULONG OSMajorVersion;
+ ULONG OSMinorVersion;
+ ULONG OSBuildNumber;
+ ULONG OSPlatformId;
+ ULONG ImageSubSystem;
+ ULONG ImageSubSystemMajorVersion;
+ ULONG ImageSubSystemMinorVersion;
+ ULONG GdiHandleBuffer[0x22];
+ ULONG PostProcessInitRoutine;
+ ULONG TlsExpansionBitmap;
+ BYTE TlsExpansionBitmapBits[0x80];
+ ULONG SessionId;
+} loc_PEB, *loc_PPEB;
+
+typedef struct loc_PROCESS_BASIC_INFORMATION {
+ LONG ExitStatus;
+ loc_PPEB PebBaseAddress;
+ ULONG_PTR AffinityMask;
+ LONG BasePriority;
+ ULONG_PTR UniqueProcessId;
+ ULONG_PTR InheritedFromUniqueProcessId;
+} PBI;
+
+static PBI pbi;
+static loc_PEB peb;
+static RTL_USER_PROCESS_PARAMETERS upa;
+
+static int get_process_info(HANDLE prs) {
+ static LONG (NTAPI * QueryInformationProcessProc)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG) = NULL;
+ SIZE_T len = 0;
+
+ memset(&pbi, 0, sizeof(pbi));
+ memset(&peb, 0, sizeof(peb));
+ memset(&upa, 0, sizeof(upa));
+
+ if (QueryInformationProcessProc == NULL) {
+ *(FARPROC *)&QueryInformationProcessProc = GetProcAddress(GetModuleHandle("NTDLL.DLL"), "ZwQueryInformationProcess");
+ if (QueryInformationProcessProc == NULL) {
+ set_win32_errno(GetLastError());
+ return -1;
+ }
+ }
+ if (QueryInformationProcessProc(prs, ProcessBasicInformation, &pbi, sizeof(pbi), &len) < 0) {
+ set_win32_errno(GetLastError());
+ return -1;
+ }
+
+ if (pbi.PebBaseAddress != NULL) {
+ if (ReadProcessMemory(prs, (LPCVOID)pbi.PebBaseAddress, &peb, sizeof(peb), &len) == 0) {
+ set_win32_errno(GetLastError());
+ return -1;
+ }
+
+ if (peb.ProcessParameters != NULL) {
+ if (ReadProcessMemory(prs, (LPCVOID)peb.ProcessParameters, &upa, sizeof(upa), &len) == 0) {
+ set_win32_errno(GetLastError());
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int write_unicode_string(OutputStream * out, HANDLE prs, UNICODE_STRING str, const char * name) {
+ if (str.Buffer != NULL) {
+ wchar_t w_fnm[FILE_PATH_SIZE];
+ SIZE_T buff_size = str.Length;
+ SIZE_T read_size = 0;
+ memset(w_fnm, 0, sizeof(w_fnm));
+ if (buff_size > sizeof(w_fnm)) buff_size = sizeof(w_fnm);
+ if (ReadProcessMemory(prs, (LPCVOID)str.Buffer, w_fnm, buff_size, &read_size)) {
+ char a_fnm[FILE_PATH_SIZE * 4];
+ DWORD k = wcslen(w_fnm);
+ int n = WideCharToMultiByte(CP_UTF8, 0, w_fnm, k, a_fnm, sizeof(a_fnm), NULL, NULL);
+ a_fnm[n] = 0;
+ write_stream(out, ',');
+ json_write_string(out, name);
+ write_stream(out, ':');
+ json_write_string(out, a_fnm);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void write_time(OutputStream * out, FILETIME tm, int64_t base, const char * name) {
+ int64_t n = (((int64_t)tm.dwLowDateTime | ((int64_t)tm.dwHighDateTime << 32)) - base) / 10000;
+
+ write_stream(out, ',');
+
+ json_write_string(out, name);
+ write_stream(out, ':');
+ if (n < 0) n = 0;
+ json_write_int64(out, n);
+}
+
+static void write_process_context(OutputStream * out, char * id, pid_t pid, HANDLE prs) {
+ write_stream(out, '{');
+
+ json_write_string(out, "ID");
+ write_stream(out, ':');
+ json_write_string(out, id);
+
+ write_stream(out, ',');
+
+ json_write_string(out, "PID");
+ write_stream(out, ':');
+ json_write_ulong(out, pid);
+
+ write_unicode_string(out, prs, upa.ImagePathName, "File");
+ write_unicode_string(out, prs, upa.CurrentDirectoryPath, "CWD");
+
+ {
+ FILETIME c_time, e_time, k_time, u_time;
+ if (GetProcessTimes(prs, &c_time, &e_time, &k_time, &u_time)) {
+ static int64_t system_start_time = 0; /* In FILETIME format: 100-nanosecond intervals since January 1, 1601 (UTC). */
+ if (system_start_time == 0) {
+ HKEY key;
+ if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+ L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management",
+ 0, KEY_READ, &key) == ERROR_SUCCESS) {
+ wchar_t buf[FILE_PATH_SIZE];
+ DWORD size = sizeof(buf);
+ memset(buf, 0, sizeof(buf));
+ if (RegQueryValueExW(key,
+ L"PagingFiles",
+ NULL, NULL, (LPBYTE)buf, &size) == ERROR_SUCCESS) {
+ WIN32_FIND_DATAW data;
+ HANDLE h = INVALID_HANDLE_VALUE;
+ int n = 0;
+ while (n < FILE_PATH_SIZE && buf[n] != 0) n++;
+ while (n > 0 && buf[n - 1] != ' ') n--;
+ while (n > 0 && buf[n - 1] == ' ') n--;
+ while (n > 0 && buf[n - 1] != ' ') n--;
+ while (n > 0 && buf[n - 1] == ' ') n--;
+ buf[n] = 0;
+ h = FindFirstFileW(buf, &data);
+ if (h != INVALID_HANDLE_VALUE) {
+ system_start_time = (int64_t)data.ftLastWriteTime.dwLowDateTime | ((int64_t)data.ftLastWriteTime.dwHighDateTime << 32);
+ FindClose(h);
+ }
+ }
+ RegCloseKey(key);
+ }
+ }
+ if (system_start_time == 0) {
+ SYSTEMTIME st;
+ FILETIME ft;
+ GetSystemTime(&st);
+ if (SystemTimeToFileTime(&st, &ft)) {
+ system_start_time = (int64_t)ft.dwLowDateTime | ((int64_t)ft.dwHighDateTime << 32);
+ system_start_time -= (int64_t)GetTickCount() * 10000; /* Note: GetTickCount() is valid only first 49 days */
+ }
+ }
+ if (system_start_time != 0) {
+ write_time(out, c_time, system_start_time, "StartTime");
+ }
+ write_time(out, k_time, 0, "STime");
+ write_time(out, u_time, 0, "UTime");
+ }
+ }
+
+ write_stream(out, '}');
+}
+
+static void command_get_context(char * token, Channel * c) {
+ char id[256];
+ pid_t pid = 0;
+ pid_t parent = 0;
+ int err = 0;
+
+ json_read_string(&c->inp, id, sizeof(id));
+ if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX);
+ if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+ write_stringz(&c->out, "R");
+ write_stringz(&c->out, token);
+
+ pid = id2pid(id, &parent);
+ if (parent != 0) {
+ write_errno(&c->out, err);
+ write_stringz(&c->out, "null");
+ }
+ else if (pid != 0) {
+ HANDLE prs = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
+ if (prs == NULL) err = set_win32_errno(GetLastError());
+ if (err == 0 && get_process_info(prs) < 0) err = errno;
+ write_errno(&c->out, err);
+ if (err == 0) {
+ write_process_context(&c->out, id, pid, prs);
+ write_stream(&c->out, 0);
+ }
+ else {
+ write_stringz(&c->out, "null");
+ }
+ if (prs != NULL) CloseHandle(prs);
+ }
+ else {
+ write_errno(&c->out, err);
+ write_stringz(&c->out, "null");
+ }
+
+ write_stream(&c->out, MARKER_EOM);
+}
+
+static void command_get_children(char * token, Channel * c) {
+ char id[256];
+ pid_t pid = 0;
+ pid_t parent = 0;
+ int err = 0;
+
+ json_read_string(&c->inp, id, sizeof(id));
+ if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX);
+ if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+ write_stringz(&c->out, "R");
+ write_stringz(&c->out, token);
+
+ pid = id2pid(id, &parent);
+
+ if (parent != 0) {
+ /* Children of a thread: none */
+ write_errno(&c->out, 0);
+ write_stringz(&c->out, "null");
+ }
+ else if (pid != 0) {
+ /* Children of a process: threads */
+ /* TODO: enumerate threads */
+ write_errno(&c->out, 0);
+ write_stringz(&c->out, "null");
+ }
+ else {
+ /* Children of the root: processes */
+ static BOOL (WINAPI * EnumProcessesProc)(DWORD *, DWORD, DWORD *) = NULL;
+ HANDLE heap = GetProcessHeap();
+ DWORD * prs_ids = NULL;
+ int prs_cnt = 0;
+ if (EnumProcessesProc == NULL) {
+ HINSTANCE psapi = LoadLibrary("PSAPI.DLL");
+ if (psapi == NULL) {
+ err = set_win32_errno(GetLastError());
+ }
+ else {
+ *(FARPROC *)&EnumProcessesProc = GetProcAddress(psapi, "EnumProcesses");
+ if (EnumProcessesProc == NULL) err = set_win32_errno(GetLastError());
+ }
+ }
+ if (err == 0) {
+ DWORD size_allocated = 128;
+ DWORD size_returned = 0;
+ do {
+ size_allocated *= 2;
+ if (prs_ids != NULL) HeapFree(heap, 0, prs_ids);
+ prs_ids = (DWORD *)HeapAlloc(heap, 0, size_allocated);
+ if (prs_ids == NULL) {
+ err = set_win32_errno(GetLastError());
+ break;
+ }
+ if (!EnumProcessesProc(prs_ids, size_allocated, &size_returned)) {
+ err = set_win32_errno(GetLastError());
+ break;
+ }
+ }
+ while (size_returned == size_allocated);
+ prs_cnt = size_returned / sizeof(DWORD);
+ }
+ write_errno(&c->out, err);
+ if (err == 0) {
+ int pos = 0;
+ int cnt = 0;
+ write_stream(&c->out, '[');
+ for (pos = 0; pos < prs_cnt; pos++) {
+ if (prs_ids[pos] == 0) continue;
+ if (cnt > 0) write_stream(&c->out, ',');
+ json_write_string(&c->out, pid2id(prs_ids[pos], 0));
+ cnt++;
+ }
+ write_stream(&c->out, ']');
+ write_stream(&c->out, 0);
+ }
+ else {
+ write_stringz(&c->out, "null");
+ }
+ if (prs_ids != NULL) HeapFree(heap, 0, prs_ids);
+ }
+
+ write_stream(&c->out, MARKER_EOM);
+}
+
+static void command_get_command_line(char * token, Channel * c) {
+ char id[256];
+ pid_t pid = 0;
+ pid_t parent = 0;
+ int err = 0;
+ HANDLE prs = NULL;
+ wchar_t * cmd = NULL;
+
+ json_read_string(&c->inp, id, sizeof(id));
+ if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX);
+ if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+ write_stringz(&c->out, "R");
+ write_stringz(&c->out, token);
+
+ pid = id2pid(id, &parent);
+ if (pid != 0 && parent == 0) {
+ prs = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
+ if (prs == NULL) err = set_win32_errno(GetLastError());
+ }
+ else {
+ err = ERR_INV_CONTEXT;
+ }
+ if (err == 0 && get_process_info(prs) < 0) err = errno;
+ if (err == 0 && upa.CommandLine.Buffer != NULL) {
+ SIZE_T cmd_size = upa.CommandLine.Length;
+ SIZE_T read_size = 0;
+ cmd = (wchar_t *)loc_alloc(cmd_size);
+ if (ReadProcessMemory(prs, (LPCVOID)upa.CommandLine.Buffer, cmd, cmd_size, &read_size) == 0) {
+ err = set_win32_errno(GetLastError());
+ }
+ }
+ if (prs != NULL) CloseHandle(prs);
+
+ write_errno(&c->out, err);
+
+ if (err == 0 && cmd != NULL) {
+ wchar_t * p = cmd;
+ wchar_t * e = cmd + upa.CommandLine.Length / sizeof(wchar_t);
+ int cnt = 0;
+ write_stream(&c->out, '[');
+ while (p < e && *p) {
+ int quotation = 0;
+ if (*p == ' ') { p++; continue; }
+ if (*p == '\t') { p++; continue; }
+ if (cnt > 0) write_stream(&c->out, ',');
+ write_stream(&c->out, '"');
+ while (p < e && *p) {
+ char buf[0x100];
+ unsigned k = 0;
+ while (p < e && *p && k < sizeof(buf) / 4) {
+ if (*p == '"' || *p == '\\' || *p == ' ' || *p == '\t') break;
+ p++;
+ k++;
+ }
+ if (k > 0) {
+ int i = 0;
+ int n = WideCharToMultiByte(CP_UTF8, 0, p - k, k, buf, sizeof(buf), NULL, NULL);
+ while (i < n) json_write_char(&c->out, buf[i++]);
+ if (p == e || *p == 0) break;
+ }
+ if (*p == '"') {
+ quotation = !quotation;
+ p++;
+ }
+ else if (*p == '\\') {
+ p++;
+ if (p == e) {
+ json_write_char(&c->out, '\\');
+ }
+ else if (*p == '"') {
+ json_write_char(&c->out, '"');
+ p++;
+ }
+ else if (*p == '\\') {
+ json_write_char(&c->out, '\\');
+ p++;
+ }
+ else {
+ json_write_char(&c->out, '\\');
+ }
+ }
+ else if (*p == ' ' || *p == '\t') {
+ p++;
+ if (!quotation) break;
+ json_write_char(&c->out, ' ');
+ }
+ else {
+ assert(k > 0);
+ }
+ }
+ write_stream(&c->out, '"');
+ cnt++;
+ }
+ write_stream(&c->out, ']');
+ write_stream(&c->out, 0);
+ }
+ else {
+ write_stringz(&c->out, "null");
+ }
+
+ write_stream(&c->out, MARKER_EOM);
+ loc_free(cmd);
+}
+
+static void command_get_environment(char * token, Channel * c) {
+ char id[256];
+ pid_t pid = 0;
+ pid_t parent = 0;
+ int err = 0;
+ HANDLE prs = NULL;
+ wchar_t * env = NULL;
+
+ json_read_string(&c->inp, id, sizeof(id));
+ if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX);
+ if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+ write_stringz(&c->out, "R");
+ write_stringz(&c->out, token);
+
+ pid = id2pid(id, &parent);
+ if (pid != 0 && parent == 0) {
+ prs = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
+ if (prs == NULL) err = set_win32_errno(GetLastError());
+ }
+ else {
+ err = ERR_INV_CONTEXT;
+ }
+ if (err == 0 && get_process_info(prs) < 0) err = errno;
+ if (err == 0 && upa.Environment != NULL) {
+ wchar_t buf[0x100];
+ SIZE_T buf_pos = 0;
+ SIZE_T buf_len = 0;
+ SIZE_T env_size = 0;
+ int cnt = 0;
+
+ for (;;) {
+ if (buf_pos >= buf_len) {
+ SIZE_T len = 0;
+ if (ReadProcessMemory(prs, (LPCVOID)((SIZE_T)upa.Environment + env_size), buf, sizeof(buf), &len) == 0) {
+ err = set_win32_errno(GetLastError());
+ break;
+ }
+ buf_pos = 0;
+ buf_len = len / sizeof(wchar_t);
+ }
+ env_size += sizeof(wchar_t);
+ if (buf[buf_pos++] == 0) {
+ cnt++;
+ if (cnt == 2) break;
+ }
+ else {
+ cnt = 0;
+ }
+ }
+
+ if (err == 0) {
+ env = (wchar_t *)loc_alloc(env_size);
+ if (ReadProcessMemory(prs, (LPCVOID)upa.Environment, env, env_size, &buf_len) == 0) {
+ err = set_win32_errno(GetLastError());
+ }
+ }
+ }
+ if (prs != NULL) CloseHandle(prs);
+
+ write_errno(&c->out, err);
+
+ if (err == 0 && env != NULL) {
+ wchar_t * p = env;
+ int cnt = 0;
+ write_stream(&c->out, '[');
+ while (*p) {
+ if (cnt > 0) write_stream(&c->out, ',');
+ write_stream(&c->out, '"');
+ while (*p) {
+ char buf[0x100];
+ unsigned k = 0;
+ int n = 0, i = 0;
+ while (*p && k < sizeof(buf) / 4) { p++; k++; }
+ n = WideCharToMultiByte(CP_UTF8, 0, p - k, k, buf, sizeof(buf), NULL, NULL);
+ while (i < n) json_write_char(&c->out, buf[i++]);
+ }
+ p++;
+ write_stream(&c->out, '"');
+ cnt++;
+ }
+ write_stream(&c->out, ']');
+ write_stream(&c->out, 0);
+ }
+ else {
+ write_stringz(&c->out, "null");
+ }
+
+ write_stream(&c->out, MARKER_EOM);
+ loc_free(env);
+}
+
+#else
+
+#include <unistd.h>
+#include <dirent.h>
+#include <pwd.h>
+#include <grp.h>
+#include <linux/param.h>
+
+#define BUF_EOF (-1)
+
+static char buf[1024];
+static int buf_fd = -1;
+static int buf_pos = 0;
+static int buf_len = 0;
+static int buf_ch = 0;
+
+static void next_ch(void) {
+ while (buf_len >= 0 && buf_pos >= buf_len) {
+ buf_pos = 0;
+ buf_len = read(buf_fd, buf, sizeof(buf));
+ if (buf_len == 0) buf_len = -1;
+ }
+ if (buf_len < 0) {
+ buf_ch = BUF_EOF;
+ }
+ else {
+ buf_ch = (unsigned char)buf[buf_pos++];
+ }
+}
+
+static void first_ch(int fd) {
+ buf_fd = fd;
+ buf_pos = 0;
+ buf_len = 0;
+ next_ch();
+}
+
+static void write_string_array(OutputStream * out, int f) {
+ int cnt = 0;
+ first_ch(f);
+ write_stream(out, '[');
+ while (buf_ch != BUF_EOF && buf_ch != 0) {
+ if (cnt > 0) write_stream(out, ',');
+ write_stream(out, '"');
+ do {
+ json_write_char(out, buf_ch);
+ next_ch();
+ }
+ while (buf_ch != BUF_EOF && buf_ch != 0);
+ next_ch();
+ write_stream(out, '"');
+ cnt++;
+ }
+ write_stream(out, ']');
+}
+
+static void write_context(OutputStream * out, char * id, char * parent_id, char * dir) {
+ char fnm[FILE_PATH_SIZE + 1];
+ int sz;
+ int f;
+
+ write_stream(out, '{');
+
+ if (chdir(dir) >= 0) {
+ if ((sz = readlink("cwd", fnm, FILE_PATH_SIZE)) > 0) {
+ fnm[sz] = 0;
+ json_write_string(out, "CWD");
+ write_stream(out, ':');
+ json_write_string(out, fnm);
+ write_stream(out, ',');
+ }
+
+ if ((sz = readlink("root", fnm, FILE_PATH_SIZE)) > 0) {
+ fnm[sz] = 0;
+ json_write_string(out, "Root");
+ write_stream(out, ':');
+ json_write_string(out, fnm);
+ write_stream(out, ',');
+ }
+
+ f = open("stat", O_RDONLY);
+ if (f >= 0) {
+ struct stat st;
+ if (fstat(f, &st) == 0) {
+ struct passwd * pwd;
+ struct group * grp;
+
+ json_write_string(out, "UID");
+ write_stream(out, ':');
+ json_write_long(out, st.st_uid);
+ write_stream(out, ',');
+
+ json_write_string(out, "UGID");
+ write_stream(out, ':');
+ json_write_long(out, st.st_gid);
+ write_stream(out, ',');
+
+ pwd = getpwuid(st.st_uid);
+ if (pwd != NULL) {
+ json_write_string(out, "UserName");
+ write_stream(out, ':');
+ json_write_string(out, pwd->pw_name);
+ write_stream(out, ',');
+ }
+
+ grp = getgrgid(st.st_gid);
+ if (grp != NULL) {
+ json_write_string(out, "GroupName");
+ write_stream(out, ':');
+ json_write_string(out, grp->gr_name);
+ write_stream(out, ',');
+ }
+ }
+
+ memset(buf, 0, sizeof(buf));
+ if ((sz = read(f, buf, sizeof(buf))) > 0) {
+ char * str = buf;
+ int pid = 0; /* The process ID. */
+ char * comm = fnm; /* The filename of the executable, in parentheses. This is visible */
+ /* whether or not the executable is swapped out. */
+ char state = 0; /* One character from the string "RSDZTW" where R is running, S is */
+ /* sleeping in an interruptible wait, D is waiting in uninterruptible */
+ /* disk sleep, Z is zombie, T is traced or stopped (on a signal), and W */
+ /* is paging. */
+ int ppid = 0; /* The PID of the parent. */
+ int pgrp = 0; /* The process group ID of the process. */
+ int session = 0; /* The session ID of the process. */
+ int tty_nr = 0; /* The tty the process uses. */
+ int tpgid = 0; /* The process group ID of the process which currently owns the tty that */
+ /* the process is connected to. */
+ unsigned long flags = 0; /* The kernel flags word of the process. For bit meanings, see the PF_* */
+ /* defines in <linux/sched.h>. Details depend on the kernel version. */
+ unsigned long minflt = 0; /* The number of minor faults the process has made which have not */
+ /* required loading a memory page from disk. */
+ unsigned long cminflt = 0; /* The number of minor faults that the process's waited-for children */
+ /* have made. */
+ unsigned long majflt = 0; /* The number of major faults the process has made which have required */
+ /* loading a memory page from disk. */
+ unsigned long cmajflt = 0; /* The number of major faults that the process's waited-for children */
+ /* have made. */
+ unsigned long utime = 0; /* The number of jiffies that this process has been scheduled in user */
+ /* mode. */
+ unsigned long stime = 0; /* The number of jiffies that this process has been scheduled in kernel */
+ /* mode. */
+ long cutime = 0; /* The number of jiffies that this process's waited-for children have */
+ /* been scheduled in user mode. (See also times(2).) */
+ long cstime = 0; /* The number of jiffies that this process's waited-for children have */
+ /* been scheduled in kernel mode. */
+ long priority = 0; /* The standard nice value, plus fifteen. The value is never negative */
+ /* in the kernel. */
+ long nice = 0; /* The nice value ranges from 19 (nicest) to -19 (not nice to others). */
+ long dummy = 0; /* This value is hard coded to 0 as a placeholder for a removed field. */
+ long itrealvalue = 0; /* The time in jiffies before the next SIGALRM is sent to the process */
+ /* due to an interval timer. */
+ unsigned long starttime = 0;/* The time in jiffies the process started after system boot. */
+ unsigned long vsize = 0; /* Virtual memory size in bytes. */
+ long rss = 0; /* Resident Set Size: number of pages the process has in real memory, */
+ /* minus 3 for administrative purposes. This is just the pages which */
+ /* count towards text, data, or stack space. This does not include */
+ /* pages which have not been demand-loaded in, or which are swapped out. */
+ unsigned long rlim = 0; /* Current limit in bytes on the rss of the process (usually 4294967295 */
+ /* on i386). */
+ unsigned long startcode = 0;/* The address above which program text can run. */
+ unsigned long endcode = 0; /* The address below which program text can run. */
+ unsigned long startstack =0;/* The address of the start of the stack. */
+ unsigned long kstkesp = 0; /* The current value of esp (stack pointer), as found in the kernel */
+ /* stack page for the process. */
+ unsigned long kstkeip = 0; /* The current EIP (instruction pointer). */
+ unsigned long signal = 0; /* The bitmap of pending signals. */
+ unsigned long blocked = 0; /* The bitmap of blocked signals. */
+ unsigned long sigignore = 0;/* The bitmap of ignored signals. */
+ unsigned long sigcatch = 0; /* The bitmap of caught signals. */
+ unsigned long wchan = 0; /* This is the "channel" in which the process is waiting. It is the */
+ /* address of a system call, and can be looked up in a namelist if you */
+ /* need a textual name. (If you have an up-to-date /etc/psdatabase, */
+ /* then try ps -l to see the WCHAN field in action.) */
+ unsigned long nswap = 0; /* Number of pages swapped (not maintained). */
+ unsigned long cnswap = 0; /* Cumulative nswap for child processes (not maintained). */
+ int exit_signal = 0; /* Signal to be sent to parent when we die. */
+ int processor = 0; /* CPU number last executed on. */
+ unsigned long rt_priority=0;/* Real-time scheduling priority (see sched_setscheduler(2)). */
+ unsigned long policy = 0; /* Scheduling policy (see sched_setscheduler(2)). */
+
+ assert(sz < (int)sizeof(buf));
+ buf[sz] = 0;
+
+ pid = (int)strtol(str, &str, 10);
+ while (*str == ' ') str++;
+ if (*str == '(') str++;
+ sz = 0;
+ while (*str && *str != ')') comm[sz++] = *str++;
+ comm[sz] = 0;
+ if (*str == ')') str++;
+ while (*str == ' ') str++;
+
+ sscanf(str,
+ "%c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu",
+ &state, &ppid, &pgrp, &session, &tty_nr, &tpgid, &flags,
+ &minflt, &cminflt, &majflt, &cmajflt, &utime, &stime, &cutime, &cstime,
+ &priority, &nice, &dummy, &itrealvalue, &starttime, &vsize, &rss, &rlim,
+ &startcode, &endcode, &startstack, &kstkesp, &kstkeip, &signal, &blocked, &sigignore, &sigcatch,
+ &wchan, &nswap, &cnswap, &exit_signal, &processor, &rt_priority, &policy);
+
+ json_write_string(out, "PID");
+ write_stream(out, ':');
+ json_write_long(out, pid);
+ write_stream(out, ',');
+
+ json_write_string(out, "File");
+ write_stream(out, ':');
+ json_write_string(out, comm);
+ write_stream(out, ',');
+
+ json_write_string(out, "State");
+ write_stream(out, ':');
+ write_stream(out, '"');
+ json_write_char(out, state);
+ write_stream(out, '"');
+ write_stream(out, ',');
+
+ if (ppid > 0) {
+ json_write_string(out, "PPID");
+ write_stream(out, ':');
+ json_write_long(out, ppid);
+ write_stream(out, ',');
+ }
+
+ json_write_string(out, "PGRP");
+ write_stream(out, ':');
+ json_write_long(out, pgrp);
+ write_stream(out, ',');
+
+ json_write_string(out, "Session");
+ write_stream(out, ':');
+ json_write_long(out, session);
+ write_stream(out, ',');
+
+ if (tty_nr > 0) {
+ json_write_string(out, "TTY");
+ write_stream(out, ':');
+ json_write_long(out, tty_nr);
+ write_stream(out, ',');
+ }
+
+ if (tpgid > 0) {
+ json_write_string(out, "TGID");
+ write_stream(out, ':');
+ json_write_long(out, tpgid);
+ write_stream(out, ',');
+ }
+
+ json_write_string(out, "Flags");
+ write_stream(out, ':');
+ json_write_ulong(out, flags);
+ write_stream(out, ',');
+
+ json_write_string(out, "MinFlt");
+ write_stream(out, ':');
+ json_write_ulong(out, minflt);
+ write_stream(out, ',');
+
+ json_write_string(out, "CMinFlt");
+ write_stream(out, ':');
+ json_write_ulong(out, cminflt);
+ write_stream(out, ',');
+
+ json_write_string(out, "MajFlt");
+ write_stream(out, ':');
+ json_write_ulong(out, majflt);
+ write_stream(out, ',');
+
+ json_write_string(out, "CMajFlt");
+ write_stream(out, ':');
+ json_write_ulong(out, cmajflt);
+ write_stream(out, ',');
+
+ json_write_string(out, "UTime");
+ write_stream(out, ':');
+ json_write_uint64(out, (uint64_t)utime * 1000 / HZ);
+ write_stream(out, ',');
+
+ json_write_string(out, "STime");
+ write_stream(out, ':');
+ json_write_uint64(out, (uint64_t)stime * 1000 / HZ);
+ write_stream(out, ',');
+
+ json_write_string(out, "CUTime");
+ write_stream(out, ':');
+ json_write_uint64(out, (uint64_t)cutime * 1000 / HZ);
+ write_stream(out, ',');
+
+ json_write_string(out, "CSTime");
+ write_stream(out, ':');
+ json_write_uint64(out, (uint64_t)cstime * 1000 / HZ);
+ write_stream(out, ',');
+
+ json_write_string(out, "Priority");
+ write_stream(out, ':');
+ json_write_long(out, (long)priority - 15);
+ write_stream(out, ',');
+
+ if (nice != 0) {
+ json_write_string(out, "Nice");
+ write_stream(out, ':');
+ json_write_long(out, nice);
+ write_stream(out, ',');
+ }
+
+ if (itrealvalue != 0) {
+ json_write_string(out, "ITRealValue");
+ write_stream(out, ':');
+ json_write_int64(out, (int64_t)itrealvalue * 1000 / HZ);
+ write_stream(out, ',');
+ }
+
+ json_write_string(out, "StartTime");
+ write_stream(out, ':');
+ json_write_uint64(out, (uint64_t)starttime * 1000 / HZ);
+ write_stream(out, ',');
+
+ json_write_string(out, "VSize");
+ write_stream(out, ':');
+ json_write_ulong(out, vsize);
+ write_stream(out, ',');
+
+ json_write_string(out, "PSize");
+ write_stream(out, ':');
+ json_write_ulong(out, getpagesize());
+ write_stream(out, ',');
+
+ json_write_string(out, "RSS");
+ write_stream(out, ':');
+ json_write_long(out, rss);
+ write_stream(out, ',');
+
+ json_write_string(out, "RLimit");
+ write_stream(out, ':');
+ json_write_ulong(out, rlim);
+ write_stream(out, ',');
+
+ if (startcode != 0) {
+ json_write_string(out, "CodeStart");
+ write_stream(out, ':');
+ json_write_ulong(out, startcode);
+ write_stream(out, ',');
+ }
+
+ if (endcode != 0) {
+ json_write_string(out, "CodeEnd");
+ write_stream(out, ':');
+ json_write_ulong(out, endcode);
+ write_stream(out, ',');
+ }
+
+ if (startstack != 0) {
+ json_write_string(out, "StackStart");
+ write_stream(out, ':');
+ json_write_ulong(out, startstack);
+ write_stream(out, ',');
+ }
+
+ json_write_string(out, "Signals");
+ write_stream(out, ':');
+ json_write_ulong(out, signal);
+ write_stream(out, ',');
+
+ json_write_string(out, "SigBlock");
+ write_stream(out, ':');
+ json_write_ulong(out, blocked);
+ write_stream(out, ',');
+
+ json_write_string(out, "SigIgnore");
+ write_stream(out, ':');
+ json_write_ulong(out, sigignore);
+ write_stream(out, ',');
+
+ json_write_string(out, "SigCatch");
+ write_stream(out, ':');
+ json_write_ulong(out, sigcatch);
+ write_stream(out, ',');
+
+ if (wchan != 0) {
+ json_write_string(out, "WChan");
+ write_stream(out, ':');
+ json_write_ulong(out, wchan);
+ write_stream(out, ',');
+ }
+
+ json_write_string(out, "NSwap");
+ write_stream(out, ':');
+ json_write_ulong(out, nswap);
+ write_stream(out, ',');
+
+ json_write_string(out, "CNSwap");
+ write_stream(out, ':');
+ json_write_ulong(out, cnswap);
+ write_stream(out, ',');
+
+ json_write_string(out, "ExitSignal");
+ write_stream(out, ':');
+ json_write_long(out, exit_signal);
+ write_stream(out, ',');
+
+ json_write_string(out, "Processor");
+ write_stream(out, ':');
+ json_write_long(out, processor);
+ write_stream(out, ',');
+
+ json_write_string(out, "RTPriority");
+ write_stream(out, ':');
+ json_write_ulong(out, rt_priority);
+ write_stream(out, ',');
+
+ json_write_string(out, "Policy");
+ write_stream(out, ':');
+ json_write_ulong(out, policy);
+ write_stream(out, ',');
+ }
+ close(f);
+ }
+ }
+
+ if (parent_id != NULL && parent_id[0] != 0) {
+ json_write_string(out, "ParentID");
+ write_stream(out, ':');
+ json_write_string(out, parent_id);
+ write_stream(out, ',');
+ }
+
+ json_write_string(out, "ID");
+ write_stream(out, ':');
+ json_write_string(out, id);
+
+ write_stream(out, '}');
+}
+
+static void command_get_context(char * token, Channel * c) {
+ char id[256];
+ pid_t pid = 0;
+ pid_t parent = 0;
+ int err = 0;
+ char dir[FILE_PATH_SIZE];
+
+ json_read_string(&c->inp, id, sizeof(id));
+ if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX);
+ if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+ write_stringz(&c->out, "R");
+ write_stringz(&c->out, token);
+
+ pid = id2pid(id, &parent);
+ if (pid != 0) {
+ struct stat st;
+ if (parent != 0) {
+ snprintf(dir, sizeof(dir), "/proc/%d/task/%d", parent, pid);
+ }
+ else {
+ snprintf(dir, sizeof(dir), "/proc/%d", pid);
+ }
+ if (lstat(dir, &st) < 0) err = errno == ENOENT ? ESRCH : errno;
+ else if (!S_ISDIR(st.st_mode)) err = ERR_INV_CONTEXT;
+ }
+
+ write_errno(&c->out, err);
+
+ if (err == 0 && pid != 0) {
+ char bf[256];
+ write_context(&c->out, id, parent == 0 ? NULL : strcpy(bf, pid2id(parent, 0)), dir);
+ write_stream(&c->out, 0);
+ }
+ else {
+ write_stringz(&c->out, "null");
+ }
+
+ write_stream(&c->out, MARKER_EOM);
+}
+
+static void command_get_children(char * token, Channel * c) {
+ char id[256];
+ pid_t pid = 0;
+ pid_t parent = 0;
+
+ json_read_string(&c->inp, id, sizeof(id));
+ if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX);
+ if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+ write_stringz(&c->out, "R");
+ write_stringz(&c->out, token);
+
+ pid = id2pid(id, &parent);
+
+ if (parent != 0) {
+ write_errno(&c->out, 0);
+ write_stringz(&c->out, "null");
+ }
+ else {
+ DIR * proc = NULL;
+ char dir[FILE_PATH_SIZE];
+ if (pid == 0) strcpy(dir, "/proc");
+ else snprintf(dir, sizeof(dir), "/proc/%d/task", pid);
+ proc = opendir(dir);
+ if (proc == NULL) {
+ int err = errno;
+ if (pid != 0 && err == ENOENT) {
+ struct stat buf;
+ snprintf(dir, sizeof(dir), "/proc/%d", pid);
+ if (stat(dir, &buf) == 0) {
+ /* Zombie */
+ err = 0;
+ }
+ else {
+ err = ESRCH;
+ }
+ }
+ write_errno(&c->out, err);
+ write_stringz(&c->out, "null");
+ }
+ else {
+ int cnt = 0;
+ write_errno(&c->out, 0);
+ write_stream(&c->out, '[');
+ for (;;) {
+ struct dirent * ent = readdir(proc);
+ if (ent == NULL) break;
+ if (ent->d_name[0] >= '1' && ent->d_name[0] <= '9') {
+ if (cnt > 0) write_stream(&c->out, ',');
+ json_write_string(&c->out, pid2id(atol(ent->d_name), pid));
+ cnt++;
+ }
+ }
+ write_stream(&c->out, ']');
+ write_stream(&c->out, 0);
+ closedir(proc);
+ }
+ }
+
+ write_stream(&c->out, MARKER_EOM);
+}
+
+static void command_get_command_line(char * token, Channel * c) {
+ char id[256];
+ pid_t pid = 0;
+ pid_t parent = 0;
+ int err = 0;
+ char dir[FILE_PATH_SIZE];
+ int f = -1;
+
+ json_read_string(&c->inp, id, sizeof(id));
+ if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX);
+ if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+ write_stringz(&c->out, "R");
+ write_stringz(&c->out, token);
+
+ pid = id2pid(id, &parent);
+ if (pid != 0 && parent == 0) {
+ struct stat st;
+ snprintf(dir, sizeof(dir), "/proc/%d", pid);
+ if (lstat(dir, &st) < 0) err = errno == ENOENT ? ESRCH : errno;
+ else if (!S_ISDIR(st.st_mode)) err = ERR_INV_CONTEXT;
+ }
+ else {
+ err = ERR_INV_CONTEXT;
+ }
+
+ if (err == 0 && chdir(dir) < 0) err = errno;
+ if (err == 0 && (f = open("cmdline", O_RDONLY)) < 0) err = errno;
+
+ write_errno(&c->out, err);
+
+ if (err == 0) {
+ write_string_array(&c->out, f);
+ close(f);
+ write_stream(&c->out, 0);
+ }
+ else {
+ write_stringz(&c->out, "null");
+ }
+
+ write_stream(&c->out, MARKER_EOM);
+}
+
+static void command_get_environment(char * token, Channel * c) {
+ char id[256];
+ pid_t pid = 0;
+ pid_t parent = 0;
+ int err = 0;
+ char dir[FILE_PATH_SIZE];
+ int f = -1;
+
+ json_read_string(&c->inp, id, sizeof(id));
+ if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX);
+ if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+
+ write_stringz(&c->out, "R");
+ write_stringz(&c->out, token);
+
+ pid = id2pid(id, &parent);
+ if (pid != 0 && parent == 0) {
+ struct stat st;
+ snprintf(dir, sizeof(dir), "/proc/%d", pid);
+ if (lstat(dir, &st) < 0) err = errno == ENOENT ? ESRCH : errno;
+ else if (!S_ISDIR(st.st_mode)) err = ERR_INV_CONTEXT;
+ }
+ else {
+ err = ERR_INV_CONTEXT;
+ }
+
+ if (err == 0 && chdir(dir) < 0) err = errno;
+ if (err == 0 && (f = open("environ", O_RDONLY)) < 0) err = errno;
+
+ write_errno(&c->out, err);
+
+ if (err == 0) {
+ write_string_array(&c->out, f);
+ close(f);
+ write_stream(&c->out, 0);
+ }
+ else {
+ write_stringz(&c->out, "null");
+ }
+
+ write_stream(&c->out, MARKER_EOM);
+}
+#endif
+
+extern void ini_sys_mon_service(Protocol * proto) {
+ add_command_handler(proto, SYS_MON, "getContext", command_get_context);
+ add_command_handler(proto, SYS_MON, "getChildren", command_get_children);
+ add_command_handler(proto, SYS_MON, "getCommandLine", command_get_command_line);
+ add_command_handler(proto, SYS_MON, "getEnvironment", command_get_environment);
+}
+
+#endif /* SERVICE_SysMonitor */

Back to the top