blob: 04226f305eab157ea5d57dc9cc86413f4164d89b [file] [log] [blame]
/*******************************************************************************
* 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.
*
* 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;
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;
}
}
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;
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;
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 */