Exemplo n.º 1
0
static void test_graceful_terminate(void)
{
    int ret, state;

    pid_t new_pid = fork();
    assert_true(new_pid >= 0);

    if (new_pid == 0)                                           /* child */
    {
        execl("/bin/sleep", "/bin/sleep", "30", NULL);
        assert_true(false);                                  /* unreachable */
    }

    time_t start_time = GetProcessStartTime(new_pid);
    SPAWNED_PID = new_pid;

    printf("Spawned a \"sleep\" child with PID %jd and start_time %jd\n",
           (intmax_t) new_pid, (intmax_t) start_time);

    state = GetProcessState(new_pid);
    assert_int_equal(state, PROCESS_STATE_RUNNING);

    printf("Killing child with wrong start_time, child should not die...\n");

    ret = GracefulTerminate(new_pid, 12345);             /* fake start time */
    assert_false(ret);

    state = GetProcessState(new_pid);
    assert_int_equal(state, PROCESS_STATE_RUNNING);

    printf("Killing child with correct start_time, child should die...\n");

    ret = GracefulTerminate(new_pid, start_time);
    assert_true(ret);

    state = GetProcessState(new_pid);
    assert_int_equal(state, PROCESS_STATE_ZOMBIE);

    wait(NULL);                                               /* reap child */

    state = GetProcessState(new_pid);
    assert_int_equal(state, PROCESS_STATE_DOES_NOT_EXIST);

    printf("Child Dead!\n");
    SPAWNED_PID = 0;

    printf("Killing ourself, should fail...\n");
    ret = GracefulTerminate(THIS_PID, THIS_STARTTIME);
    assert_false(ret);

    printf("Killing ourself without specifying starttime, should fail...\n");
    ret = GracefulTerminate(THIS_PID, PROCESS_START_TIME_UNKNOWN);
    assert_false(ret);
}
Exemplo n.º 2
0
void test_kill_simple_process(void)
{
    InitTime();
    InitFakeProcess(12345, 100, false, false, true);

    int res = GracefulTerminate(1, 12345);
    assert_true(res);

    FakeProcessDoSignals();

    assert_false(exists);
    assert_int_equal(exit_signal, SIGINT);
}
Exemplo n.º 3
0
void TimeOut()
{
    alarm(0);

    if (ALARM_PID != -1)
    {
        Log(LOG_LEVEL_VERBOSE, "Time out of process %jd", (intmax_t)ALARM_PID);
        GracefulTerminate(ALARM_PID, PROCESS_START_TIME_UNKNOWN);
    }
    else
    {
        Log(LOG_LEVEL_VERBOSE, "%s> Time out", VPREFIX);
    }
}
Exemplo n.º 4
0
void test_kill_anothers_process(void)
{
    /* This process is not owned by killer */
    InitTime();
    InitFakeProcess(12345, 100, true, true, false);

    int res = GracefulTerminate(1, 12345);
    assert_true(res);

    FakeProcessDoSignals();

    assert_true(exists);
    assert_false(was_stopped);
}
Exemplo n.º 5
0
void test_kill_no_sigint_sigterm(void)
{
    /* This process only can be killed by SIGKILL */
    InitTime();
    InitFakeProcess(12345, 100, true, true, true);

    int res = GracefulTerminate(1, 12345);
    assert_true(res);

    FakeProcessDoSignals();

    assert_false(exists);
    assert_int_equal(exit_signal, SIGKILL);
}
Exemplo n.º 6
0
void test_kill_no_sigint(void)
{
    /* This process blocks SIGINT */
    InitTime();
    InitFakeProcess(12345, 100, true, false, true);

    int res = GracefulTerminate(1, 12345);
    assert_true(res);

    FakeProcessDoSignals();

    assert_false(exists);
    assert_int_equal(exit_signal, SIGTERM);
}
Exemplo n.º 7
0
void test_kill_long_reacting_signal(void)
{
    /* This process is very slow in reaction. It should not be left stopped though */
    InitTime();
    InitFakeProcess(12345, 2000000000, false, false, true);

    int res = GracefulTerminate(1, 12345);
    assert_true(res);

    FakeProcessDoSignals();

    assert_true(exists); /* We should not kill this process */
    assert_false(stopped); /* It should either be running or waiting to process SIGCONT */
}
Exemplo n.º 8
0
void TimeOut()
{
    alarm(0);

    if (ALARM_PID != -1)
    {
        CfOut(OUTPUT_LEVEL_VERBOSE, "", "Time out of process %jd\n", (intmax_t)ALARM_PID);
        GracefulTerminate(ALARM_PID);
    }
    else
    {
        CfOut(OUTPUT_LEVEL_VERBOSE, "", "%s> Time out\n", VPREFIX);
    }
}
Exemplo n.º 9
0
void test_kill_wrong_process(void)
{
    InitTime();
    InitFakeProcess(66666, 100, false, false, true);

    int res = GracefulTerminate(1, 12345);
    assert_true(res);

    FakeProcessDoSignals();

    assert_true(exists);
    assert_false(stopped);
    assert_false(was_stopped); /* We should not touch this process at all */
    assert_int_equal(signal_time, (time_t)-1); /* No pending signals either */
}
Exemplo n.º 10
0
CfLock AcquireLock(char *operand, char *host, time_t now, Attributes attr, Promise *pp, int ignoreProcesses)
{
    unsigned int pid;
    int i, err, sum = 0;
    time_t lastcompleted = 0, elapsedtime;
    char *promise, cc_operator[CF_BUFSIZE], cc_operand[CF_BUFSIZE];
    char cflock[CF_BUFSIZE], cflast[CF_BUFSIZE], cflog[CF_BUFSIZE];
    char str_digest[CF_BUFSIZE];
    CfLock this;
    unsigned char digest[EVP_MAX_MD_SIZE + 1];

    this.last = (char *) CF_UNDEFINED;
    this.lock = (char *) CF_UNDEFINED;
    this.log = (char *) CF_UNDEFINED;

    if (now == 0)
    {
        return this;
    }

    this.last = NULL;
    this.lock = NULL;
    this.log = NULL;

/* Indicate as done if we tried ... as we have passed all class
   constraints now but we should only do this for level 0
   promises. Sub routine bundles cannot be marked as done or it will
   disallow iteration over bundles */

    if (pp->done)
    {
        return this;
    }

    if (CF_STCKFRAME == 1)
    {
        *(pp->donep) = true;
        /* Must not set pp->done = true for editfiles etc */
    }

    HashPromise(operand, pp, digest, CF_DEFAULT_DIGEST);
    strcpy(str_digest, HashPrint(CF_DEFAULT_DIGEST, digest));

/* As a backup to "done" we need something immune to re-use */

    if (THIS_AGENT_TYPE == cf_agent)
    {
        if (IsItemIn(DONELIST, str_digest))
        {
            CfOut(cf_verbose, "", " -> This promise has already been verified");
            return this;
        }

        PrependItem(&DONELIST, str_digest, NULL);
    }

/* Finally if we're supposed to ignore locks ... do the remaining stuff */

    if (IGNORELOCK)
    {
        this.lock = xstrdup("dummy");
        return this;
    }

    promise = BodyName(pp);
    snprintf(cc_operator, CF_MAXVARSIZE - 1, "%s-%s", promise, host);
    strncpy(cc_operand, operand, CF_BUFSIZE - 1);
    CanonifyNameInPlace(cc_operand);
    RemoveDates(cc_operand);

    free(promise);

    CfDebug("AcquireLock(%s,%s), ExpireAfter=%d, IfElapsed=%d\n", cc_operator, cc_operand, attr.transaction.expireafter,
            attr.transaction.ifelapsed);

    for (i = 0; cc_operator[i] != '\0'; i++)
    {
        sum = (CF_MACROALPHABET * sum + cc_operator[i]) % CF_HASHTABLESIZE;
    }

    for (i = 0; cc_operand[i] != '\0'; i++)
    {
        sum = (CF_MACROALPHABET * sum + cc_operand[i]) % CF_HASHTABLESIZE;
    }

    snprintf(cflog, CF_BUFSIZE, "%s/cf3.%.40s.runlog", CFWORKDIR, host);
    snprintf(cflock, CF_BUFSIZE, "lock.%.100s.%s.%.100s_%d_%s", pp->bundle, cc_operator, cc_operand, sum, str_digest);
    snprintf(cflast, CF_BUFSIZE, "last.%.100s.%s.%.100s_%d_%s", pp->bundle, cc_operator, cc_operand, sum, str_digest);

    CfDebug("LOCK(%s)[%s]\n", pp->bundle, cflock);

// Now see if we can get exclusivity to edit the locks

    CFINITSTARTTIME = time(NULL);

    WaitForCriticalSection();

/* Look for non-existent (old) processes */

    lastcompleted = FindLock(cflast);
    elapsedtime = (time_t) (now - lastcompleted) / 60;

    if (elapsedtime < 0)
    {
        CfOut(cf_verbose, "", " XX Another cf-agent seems to have done this since I started (elapsed=%jd)\n",
              (intmax_t) elapsedtime);
        ReleaseCriticalSection();
        return this;
    }

    if (elapsedtime < attr.transaction.ifelapsed)
    {
        CfOut(cf_verbose, "", " XX Nothing promised here [%.40s] (%jd/%u minutes elapsed)\n", cflast,
              (intmax_t) elapsedtime, attr.transaction.ifelapsed);
        ReleaseCriticalSection();
        return this;
    }

/* Look for existing (current) processes */

    if (!ignoreProcesses)
    {
        lastcompleted = FindLock(cflock);
        elapsedtime = (time_t) (now - lastcompleted) / 60;

        if (lastcompleted != 0)
        {
            if (elapsedtime >= attr.transaction.expireafter)
            {
                CfOut(cf_inform, "", "Lock %s expired (after %jd/%u minutes)\n", cflock, (intmax_t) elapsedtime,
                      attr.transaction.expireafter);

                pid = FindLockPid(cflock);

                if (pid == -1)
                {
                    CfOut(cf_error, "", "Illegal pid in corrupt lock %s - ignoring lock\n", cflock);
                }
#ifdef MINGW                    // killing processes with e.g. task manager does not allow for termination handling
                else if (!NovaWin_IsProcessRunning(pid))
                {
                    CfOut(cf_verbose, "",
                          "Process with pid %d is not running - ignoring lock (Windows does not support graceful processes termination)\n",
                          pid);
                    LogLockCompletion(cflog, pid, "Lock expired, process not running", cc_operator, cc_operand);
                    unlink(cflock);
                }
#endif /* MINGW */
                else
                {
                    CfOut(cf_verbose, "", "Trying to kill expired process, pid %d\n", pid);

                    err = GracefulTerminate(pid);

                    if (err || errno == ESRCH)
                    {
                        LogLockCompletion(cflog, pid, "Lock expired, process killed", cc_operator, cc_operand);
                        unlink(cflock);
                    }
                    else
                    {
                        ReleaseCriticalSection();
                        FatalError("Unable to kill expired cfagent process %d from lock %s, exiting this time..\n", pid,
                                   cflock);
                    }
                }
            }
            else
            {
                ReleaseCriticalSection();
                CfOut(cf_verbose, "", "Couldn't obtain lock for %s (already running!)\n", cflock);
                return this;
            }
        }

        WriteLock(cflock);
    }

    ReleaseCriticalSection();

    this.lock = xstrdup(cflock);
    this.last = xstrdup(cflast);
    this.log = xstrdup(cflog);

/* Keep this as a global for signal handling */
    strcpy(CFLOCK, cflock);
    strcpy(CFLAST, cflast);
    strcpy(CFLOG, cflog);

    return this;
}