/*
 * (C) Copyright 1996- ECMWF.
 *
 * This software is licensed under the terms of the Apache Licence Version 2.0
 * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
 * In applying this licence, ECMWF does not waive the privileges and immunities
 * granted to it by virtue of its status as an intergovernmental organisation
 * nor does it submit to any jurisdiction.
 */

#include <csignal>
#include <unistd.h>

#include "eckit/cmd/KillCmd.h"
#include "eckit/runtime/Monitor.h"


namespace eckit {

//----------------------------------------------------------------------------------------------------------------------

KillCmd::KillCmd() :
    CmdResource("kill") {}


KillCmd::~KillCmd() {}


void KillCmd::execute(std::istream&, std::ostream& out, CmdArg& arg) {

    Monitor::TaskArray& info = Monitor::instance().tasks();

    for (size_t i = 1; i < arg.size(); ++i) {

        Value task(arg[i]);

        if (task.isNil()) {
            // usage(out);
            return;
        }

        if (task.isNumber()) {
            // MarsId or Unix process ID
            unsigned long marsid = (long long)task;
            if (marsid > info.size()) {
                kill(marsid, out);
            }
            else {
                kill(info[marsid].pid(), out);
            }
        }

        if (task.isString()) {
            // Name. Look for Unix process ID
            std::string name = task;
            for (unsigned long i = 0; i < info.size(); ++i) {
                if (info[i].busy(true) && info[i].application() == name) {
                    kill(info[i].pid(), out);
                }
            }
        }
    }
}


void KillCmd::kill(pid_t pid, std::ostream& out) const {
    static pid_t me = ::getpid();
    if (pid == me) {
        out << pid << ": Suicide avoided ;-)" << std::endl;
    }
    else {
        if (::kill(pid, SIGTERM)) {
            out << Log::syserr << std::endl;
        }
        else {
            out << pid << ": Killed" << std::endl;
        }
    }
}


void KillCmd::help(std::ostream& out) const {}


Arg KillCmd::usage(const std::string& cmd) const {
    return Arg("<name>", Arg::text) | Arg("<pid>", Arg::number) | Arg("<task>", Arg::number);
}


static KillCmd killCmd;

//----------------------------------------------------------------------------------------------------------------------

}  // namespace eckit
