Logo Search packages:      
Sourcecode: netams version File versions  Download package

s_scheduler.c

/*************************************************************************
***   Authentication, authorization, accounting + firewalling package
***   Copyright 1998-2002 Anton Vinokurov <anton@netams.com>
***   Copyright 2002-2008 NeTAMS Development Team
***   This code is GPL v3
***   For latest version and more info, visit this project web page
***   located at http://www.netams.com
***
*************************************************************************/
/* $Id: s_scheduler.c,v 1.68 2009-08-01 09:23:55 anton Exp $ */

#include "netams.h"

static int initialized=0;
//////////////////////////////////////////////////////////////////////////
Service *sSched=NULL;
class ScheduleList *SchedL=NULL;
//////////////////////////////////////////////////////////////////////////
int cShowScheduleList   (struct cli_def *cli, const char *cmd, char **argv, int argc);
u_short sSchedulerGetTasks();
//////////////////////////////////////////////////////////////////////////
//defined commands
static const  struct CMD_DB cmd_db[] = {
{ 2, 0, 0, "show",      PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL,        "shows various system parameters" },
{ 0, 2, 0, "schedule",  PRIVILEGE_UNPRIVILEGED, MODE_EXEC, cShowScheduleList,       "active scheduled actions" },
{ 0, 0, 0, "oid", PRIVILEGE_UNPRIVILEGED, MODE_SCHEDULER, cServiceProcessCfg, NULL },
{ 0, 0, 0, "action",    PRIVILEGE_UNPRIVILEGED, MODE_SCHEDULER, cServiceProcessCfg, NULL },
{ 0, 0, 0, "time",      PRIVILEGE_UNPRIVILEGED, MODE_SCHEDULER, cServiceProcessCfg, NULL },
{ 0, 0, 0, "start",     PRIVILEGE_UNPRIVILEGED, MODE_SCHEDULER, cServiceStart,          NULL },
{ 0, 0, 0, "stop",      PRIVILEGE_UNPRIVILEGED, MODE_SCHEDULER, cServiceStop,           NULL },
{ -1, 0, 0, NULL,  0, 0, NULL, NULL }
};
//////////////////////////////////////////////////////////////////////////
class Service_Scheduler: public Service {
      public:
            Service_Scheduler();
            ~Service_Scheduler();

            void ShowCfg(struct cli_def *cli, u_char flags);
            int ProcessCfg(struct cli_def *cli, char **argv, int argc, u_char no_flag);
            void ShowInfo(struct cli_def *cli);
            void Worker();

};

void Service_Scheduler::ShowInfo(struct cli_def *cli) {
      cli_print(cli, " Scheduled tasks: %u", sSchedulerGetTasks());
}
//////////////////////////////////////////////////////////////////////////
Service* InitSchedulerService() {
      Service *s;
      if(!initialized) {
            InitCliCommands(cmd_db);
            initialized = 1;
      }
      s = (Service*)new Service_Scheduler();
      s->serv_flags|=SERVICE_FLAG_SINGLE;
      sSched = s;
      return s;
}
//////////////////////////////////////////////////////////////////////////
class Task: public Object{
      public:
            time_t when;
            char *action;
            char *str_interval;
            time_t interval;
            u_char visible;

            Task();
            ~Task();
};

class ScheduleList: public List {
      public:

            ScheduleList();
            ~ScheduleList() {};
            Task *getTask(char *action);
            void listTasks(struct cli_def *cli);
            void listTasksCfg(struct cli_def *cli);
};
//////////////////////////////////////////////////////////////////////////
void *sScheduler(void *ss);
void sSchedulerCancel(void *v);
void *sSchedulerTask(void *v);
time_t getInterval(char *s);
//////////////////////////////////////////////////////////////////////////
Task::Task():Object(){
      action=str_interval=NULL;
      interval=-1;
      when=0;
      visible=1;
}

Task::~Task(){
      if(action) aFree(action);
      if(str_interval) aFree(str_interval);
}

//////////////////////////////////////////////////////////////////////////
ScheduleList::ScheduleList():List(){
}

Task *ScheduleList::getTask(char *action){
      Task *d=NULL;

      netams_rwlock_rdlock(&rwlock);
      for(d=(Task*)root; d!=NULL; d=(Task*)d->next)
            if (STREQ(d->action, action))
                  break;
      netams_rwlock_unlock(&rwlock);
      return d;
}

void ScheduleList::listTasks(struct cli_def *cli){
      Task *t;

      cli_print(cli, "%6s | %-10s | %7s | %-40s", "OID", "INTERVAL", "LEFT", "ACTION");
      netams_rwlock_rdlock(&rwlock);
      for(t=(Task*)root; t!=NULL; t=(Task*)t->next){
            if (t->visible) {
                  cli_print(cli, "%06X | %-10s | %7d | %-40s",
                        t->id, t->str_interval, (int)(t->when-time(NULL)), t->action);
            }
      }
      netams_rwlock_unlock(&rwlock);
}

