142
147
*----------------------------------------------------------------------
149
* ProcMgr_ReadProcFile --
151
* Read the contents of a file in /proc/<pid>.
153
* The size is essentially unbounded because of cmdline arguments.
154
* The only way to figure out the content size is to keep reading;
155
* stat(2) and lseek(2) lie.
157
* The contents are NUL terminated -- in some distros may not include
158
* a NUL for some commands (eg. pid 1, /sbin/init) -- so add
163
* The length of the file.
169
* The returned contents must be freed by caller.
171
*----------------------------------------------------------------------
176
ProcMgr_ReadProcFile(int fd, // IN
177
char **contents) // OUT
180
#if !defined(__FreeBSD__) && !defined(__APPLE__)
185
numRead = read(fd, tmp, sizeof(tmp));
193
* handle the 99% case
195
if (sizeof(tmp) > numRead) {
198
result = malloc(numRead + 1);
199
if (NULL == result) {
203
memcpy(result, tmp, numRead);
204
result[numRead] = '\0';
211
DynBuf_Append(&dbuf, tmp, numRead);
213
numRead = read(fd, tmp, sizeof(tmp));
215
DynBuf_Append(&dbuf, tmp, numRead);
218
} while (numRead > 0);
220
DynBuf_Append(&dbuf, "", 1);
222
*contents = DynBuf_Detach(&dbuf);
223
DynBuf_Destroy(&dbuf);
233
*----------------------------------------------------------------------
144
235
* ProcMgr_ListProcesses --
146
237
* List all the processes that the calling client has privilege to
156
247
*----------------------------------------------------------------------
159
251
ProcMgr_ProcList *
160
252
ProcMgr_ListProcesses(void)
162
254
ProcMgr_ProcList *procList = NULL;
163
#if !defined(__FreeBSD__) && !defined(sun) && !defined(__APPLE__)
255
#if !defined(__FreeBSD__) && !defined(__APPLE__)
164
256
Bool failed = FALSE;
166
258
DynBuf dbProcCmd;
290
382
* In the future, we could keep the NUL version around and pass it
291
383
* back to the client for easier parsing when retrieving individual
292
384
* command line parameters is needed.
294
* We read at most (sizeof cmdLineTemp) - 1 bytes to leave room
295
* for NUL termination at the end.
297
numRead = read(cmdFd, cmdLineTemp, sizeof cmdLineTemp - sizeof(char));
386
numRead = ProcMgr_ReadProcFile(cmdFd, &cmdLineTemp);
300
393
if (numRead > 0) {
395
* Stop before we hit the final '\0'; want to leave it alone.
301
397
for (replaceLoop = 0 ; replaceLoop < (numRead - 1) ; replaceLoop++) {
302
398
if ('\0' == cmdLineTemp[replaceLoop]) {
303
399
cmdLineTemp[replaceLoop] = ' ';
320
416
cmdFd = open(cmdFilePath, O_RDONLY);
322
418
if (cmdFd != -1) {
323
numRead = read(cmdFd, cmdLineTemp, sizeof(cmdLineTemp) - sizeof(char));
419
numRead = ProcMgr_ReadProcFile(cmdFd, &cmdLineTemp);
327
cmdLineTemp[0] = '\0';
329
cmdLineTemp[numRead] = '\0';
332
422
if (numRead > 0) {
334
424
* Extract the part with just the name, by reading until the first
335
425
* space, then reading the next non-space word after that, and
336
426
* ignoring everything else. The format looks like this:
363
* There is an edge case where /proc/#/cmdline does not NUL terminate
364
* the command. /sbin/init (process 1) is like that on some distros.
365
* So let's guarantee that the string is NUL terminated, even if
366
* the last character of the string might already be NUL.
367
* This is safe to do because we read at most (sizeof cmdLineTemp) - 1
368
* bytes from /proc/#/cmdline -- we left just enough space to add
369
* NUL termination at the end.
372
cmdLineTemp[0] = '\0';
374
cmdLineTemp[numRead] = '\0';
378
453
* Get the inode information for this process. This gives us
379
454
* the process owner.
406
481
ent->d_name) == -1) {
407
482
Debug("Giant process id '%s'\n", ent->d_name);
410
485
cmdFd = open(cmdFilePath, O_RDONLY);
411
486
if (-1 == cmdFd) {
414
numRead = read(cmdFd, cmdStatTemp, sizeof cmdStatTemp);
489
numRead = ProcMgr_ReadProcFile(cmdFd, &cmdStatTemp);
416
491
if (0 >= numRead) {
420
495
* Skip over initial process id and process name. "123 (bash) [...]".
422
497
stringBegin = strchr(cmdStatTemp, ')') + 2;
424
499
numberFound = sscanf(stringBegin, "%c %d %d %d %d %d "
425
500
"%lu %lu %lu %lu %lu %Lu %Lu %Lu %Lu %ld %ld "
437
512
(int *) &dummy, (long *) &dummy,
438
513
&relativeStartTime);
439
514
if (20 != numberFound) {
442
517
processStartTime = hostStartTime + (relativeStartTime / hertz);
445
520
* Store the command line string pointer in dynbuf.
447
cmdLine = strdup(cmdLineTemp);
523
cmdLine = Unicode_Alloc(cmdLineTemp, STRING_ENCODING_DEFAULT);
525
cmdLine = Unicode_Alloc("", STRING_ENCODING_UTF8);
448
527
DynBuf_Append(&dbProcCmd, &cmdLine, sizeof cmdLine);
459
538
pwd = getpwuid(fileStat.st_uid);
460
539
userName = (NULL == pwd)
461
540
? Str_Asprintf(&strLen, "%d", (int) fileStat.st_uid)
462
: Util_SafeStrdup(pwd->pw_name);
541
: Unicode_Alloc(pwd->pw_name, STRING_ENCODING_DEFAULT);
463
542
DynBuf_Append(&dbProcOwner, &userName, sizeof userName);
582
666
Debug("Executing sync command: %s\n", cmd);
584
pid = ProcMgrStartProcess(cmd, userArgs ? userArgs->envp : NULL);
668
pid = ProcMgrStartProcess(cmd, userArgs ? userArgs->envp : NULL,
669
userArgs ? userArgs->workingDirectory : NULL);
612
697
ProcMgrStartProcess(char const *cmd, // IN: UTF-8 encoded cmd
613
char * const *envp) // IN: UTF-8 encoded env vars
698
char * const *envp, // IN: UTF-8 encoded env vars
699
char const *workingDir) // IN: UTF-8 working directory
616
702
char *cmdCurrent = NULL;
617
703
char **envpCurrent = NULL;
704
char *workDir = NULL;
619
706
if (cmd == NULL) {
721
if ((NULL != workingDir) &&
722
!CodeSet_Utf8ToCurrent(workingDir, strlen(workingDir), &workDir, NULL)) {
723
Warning("Could not convert workingDir from UTF-8 to current\n");
634
727
if (NULL != envp) {
635
728
envpCurrent = Unicode_GetAllocList(envp, -1, STRING_ENCODING_DEFAULT);
641
734
Warning("Unable to fork: %s.\n\n", strerror(errno));
642
735
} else if (pid == 0) {
738
* On Solaris, /bin/sh is the Bourne shell, and it
739
* doesn't appear to have the optimization that bash does -- when
740
* called with -c, bash appears to just use exec() to replace itself.
741
* Bourne shell does a fork & exec, so 2 processes are started.
742
* This is bad for us because we then see the PID of the shell, not the
743
* app that it starts. When this PID is returned to a user to
744
* watch, they'll watch the wrong process.
746
* So for Solaris, use bash instead if possible. We support
747
* Solaris 10 and better; it contains bash, but not in its
748
* minimal 'core' package, so it may not exist.
750
static const char bashShellPath[] = SOLARIS_BASH_PATH;
751
char *bashArgs[] = { "bash", "-c", cmdCurrent, NULL };
752
static const char bourneShellPath[] = "/bin/sh";
753
char *bourneArgs[] = { "sh", "-c", cmdCurrent, NULL };
754
const char *shellPath;
643
757
static const char shellPath[] = "/bin/sh";
644
758
char *args[] = { "sh", "-c", cmdCurrent, NULL };
762
if (File_Exists(SOLARIS_BASH_PATH)) {
763
shellPath = bashShellPath;
766
shellPath = bourneShellPath;
775
if (NULL != workDir) {
776
if (chdir(workDir) != 0) {
777
Warning("%s: Could not chdir(%s) %s\n", __FUNCTION__, workDir,
650
782
if (NULL != envpCurrent) {
651
783
execve(shellPath, args, envpCurrent);
763
896
FileIODescriptor readFd;
764
897
FileIODescriptor writeFd;
766
Debug("Executing async command: %s\n", cmd);
899
Debug("Executing async command: '%s' in working dir '%s'\n",
900
cmd, (userArgs && userArgs->workingDirectory) ? userArgs->workingDirectory : "");
768
902
if (pipe(fds) == -1) {
769
903
Warning("Unable to create the pipe to launch command: %s.\n", cmd);
819
953
* Only run the program if we have not already experienced a failure.
822
childPid = ProcMgrStartProcess(cmd, userArgs ? userArgs->envp : NULL);
956
childPid = ProcMgrStartProcess(cmd,
957
userArgs ? userArgs->envp : NULL,
958
userArgs ? userArgs->workingDirectory : NULL);
823
959
status = childPid != -1;
1592
*----------------------------------------------------------------------
1594
* ProcMgr_GetImpersonatedUserInfo --
1596
* Return info about the impersonated user.
1603
*----------------------------------------------------------------------
1607
ProcMgr_GetImpersonatedUserInfo(char **userName, // OUT
1608
char **homeDir) // OUT
1610
uid_t uid = geteuid();
1611
char buffer[BUFSIZ];
1613
struct passwd *ppw = &pw;
1618
if ((error = getpwuid_r(uid, &pw, buffer, sizeof buffer, &ppw)) != 0 ||
1621
* getpwuid_r() and getpwnam_r() can return a 0 (success) but not
1622
* set the return pointer (ppw) if there's no entry for the user,
1623
* according to POSIX 1003.1-2003, so patch up the errno.
1631
*userName = Unicode_Alloc(ppw->pw_name, STRING_ENCODING_DEFAULT);
1632
*homeDir = Unicode_Alloc(ppw->pw_dir, STRING_ENCODING_DEFAULT);
1455
1637
#endif // linux