Project

General

Profile

Feature #42 » killall5.c.patch

Patch for killall5.c (by Caleb James DeLisle) - Igor Pashev, 2012-12-22 09:17 PM

View differences:

src/killall5.c
40 40
 *		along with this program; if not, write to the Free Software
41 41
 *		Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
42 42
 */
43
#ifdef __sun__
44
    #define __EXTENSIONS__
45
    /* PATH_MAX */
46
    #include <limits.h>
47

  
48
    #include <sys/ucontext.h>
49
    #include <procfs.h>
50
    #include <fcntl.h>
51
    #include <sys/types32.h>
52
    #include <assert.h>
53

  
54
    #define va_list __va_list
55
    #include <procfs.h>
56
#endif
57

  
43 58
#include <dirent.h>
44 59
#include <errno.h>
45 60
#include <getopt.h>
46
#include <mntent.h>
61
#ifndef __sun__
62
    #include <mntent.h>
63
#endif
47 64
#include <stdarg.h>
48 65
#include <stdio.h>
49 66
#include <stdlib.h>
......
181 198
 */
182 199
int mount_proc(void)
183 200
{
201
    #ifdef __sun__
202
        const char* checkProc = "/proc/0";
203
    #else
204
        const char* checkProc = "/proc/version";
205
    #endif
206

  
184 207
	struct stat	st;
185 208
	char		*args[] = { "mount", "-t", "proc", "proc", "/proc", 0 };
186 209
	pid_t		pid, rc;
......
188 211
	int		did_mount = 0;
189 212

  
190 213
	/* Stat /proc/version to see if /proc is mounted. */
191
	if (stat("/proc/version", &st) < 0 && errno == ENOENT) {
214
	if (stat(checkProc, &st) < 0 && errno == ENOENT) {
192 215

  
193 216
		/* It's not there, so mount it. */
194 217
		if ((pid = fork()) < 0) {
......
215 238
	}
216 239

  
217 240
	/* See if mount succeeded. */
218
	if (stat("/proc/version", &st) < 0) {
241
	if (stat(checkProc, &st) < 0) {
219 242
		if (errno == ENOENT)
220 243
			nsyslog(LOG_ERR, "/proc not mounted, failed to mount.");
221 244
		else
......
237 260
	return 0;
238 261
}
239 262

  
263
#ifdef __sun__
264
    void init_nfs(void) { }
265
#else
240 266
/*
241 267
 *     Remember all NFS typed partitions.
242 268
 */
......
302 328
	}
303 329
	endmntent(mnt);
304 330
}
331
#endif /* not __sun__ */
305 332

  
306 333
static void clear_shadow(SHADOW *restrict shadow)
307 334
{
......
443 470
	return (c == EOF && f == 0) ? c : f;
444 471
}
445 472

  
473

  
474

  
475
#ifdef __sun__
476

  
477
static int openProcFile(const char* format, int pid)
478
{
479
    char procfile[100];
480
    snprintf(procfile, 100, format, pid);
481
    int fd;
482
    if ((fd = open(procfile, O_RDONLY)) < 0) {
483
        fprintf(stderr, "Error opening %s", procfile);
484
        perror(" ");
485
        exit(1);
486
    }
487
    return fd;
488
}
489

  
490
static int readStringFromAs(int asFd, uint64_t offset, char** strOut, int strOutSize)
491
{
492
    char* initStr = *strOut;
493
    if (pread(asFd, initStr, strOutSize, offset) < 0) {
494
        return 0;
495
    }
496
    initStr[strOutSize] = '\0';
497
    int length = strlen(initStr);
498
    if (length == strOutSize) {
499
        // need a bigger buffer.
500
        strOutSize *= 2;
501
        *strOut = realloc(initStr, strOutSize);
502
        assert(*strOut);
503
        return readStringFromAs(asFd, offset, strOut, strOutSize);
504
    }
505
    return length;
506
}
507

  
508
static char* getArguments(psinfo_t* psinfo)
509
{
510
    int asFd = openProcFile("/proc/%d/as", psinfo->pr_pid);
511

  
512
    uintptr_t addrArgs = psinfo->pr_argv;
513
    int argCount = psinfo->pr_argc;
514

  
515
    // argPointers point to the arguments in the process's memory space.
516
    // args point to the copies of them in our memory space.
517
    uintptr_t* argPointers = malloc(argCount * sizeof(uintptr_t));
518
    char** args = malloc(argCount * sizeof(uintptr_t));
519
    assert(argPointers && args);
520
    if (psinfo->pr_dmodel == PR_MODEL_NATIVE) {
521
        pread(asFd, argPointers, argCount * sizeof(uintptr_t), addrArgs);
522
    } else {
523
        // we are 64-bit, target is 32-bit
524
        caddr32_t* argPointers32 = (caddr32_t*) argPointers;
525
        pread(asFd, argPointers32, argCount * sizeof(caddr32_t), addrArgs);
526
        // convert from 32-bit to 64-bit in place
527
        for (int i = argCount - 1; i >= 0; --i) {
528
            argPointers[i] = argPointers32[i];
529
        }
530
    }
531

  
532
    int totalLength = 0;
533
    for (int i = 0; i < argCount; i++) {
534
        char* arg = malloc(16);
535
        assert(arg);
536
        totalLength += readStringFromAs(asFd, argPointers[i], &arg, 16);
537
        args[i] = arg;
538
    }
539

  
540
    close(asFd);
541

  
542
    // Merge everything into one buffer representing a list of null terminated strings.
543
    char* out = malloc(totalLength + argCount + 4);
544
    assert(out);
545
    memcpy(out, &argCount, 4);
546
    int index = 4;
547
    for (int i = 0; i < argCount; i++) {
548
        int length = strlen(args[i]);
549
        memcpy(out + index, args[i], length+1);
550
        index += length+1;
551
        free(args[i]);
552
    }
553
    free(argPointers);
554

  
555
    return out;
556
}
557

  
558
static char* baseName(char* name)
559
{
560
    if (!name) { return NULL; }
561
    char* base = strrchr(name, '/');
562
    return (base) ? base+1 : name;
563
}
564

  
565
static void getNfsInodeNumberAndDevice(int do_stat, psinfo_t* psinfo, struct proc* procOut)
566
{
567
    char path[PATH_MAX+1];
568

  
569
    snprintf(path, sizeof(path), "/proc/%d/path/a.out", psinfo->pr_pid);
570

  
571
	procOut->nfs = 0;
572
    if (do_stat == DO_NETFS) {
573
        char buff[PATH_MAX+1];
574
        procOut->nfs = check4nfs(path, buff);
575
    } else if (do_stat != DO_STAT) {
576
        return;
577
    }
578

  
579
    struct stat st = { .st_dev = 0 };
580

  
581
    if (stat(path, &st)) { fprintf(stderr, "Failed to stat [%s]\n", path); }
582

  
583
    procOut->dev = st.st_dev;
584
    procOut->ino = st.st_ino;
585
}
586

  
587
static void getProcInfo(int pid, int do_stat, struct proc* procOut)
588
{
589
    psinfo_t psinfo;
590
    {
591
        int psinfoFd = openProcFile("%d/psinfo", pid);
592
        read(psinfoFd, &psinfo, sizeof(psinfo_t));
593
        close(psinfoFd);
594
    }
595

  
596
    // argv0, argv1
597
    procOut->argv0 = procOut->argv1 = NULL;
598
    {
599
        char* args = getArguments(&psinfo);
600
        int argCount;
601
        memcpy(&argCount, args, 4);
602
        char* argv = args+4;
603
        for (int i = 0; i < argCount; i++) {
604
            if (i == 0) {
605
                procOut->argv0 = strdup(argv);
606
                assert(procOut->argv0);
607
            } else if (argv[0] != '-') {
608
                procOut->argv1 = strdup(argv);
609
                assert(procOut->argv1);
610
                break;
611
            }
612
            argv += strlen(argv) + 1;
613
        }
614
        free(args);
615
    }
616

  
617
    // argv0base, argv1base
618
    procOut->argv0base = baseName(procOut->argv0);
619
    procOut->argv1base = baseName(procOut->argv1);
620

  
621
    // statname is compared to argv1base used to decide if it's executing a script.
622
    procOut->statname = strdup(psinfo.pr_fname);
623

  
624
    // Is it a kernel thread or zombie.
625
    // Linux detects this by checking the upper and lower bounds of the address space.
626
    // From some basic testing I see that Illumos sets the size of obvious kernel threads
627
    // such as sched to 0 so we'll assume that kernel threads are defined by image size
628
    // being zero.
629
    procOut->kernel = (psinfo.pr_size == 0);
630

  
631
    if (!procOut->kernel) {
632
        // nfs, ino, dev
633
        getNfsInodeNumberAndDevice(do_stat, &psinfo, procOut);
634
    }
635

  
636
    procOut->pid = psinfo.pr_pid;
637
    procOut->sid = psinfo.pr_sid;
638
}
639

  
640
void freeProcList()
641
{
642
    PROC* p;
643
	PROC* n = plist;
644
	for (p = plist; n; p = n) {
645
		n = p->next;
646
		if (p->argv0) { free(p->argv0); }
647
		if (p->argv1) { free(p->argv1); }
648
		if (p->statname) { free(p->statname); }
649
		free(p);
650
	}
651
	plist = NULL;
652
}
653

  
654
int readproc(int do_stat)
655
{
656
	/* Open the /proc directory. */
657
	if (chdir("/proc") == -1) {
658
		nsyslog(LOG_ERR, "chdir /proc failed");
659
		return -1;
660
	}
661
    DIR* procDir;
662
	if ((procDir = opendir(".")) == NULL) {
663
		nsyslog(LOG_ERR, "cannot opendir(/proc)");
664
		return -1;
665
	}
666

  
667
	/* Free the already existing process list. */
668
    freeProcList();
669

  
670
	/* Walk through the directory. */
671
    struct dirent* d;
672
	while ((d = readdir(procDir)) != NULL) {
673

  
674
		/* See if this is a process */
675
        int pid;
676
		if ((pid = atoi(d->d_name)) == 0) { continue; }
677

  
678
		/* Get a PROC struct . */
679
		PROC* p = xmalloc(sizeof(PROC));
680
		memset(p, 0, sizeof(PROC));
681

  
682
        getProcInfo(pid, do_stat, p);
683

  
684
		/* Link it into the list. */
685
		p->next = plist;
686
		plist = p;
687
    }
688
    closedir(procDir);
689

  
690
	/* Done. */
691
	return 0;
692
}
693

  
694
#else /* __sun__ */
695

  
446 696
/*
447 697
 *	Read the proc filesystem.
448 698
 *	CWD must be /proc to avoid problems if / is affected by the killing (ie depend on fuse).
......
630 880
	/* Done. */
631 881
	return 0;
632 882
}
883
#endif /* not __sun__ */
633 884

  
634 885
PIDQ_HEAD *init_pid_q(PIDQ_HEAD *q)
635 886
{
    (1-1/1)