void ScheduleList::listTasksCfg(struct cli_def *cli){
      Task *t;

      netams_rwlock_rdlock(&rwlock);
      for(t=(Task*)root; t!=NULL; t=(Task*)t->next){
            if (t->visible) {
                  cli_bufprint(cli, "oid %06X", t->id);
                  if (t->str_interval) cli_bufprint(cli, " time %s", t->str_interval);
                  if (t->action) cli_bufprint(cli, " action \"%s\"", t->action);
                  cli_bufprint(cli, "\n");
            }
      }
      netams_rwlock_unlock(&rwlock);
}

void Service_Scheduler::ShowCfg(struct cli_def *cli, u_char flags) {
      SchedL->listTasksCfg(cli);
}

u_short sSchedulerGetTasks() {
      return sSched?SchedL->getNum():0;
}

int Service_Scheduler::ProcessCfg(struct cli_def *cli, char **param, int argc, u_char no_flag){
      Task *t=NULL;
      oid id=0;
      u_char i=0;

      if (STRARG(param[0], "oid")) {
            id=strtol(param[1], NULL, 16);
            t=(Task*)SchedL->getById(id);
            i+=2;
      }

      aDebug(DEBUG_SCHED, "getTaskByOid return: %p, p2=%s\n", t, param[1]);

      if (t && no_flag){
            cli_error(cli, "task %06X deleted", t->id);
            SchedL->Delete(t);
      }
      else if (!no_flag) {
            if(!t) {
                  t = new Task();
                  t->id = newOid(id);
                  cli_error(cli, "task %06X created", t->id);
            }
            else
                  cli_error(cli, "task %06X modified", t->id);

            for(; i<argc; i+=2) {
                  if (STRARG(param[i], "action")) {
                        if(t->action) aFree(t->action);
                        t->action=set_string(param[i+1]);
                        cli_error(cli, "task %06X action set: %s", t->id, t->action);

                  } else if (STRARG(param[i], "time")) {
                        t->interval=getInterval(param[i+1]);
                        if (t->interval==-1)
                              cli_error(cli, "time interval specified invalid");
                        else {
                              if(t->str_interval) aFree(t->str_interval);
                              t->str_interval=set_string(param[i+1]);
                              t->when=time(NULL)+t->interval;
                              cli_error(cli, "task %06X time set: %s, exec in %lu sec",
                                    t->id, t->str_interval, (u_long)t->interval);
                        }
                  } else if (STREQ(param[i], "invisible")) {
                        cli_error(cli, "task %06X set as invisible", t->id);
                        t->visible=0;
                        i--;
                  }
                  else
                        cli_error(cli, "schedule %06X command unknown", t->id);
            }

            if (t->interval!=-1) {
                  SchedL->Insert(t);
                  char buff[32]; timeU2T(t->when, buff);
                  cli_error(cli, "scheduled to: %s", buff);
            }
            else
                  cli_error(cli, "scheduling failed!");
      }
      else if (!t && no_flag)
            cli_error(cli, "task is not exist");

      sSched->Wakeup(); // we should re-calculate the scheduling table!
      return CLI_OK;
}
//////////////////////////////////////////////////////////////////////////
int cShowScheduleList(struct cli_def *cli, const char *cmd, char **argv, int argc){
      if(SchedL)
            SchedL->listTasks(cli);
      else
            cli_print(cli, "No scheduled task");

      return CLI_OK;
}
//////////////////////////////////////////////////////////////////////////
time_t getInterval(char *s_o){

      time_t retval=-1;
      struct tm t1;
      time_t ti1;
      time_t ti2;
      char s[255], *s1, *s2;
      int h, m, p=0, plus=0;
      char z[32];

      ti1=time(NULL);
      localtime_r(&ti1, &t1);
      ti2=mktime(&t1);

      bzero(z, 31);
      bzero(s, 255); strncpy(s, s_o, strlen(s_o));
      s1=&s[strlen(s)-1];
      if (s1[0]=='+') { plus= 10; s1[0]=0; }
      if (s1[0]=='-') { plus=-10; s1[0]=0; }
      sscanf(s, "%d%s", &p, z);

      aDebug(DEBUG_SCHED, " arg \"%s\" prefix %d string %s\n", s, p, z);

      if (p!=0) {
            if (STREQ(z, "sec")) retval=p;
            else if (STREQ(z, "min")) retval=p*60;
            else if (STREQ(z, "hour")) retval=p*60*60;
            else if (STREQ(z, "day")) retval=p*60*60*24;
            else if (STREQ(z, "week")) retval=p*60*60*24*7;
            else if (STREQ(z, "month")) {
                  if (p<1 || p>12) return retval;
                  t1.tm_mon+=p; t1.tm_isdst=-1; //? t2.tm_isdst=-1;
                  if (t1.tm_mon>11) { t1.tm_year++; t1.tm_mon-=12; }
                  //    debug(D_MAIN, D_INFO, "flextime/month: p=%d, t1=%ld, t2=%ld, interval=%d\n", p, mktime(t1), mktime(t2), (int)difftime(mktime(t1), mktime(t2)));
                  retval=(time_t)difftime(mktime(&t1), ti2);
            }
            return retval;
      }

      if (STREQ(s, "hourly")) {
            //    debug(D_MAIN, D_INFO, "flextime/month: p=%d, t1=%ld, t2=%ld, interval=%d\n", p, mktime(t1)+24*60*60, mktime(t2), (int)difftime(mktime(t1)+24*60*60, mktime(t2)));
            retval=(time_t)difftime(aGetActual('H',ti1)+60*60, ti2)+plus;
            if (retval<=0) retval+=60*60;
      }
      else if (STREQ(s, "daily")) {
            //    debug(D_MAIN, D_INFO, "flextime/month: p=%d, t1=%ld, t2=%ld, interval=%d\n", p, mktime(t1)+24*60*60, mktime(t2), (int)difftime(mktime(t1)+24*60*60, mktime(t2)));
            retval=(time_t)difftime(aGetActual('D',ti1)+60*60*24, ti2)+plus;
            if (retval<=0) retval+=60*60*24;
      }
      else if (STREQ(s, "weekly")) {
            //    debug(D_MAIN, D_INFO, "flextime/month: p=%d, t1=%ld, t2=%ld, interval=%d\n", p, mktime(t1)+24*60*60, mktime(t2), (int)difftime(mktime(t1)+24*60*60, mktime(t2)));
            retval=(time_t)difftime(aGetActual('W',ti1), ti2)+plus;
            if (retval<=0) retval+=60*60*7*24;
      }
      else if (STREQ(s, "monthly")) {
            //    debug(D_MAIN, D_INFO, "flextime/month: p=%d, t1=%ld, t2=%ld, interval=%d\n", p, mktime(t1)+24*60*60, mktime(t2), (int)difftime(mktime(t1)+24*60*60, mktime(t2)));
            retval=(time_t)difftime(aGetActual('M',ti1), ti2)+plus;
            if (retval<=0) retval+=60*60*24; //shit!!!
      }
      else if (strstr(s, "at-")==s) { //looks like at-XXXXX
            s1=strchr(s+1, '.'); if (s1==NULL) s1=strchr(s+1, ':');
            //    debug(D_MAIN, D_INFO, "s=%s(%p), s1=%p\n", s, s, s1);
            if (s1==NULL) return retval; // no time definition at 'at'
            s2=strchr(s1+1, '-');
            sscanf(s+3, "%d", &h); sscanf(s+6, "%d", &m);
            if (h<0 || h>24 || m<0 || m>59) return retval;

            localtime_r(&ti1, &t1);
            //sprintf(s3, "%d", t1->tm_wday);
            //if (strchr(s2+1, s3[0])!=NULL) { *i=0xffff; return 1; }

            t1.tm_sec=0; t1.tm_min=m; t1.tm_hour=h; t1.tm_isdst=-1;
            retval=(time_t)difftime(mktime(&t1), ti2);
            if (retval<=0) retval=retval+24*60*60;
            // debug(DEBUG_SCHED, "getInterval: %d \n", retval);
      }

      return retval;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// service thread definition
Service_Scheduler::Service_Scheduler():Service(SERVICE_SCHEDULER) {
      sSched=this;
      SchedL=new ScheduleList;
}

Service_Scheduler::~Service_Scheduler() {
      sSched=NULL;
      delete SchedL;
      SchedL=NULL;
}
//////////////////////////////////////////////////////////////////////////
void Service_Scheduler::Worker(){
      Task *t;
      time_t now, min;
      pthread_t task;

      aLog(D_INFO, "service scheduler:%u processing queue\n", instance);
      while (1) {
            aDebug(DEBUG_SCHED, "scheduler loop processed...\n");

            time(&now); min=SCHED_MIN_SLEEP_TIME;

            for (t=(Task*)SchedL->root; t!=NULL; t=(Task*)t->next){
                  if (t->when<=now) {
                        if (t->visible) aLog(D_INFO, "time to exec task %06X \"%s\"\n", t->id, t->action);

                        // actual exec
                        pthread_create(&task, NULL, &sSchedulerTask, t->action);

                        t->when=now + getInterval(t->str_interval);
                  }
                  aDebug(DEBUG_SCHED, " current task %06X now %ld when %ld min %d\n", t->id, now, t->when, min);
                  if (min > (t->when-now)) min=(t->when-now);
            }

            aDebug(DEBUG_SCHED, "scheduler sleeping for %d seconds\n", min);
            Sleep(min);
      }
}
//////////////////////////////////////////////////////////////////////////
void *sSchedulerTask(void *ss){
      DISABLE_CANCEL;
      pthread_detach(pthread_self());

      aCommand((char*)ss, MODE_EXEC);

      return NULL;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////

Generated by  Doxygen 1.6.0   Back to index