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

common.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: common.c,v 1.193 2009-08-01 09:23:55 anton Exp $ */

#include "netams.h"

char *SHOW_VERSION=NULL;
//////////////////////////////////////////////////////////////////////////////////////////
const char *signal_name[] = { "", "Kill", "Reload", "Shutdown" };
//////////////////////////////////////////////////////////////////////////////////////////
const char UNKNOWN_REFERENCE[]="<..>";

//////////////////////////////////////////////////////////////////////////////////////////
// Logging Management ///////////////////////////////////////////////////////////////////
pthread_mutex_t log_lock = PTHREAD_MUTEX_INITIALIZER;
void aLog(u_char level, char const *fmt, ...){

      time_t t;
      struct timeval tv;
      char t_T[30];
      const char *where,*state;
      u_char id=0;
      Service *s;
      Connection *conn;
      va_list ap;
      int facility;
      static char str2log2[256];
      static char str2log1[256+64];

      switch(level){
            case D_INFO:    state="INFO"; facility=LOG_INFO; break;
            case D_ERR:     state="ERR"; facility=LOG_ERR; break;
            case D_CRIT:    state="CRIT"; facility=LOG_CRIT; break;
            case D_WARN:    state="WARN"; facility=LOG_WARNING; break;
                case D_DEBUG:
#ifndef DEBUG
                  return;
#endif
                  state="DEBUG";
                  facility=LOG_DEBUG;
                  break;
                default:
                state=UNKNOWN_REFERENCE;
                facility=LOG_NOTICE;
                break;
      }

      DISABLE_CANCEL;

      if(Services && (s=Services->getServiceByThr(pthread_self()))) {
            where=s->getName();
            id=s->instance;
      } else if(Connections && (conn=Connections->getConnectionByThr(pthread_self()))) {
            where="conn";
            id=conn->id;
      } else
            where=UNKNOWN_REFERENCE;

      time(&t); timeU2T(t, t_T);
      gettimeofday(&tv, NULL);

      pthread_mutex_lock(&log_lock);

      if (flag_nodaemon && !flag_quiet)
            fprintf(stdout, "%s.%04u %s:%u [%s]: ", t_T, (unsigned)((double)tv.tv_usec/100), where, id, state);
      if (flag_log)
            fprintf(LOGFILE, "%s.%04u %s:%u [%s]: ", t_T, (unsigned)((double)tv.tv_usec/100), where, id, state);

      if (flag_syslog) { bzero(str2log2, 256); bzero(str2log1, 256+64); }

      if (flag_nodaemon && !flag_quiet) {
            va_start(ap, fmt);
            vfprintf(stdout, fmt, ap);
            va_end(ap);
      }
      if (flag_log) {
            va_start(ap, fmt);
            vfprintf(LOGFILE, fmt, ap);
            va_end(ap);
      }
      if (flag_syslog) {
            va_start(ap, fmt);
            vsnprintf(str2log2,256, fmt, ap);
            va_end(ap);
      }

      if (flag_syslog) {
          snprintf(str2log1,256+64,"%s:%u %s", where, id, str2log2);
          syslog(facility,str2log1);
      }

      pthread_mutex_unlock(&log_lock);
      RESTORE_CANCEL;

      if (level==D_ERR && !is_running) termination(SIGTERM);
      if (level==D_CRIT) termination(SIGTERM);
}
//////////////////////////////////////////////////////////////////////////////////////////
void logrotate(int signal){
      if(flag_log && LOGFILE) {
            aLog(D_INFO, "Rotating log file %s\n",path_to_log);
            FILE *f = LOGFILE;
            LOGFILE = NULL;
            fclose(f);
            LOGFILE=fopen(path_to_log, "at");
      }
}
//////////////////////////////////////////////////////////////////////////////////////////
void termination(int signal){
      if(signal==SIGKILL)
            global_return_code = KILL;
      else
            global_return_code = SHUTDOWN;
      sMain->Wakeup();
}

int cTermination(struct cli_def *cli, const char *cmd, char **argv, int argc) {
      if(STREQ(argv[0], "kill"))    global_return_code = KILL;
      else if(STREQ(argv[0], "shutdown")) global_return_code = SHUTDOWN;
      else if(STREQ(argv[0], "reload"))   global_return_code = RELOAD;

      sMain->Wakeup();
      return CLI_OK;
}
/////////////////////////////////////////////////////////////////////////////////////////////
char *timeU2T(time_t time, char *buf){
      struct tm tm;
      if (buf==NULL) buf=(char *)aMalloc(25);
      localtime_r(&time, &tm);
      sprintf(buf, "%02d.%02d.%4d %02d:%02d:%02d", tm.tm_mday, tm.tm_mon+1, tm.tm_year+1900, tm.tm_hour, tm.tm_min, tm.tm_sec);
      return buf;
}
///////////////////////////////////////////////////////////////////////////
time_t timeT2U(char *buf, time_t *time){
      struct tm tm;
      time_t t;
      sscanf(buf, "%02d.%02d.%4d %02d:%02d:%02d", &tm.tm_mday, &tm.tm_mon, &tm.tm_year, &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
      tm.tm_mon = tm.tm_mon-1;
      tm.tm_year = tm.tm_year-1900;
      tm.tm_isdst = -1;
      t=mktime(&tm);
      if (time!=NULL) memcpy(time, &t, sizeof(time_t));
      return t;
}
/////////////////////////////////////////////////////////////////////////////////////////////
char *bytesQ2T(unsigned long long bytes, char *buf){
if (buf==NULL) buf=(char*)aMalloc(12);
if (bytes<KILOBYTE) sprintf(buf, "%llu", bytes);
else if (bytes>=KILOBYTE && bytes<MEGABYTE) sprintf(buf, "%.3fK", (double)bytes/(KILOBYTE));
else if (bytes>=MEGABYTE && bytes<GIGABYTE) sprintf(buf, "%.3fM", (double)bytes/(MEGABYTE));
else if (bytes>=GIGABYTE && bytes <TERABYTE) sprintf(buf, "%.3fG", (double)bytes/(GIGABYTE));
else if (bytes>=TERABYTE) sprintf(buf, "%.3fT", (double)bytes/(TERABYTE));
else aLog(D_WARN, "bytesQ2T called with enormous value: %llu\n", bytes);
return buf;
}
//////////////////////////////////////////////////////////////////////////////////////////
unsigned long long bytesT2Q(char *buf){
if (buf==NULL) { return 0; }
long double b;
sscanf(buf, "%Lf", &b);
if (strchr(buf, 'K')!=NULL) b*=KILOBYTE;
if (strchr(buf, 'M')!=NULL) b*=MEGABYTE;
if (strchr(buf, 'G')!=NULL) b*=GIGABYTE;
if (strchr(buf, 'T')!=NULL) b*=TERABYTE;
return (unsigned long long)b;
}
//////////////////////////////////////////////////////////////////////////////////////////
pthread_mutex_t oid_lock = PTHREAD_MUTEX_INITIALIZER;
#define MAX_OID         0x0FFFFF    //max oid
#define CELL_SIZE 32
#define CELL_MASK (CELL_SIZE-1)
u_int32_t oids_hash[(MAX_OID+1)>>5];            //it's important sizeof(u_int)=32
unsigned oids_used;

void aOidsInit() {
      oids_used=0;
#if defined (LINUX) || defined (SOLARIS) || defined (NETBSD)
      srandom(time(NULL));
#else
      srandomdev(); // true random numbers at each run
#endif
      bzero(&oids_hash, (MAX_OID+1)>>5);
}

oid newOid(oid newid){
      newid&=MAX_OID; //restrict oids we work

      oid result=newid;
      u_short poz;
      u_char bit;

      netams_mutex_lock(&oid_lock);

      if(newid) {
            poz=(unsigned)(result>>5);
            bit=result&CELL_MASK;
            goto OK;
      }

      for(u_char j=0;j<25;j++) {
            result=random()&MAX_OID;
            poz=(unsigned)(result>>5);
            bit=result&CELL_MASK;
            if(!(oids_hash[poz]&(1<<bit)))  goto OK;
      }

      for(result=1; result<MAX_OID; result++) { // no oids with 0000 in the end
            poz=(unsigned)(result>>5);
            bit=result&CELL_MASK;
            if(!(oids_hash[poz]&(1<<bit))) goto OK;
      }

      netams_mutex_unlock(&oid_lock);
      aLog(D_WARN, "newOid cannot construct new id\n");
      return 0;
OK:
      oids_used++;
      oids_hash[poz]|=(1<<bit);
      netams_mutex_unlock(&oid_lock);
      return result;

}
//////////////////////////////////////////////////////////////////////////////////////////
void PrepareTimeCounters(struct time_counters *tc, time_t t1) {
        struct tm tm1;

        localtime_r(&t1, &tm1);
        tm1.tm_sec=0; tm1.tm_min=0; tm1.tm_isdst=-1;
        tc->ht=mktime(&tm1);

        tm1.tm_hour=0; tm1.tm_isdst=-1;
        tc->dt=mktime(&tm1);

        if (tm1.tm_wday==0) tm1.tm_wday=7;
        tm1.tm_mday+=(8-tm1.tm_wday)-7;
        tc->wt=mktime(&tm1);

        localtime_r(&t1, &tm1);
        tm1.tm_sec=0; tm1.tm_min=0; tm1.tm_hour=0; tm1.tm_isdst=-1;
        tm1.tm_mday=1; // tm1.tm_mon-=1; if (tm1.tm_mon<0) {         tm1.tm_year--; tm1.tm_mon+=12; }
        tc->mt=mktime(&tm1);

}
//////////////////////////////////////////////////////////////////////////////////////////
void FillTimeCounters(policy_data *np, struct time_counters *tc){

      time_t t2;

      t2=tc->ht;
      if (np->h.from!=t2) {
            np->h.from=t2;
            np->h.in=np->h.out=0;
      }

      t2=tc->dt;
      if (np->d.from!=t2) {
            np->d.from=t2;
            np->d.in=np->d.out=0;
      }

      t2=tc->wt;
      if (np->w.from!=t2) {
            np->w.from=t2;
            np->w.in=np->w.out=0;
      }

      t2=tc->mt;
      if (np->m.from!=t2) {
            np->m.from=t2;
            np->m.in= np->m.out=0;
      }

}

//////////////////////////////////////////////////////////////////////////////////////////
// Debugging management
Debug debug=0;
const char *debug_list[64];
const char *debug_list_help[64];
pthread_mutex_t debug_lock = PTHREAD_MUTEX_INITIALIZER;

#if defined(DEBUG) || defined(OLD_GCC)
u_char aDebug(u_char d, char const *fmt, ...){
#ifdef DEBUG

      if(!debug_list[d]) return 0;

      Connection *conn;
      va_list ap;

      DISABLE_CANCEL;
      pthread_mutex_lock(&debug_lock);

      va_start(ap, fmt);
      for (conn=Connections?(Connection*)Connections->root:NULL; conn!=NULL; conn=(Connection*)conn->next) {
            if (conn->cli->client && aDebugIsSet(&conn->debug, d)) {
                  cli_bufprint(conn->cli, "|%s: ", debug_list[d]);
                  cli_vabufprint(conn->cli, (char*)fmt, ap);
            }
      }
      va_end(ap);

      #ifdef DEBUG_TO_LOG
      if (flag_log && aDebugIsSet(&debug, d)) {
            fprintf(LOGFILE, "|%s: ", debug_list[d]);
            va_start(ap, fmt);
            vfprintf(LOGFILE, fmt, ap);
            va_end(ap);
            if(!flag_quiet) {
                  fprintf(stdout, "|%s: ", debug_list[d]);
                  va_start(ap, fmt);
                  vfprintf(stdout, fmt, ap);
                  va_end(ap);
            }
      }
      #endif

      pthread_mutex_unlock(&debug_lock);
      RESTORE_CANCEL;

      return 1;
#endif
}
#endif

u_char aDebugAdd(Debug *d, const char *str){
      for (u_char i=0; i<64; i++){
            if (STREQ(str, debug_list[i])) {
                  if (i==DEBUG_NONE) *d=0L;
                  else if (i==DEBUG_ALL) *d=~0;
                  else *d |= (Debug)(1<<i);
                  return 1;
            }
      }
      return 0;
}

u_char aDebugRm(Debug *d, const char *str){
      for (u_char i=0; i<64; i++){
            if (STREQ(str, debug_list[i])) {
                  if (i==DEBUG_NONE) *d=~0;
                  else if (i==DEBUG_ALL) *d=0;
                  else *d &=~ (Debug)(1<<i);
                  return 1;
            }
      }
      return 0;
}

u_char aDebugIsSet(Debug *d, u_char u){
      if (u==DEBUG_NONE && *d==0) return 1;
      else if (u==DEBUG_ALL && *d==~0) return 1;
      else if (u!=DEBUG_NONE && (*d&((Debug)1<<u))) return 1;
      return 0;
}

void aDebugInit(){
      for (u_char i=0; i<=63; i++) { debug_list[i]=NULL;    debug_list_help[i]=NULL; }
      debug_list[DEBUG_NONE]="none"; debug_list_help[DEBUG_NONE]="turn off all debugging info";
      debug_list[DEBUG_COMMAND]="command"; debug_list_help[DEBUG_COMMAND]="entered command processing";
      debug_list[DEBUG_PARSE]="parse"; debug_list_help[DEBUG_PARSE]="entered command parse";
      debug_list[DEBUG_SLEEP]="sleep"; debug_list_help[DEBUG_SLEEP]="services going in/out sleep mode";
      debug_list[DEBUG_SERVER]="server"; debug_list_help[DEBUG_SERVER]="commands server activity";
      debug_list[DEBUG_PROC_MUX]="proc_mux"; debug_list_help[DEBUG_PROC_MUX]="processor multiplexer activity";
      debug_list[DEBUG_DS_IP]="ds_ip"; debug_list_help[DEBUG_DS_IP]="data sources, IP-packets based";
      debug_list[DEBUG_STORAGE]="storage"; debug_list_help[DEBUG_STORAGE]="storage activity";
      debug_list[DEBUG_ALERT]="alert"; debug_list_help[DEBUG_ALERT]="system alerts";
      debug_list[DEBUG_SCHED]="scheduler"; debug_list_help[DEBUG_SCHED]="scheduled actions";
      debug_list[DEBUG_HTML]="html"; debug_list_help[DEBUG_HTML]="html static pages generation";
      debug_list[DEBUG_MONITOR]="monitor"; debug_list_help[DEBUG_MONITOR]="specified units packet headers";
      debug_list[DEBUG_LOGIN]="login"; debug_list_help[DEBUG_LOGIN]="user login events";
      debug_list[DEBUG_QUOTA]="quota"; debug_list_help[DEBUG_QUOTA]="quota control events";
      debug_list[DEBUG_IPTREE]="iptree"; debug_list_help[DEBUG_IPTREE]="iptree engine events";
      debug_list[DEBUG_FLOW]="flow"; debug_list_help[DEBUG_FLOW]="ip flow engine events";
      debug_list[DEBUG_DS_MUX]="ds_mux"; debug_list_help[DEBUG_DS_MUX]="data source multiplexer activity";
      debug_list[DEBUG_MEMORY]="memory"; debug_list_help[DEBUG_MEMORY]="memory usage events";
      debug_list[DEBUG_POLICY]="policy"; debug_list_help[DEBUG_POLICY]="policy checking actions";
      debug_list[DEBUG_BILLING]="billing"; debug_list_help[DEBUG_BILLING]="billing events";
      debug_list[DEBUG_BW]="bw"; debug_list_help[DEBUG_BW]="bandwidth engine events";
      debug_list[DEBUG_ACLSERVER]="aclserver"; debug_list_help[DEBUG_BW]="acl server events";
      debug_list[DEBUG_MUTEX]="mutex"; debug_list_help[DEBUG_MUTEX]="mutex operations events";
      debug_list[DEBUG_DS_RAW]="ds_raw"; debug_list_help[DEBUG_DS_RAW]="data sources, RAW data";
      debug_list[DEBUG_ALL]="all"; debug_list_help[DEBUG_ALL]="turn on all debugging info (be careful!)";
}
//////////////////////////////////////////////////////////////////////////////////////////
void aShowVersion(FILE *f) {
      fprintf(f, "%s\n", SHOW_VERSION);
}
//////////////////////////////////////////////////////////////////////////////////////////
int cShowVersion(struct cli_def *cli, const char *cmd, char **argv, int argc){
      struct rusage res;
      struct timeval now;
      unsigned long days, hours, mins, secs;
      time_t t_secs;
      double mksecs;

      cli_print(cli, "%s", SHOW_VERSION);

      gettimeofday(&now, NULL);
      if (0!=getrusage(RUSAGE_SELF, &res)) {
            cli_error(cli, "resourse usage retrival failed: %s\n", strerror(errno));
            return CLI_OK;
      }

      char buf[32];
      t_secs=(now.tv_sec - program_start.tv_sec);
      days=t_secs/(60*60*24);
      *buf=0;
      hours=(t_secs-days*60*60*24)/(60*60);
      mins=(t_secs-(days*60*60*24)-(hours*60*60))/60;
      secs=t_secs-(days*60*60*24)-(hours*60*60)-mins*60;
      mksecs=(double)(now.tv_usec - program_start.tv_usec)/1000000;

      *buf=0;
      if (days>0) sprintf(buf, " %ld days", days);
      if (hours>0) sprintf(buf+strlen(buf), " %ld hours", hours);
      if (mins>0) sprintf(buf+strlen(buf), " %ld mins", mins);
      cli_print(cli, "Run time %s %.4f secs", buf, fabs((double)secs+mksecs));

      t_secs=(res.ru_stime.tv_sec);
      days=t_secs/(60*60*24);
      hours=(t_secs-days*60*60*24)/(60*60);
      mins=(t_secs-(days*60*60*24)-(hours*60*60))/60;
      secs=t_secs-(days*60*60*24)-(hours*60*60)-mins*60;
      mksecs=(double)(res.ru_stime.tv_usec)/1000000;

      if (days>0) sprintf(buf, " %ld days", days);
      if (hours>0) sprintf(buf+strlen(buf), " %ld hours", hours);
      if (mins>0) sprintf(buf+strlen(buf), " %ld mins", mins);
      cli_print(cli, "System time: %s %.4f secs", buf, (double)secs+mksecs);

      cli_print(cli, "Average CPU/system load: %3.2f%%",
            100*((float)(res.ru_stime.tv_sec)+(float)(res.ru_stime.tv_usec)/1000000)/
            ((float)(now.tv_sec - program_start.tv_sec)+(float)(now.tv_usec - program_start.tv_usec)/1000000));
      cli_print(cli, "Process ID: %u RES: %luK", getpid(), res.ru_maxrss);
      cli_print(cli, "Memory allocated: %llu (%lu), freed (%lu) (%u NULL) [%lu used]",
            aGetBytesAllocated(), aGetTimesAllocated(), aGetTimesFreed(),
            aGetTimesFreedNull(), aGetTimesAllocated() - aGetTimesFreed());

      cli_print(cli, "Total objects:");

      cli_print(cli, "   Oids used: %u", oids_used);
      cli_print(cli, "   NetUnits: %u", Units->getNum());
      cli_print(cli, "   Policies: %u", PolicyL->getNum());
      cli_print(cli, "   Services: %u", Services->getNum());
      cli_print(cli, "   Users: %u", Users->getNum());
      cli_print(cli, "   Connections: %u active, %u total",
            Connections->getNum(), Connections->getConnectionsLastId());

      cli_print(cli, "\nServices info:");
      Services->ShowInfo(cli);

      return CLI_OK;
}
//////////////////////////////////////////////////////////////////////////////////////////
time_t aGetActual(char prefix, time_t t){
      struct tm tm;
      time_t actual=0;

      localtime_r(&t, &tm);

      //next in special order most often we check for H, then for M and so on
      switch(prefix) {
            case 'H': {
                  tm.tm_sec=0; tm.tm_min=0; tm.tm_isdst=-1;
                  actual=mktime(&tm);
                  break;
            }
            case 'M': {
                  tm.tm_sec=0; tm.tm_min=0; tm.tm_hour=0; tm.tm_isdst=-1;
                  tm.tm_mday=1;  tm.tm_mon++; //if (tm.tm_mon<0) {      tm.tm_year--; tm.tm_mon+=12; }
                  actual=mktime(&tm);
                  break;
            }
            case 'W': {
                  tm.tm_sec=0; tm.tm_min=0; tm.tm_hour=0; tm.tm_isdst=-1;
                  if (tm.tm_wday==0) tm.tm_wday=7;
                  tm.tm_mday+=(8-tm.tm_wday)-7;
                  actual=mktime(&tm);
                  break;
            }
            case 'D': {
                  tm.tm_sec=0; tm.tm_min=0; tm.tm_hour=0; tm.tm_isdst=-1;
                  actual=mktime(&tm);
                  break;
            }
            case 'F':
                  actual=t;
                  break;
      }

      return actual;
}
//////////////////////////////////////////////////////////////////////////////////////////
void print_to_string(char **string, char const *fmt, ...){

      va_list ap;
      char *result;
      char *ret;

      va_start(ap, fmt);
      if (-1==vasprintf(&ret, fmt, ap)) { va_end(ap); return; }
      va_end(ap);

      if (*string) {
            result=(char*)aMalloc(strlen(*string)+strlen(ret)+1);
            sprintf(result, "%s%s", *string, ret);
            aFree(*string);
            (*string)=result;
      }
      else
            (*string)=set_string(ret);

      free(ret);
}
//////////////////////////////////////////////////////////////////////////////////////////
char *set_string(const char *string) {
      char *res=NULL;
      if(string) {
            res=(char*)aMalloc(strlen(string)+1);
            strcpy(res, string);
      }
      return res;
}
//////////////////////////////////////////////////////////////////////////////////////////
// command execution
static pthread_mutex_t cmd_lock = PTHREAD_MUTEX_INITIALIZER;

int aCommand(const char *cmd, int mode, FILE *f){
      int res;

      netams_mutex_lock(&cmd_lock);
      CLI->client=f;
      if(mode!= MODE_EXEC)
            cli_set_configmode(CLI, mode, NULL);
      res = cli_run_command(CLI, cmd);
      CLI->client=NULL;
      netams_mutex_unlock(&cmd_lock);
      return res;
}


char* cExec(const char *cmd){
      char buf[260];
      u_char size;
      char *res = NULL;
      u_short res_size=0;
      u_short poz=0;
      FILE *tmp;

      tmp=tmpfile();
      if (tmp == NULL) {
            aLog(D_WARN, "Failed to create tmp file for %s: %s", cmd, strerror(errno));
            return NULL;
      }

      netams_mutex_lock(&cmd_lock);
      CLI->client = tmp;
      cli_run_command(CLI, cmd);
      CLI->client=NULL;
      netams_mutex_unlock(&cmd_lock);

      rewind(tmp);
      while((size=fread(buf, 1, 255 , tmp)) >0 ) {
            if(poz+size>= res_size) {
                  res_size+=256;
                  res = (char*)realloc(res, res_size);
                  bzero(res+res_size-256, 256);
            }
            bcopy(buf, res+poz, size);
            poz+=size;
      }
      fclose(tmp);
      return res;
}
//////////////////////////////////////////////////////////////////////////////////////////
void cAccessScriptCall(restrict_type action, NetUnit *u, const char *p){
      if (!Processor->access_script) return;
      char buf[32];
      int i;

      char *param=NULL;
      if (u->type==NETUNIT_HOST) {
            print_to_string(&param, "%s %s", inet_ntop(AF_INET, &((NetUnit_host*)u)->ip, buf, 32), p);
      }
      else if (u->type==NETUNIT_USER) {
            print_to_string(&param, "%s %s", inet_ntop(AF_INET, &((NetUnit_user*)u)->ip, buf, 32), p);
      }
      else {
            param=set_string(p);
      }

      unsigned len = strlen(Processor->access_script) + 15 + strlen(param);
      char *buffer = (char*)aMalloc(len);
      oid oid=u->id;

      switch (action) {
            case DROP:
                  snprintf(buffer, len, "%s DENY %06X %s", Processor->access_script, oid, param?param:"");
                  break;
            case PASS:
                  snprintf(buffer, len, "%s ALLOW %06X %s", Processor->access_script, oid, param?param:"");
                  break;
            case PASS_LOCAL:
                  snprintf(buffer, len, "%s LOCAL %06X %s", Processor->access_script, oid, param?param:"");
                  break;
            default:
                  break;
      }

      i=netams_system(buffer);
      aLog(D_INFO, "cAccessScriptCall oid %06X action %d system:%d\n", oid, action, i);
      aFree(param);
      aFree(buffer);
}
//////////////////////////////////////////////////////////////////////////////////////////
int cShowPerf(struct cli_def *cli, const char *cmd, char **argv, int argc) {
      char *filename=NULL;
      FILE *out=NULL;
      u_char i=2;

      if (argc>i) {
            filename=argv[i++];
            if(filename) {
                  out=fopen(filename, "at");
                  if(!out) return CLI_OK;
                  cli=cli_init();
                  cli->client = out;
            }
      }

      if (STREQ(argv[i], "header") || !filename) {
            cli_print(cli, "%s", SHOW_VERSION);
            /*
            TOD         Time-Of-Day
            RTM         Run Time
            STM         System Time
            LOAD        System Load
            RES         Resources Usage
            */
            cli_bufprint(cli, "%10s  %7s  %7s  %5s  %5s  ","TOD","RTM","STM","LOAD","RES");

            Services->ShowPerf(cli, 1);
            cli_bufprint(cli, "\n");

      }

      struct rusage res;
      struct timeval now;
      time_t t_secs;
      double mksecs;
      static char t_T[32];
      time_t t;

      time(&t); timeU2T(t, t_T);
      gettimeofday(&now, NULL);

      //TOD
//    fprintf(out, "%s.%04u  ", t_T, (unsigned)((double)now.tv_usec/100));
      cli_bufprint(cli, "%-19s", t_T);

      //RTM
      t_secs=(now.tv_sec - program_start.tv_sec);
      cli_bufprint(cli, "  %7lu", (u_long)t_secs);

      //STM
      if (0!=getrusage(RUSAGE_SELF, &res)) { return CLI_OK; }
      t_secs=(res.ru_stime.tv_sec);
      mksecs=(double)(res.ru_stime.tv_usec)/1000000;
      cli_bufprint(cli, "  %7f", t_secs+mksecs);

      //LOAD
      cli_bufprint(cli, "  %3.2f",
            100*((float)(res.ru_stime.tv_sec)+(float)(res.ru_stime.tv_usec)/1000000)/((float)(now.tv_sec - program_start.tv_sec)+(float)(now.tv_usec - program_start.tv_usec)/1000000));

      //RES
      cli_bufprint(cli, "  %5lu", res.ru_maxrss);

      //show performance counters for all services which provides such an info
      Services->ShowPerf(cli);

      cli_bufprint(cli, "\n");
      if(filename) {
            cli_done(cli);
            fclose(out);
      }
      return CLI_OK;
}
//////////////////////////////////////////////////////////////////////////////////////////
int aShowSystemHealth(struct cli_def *cli, u_char is_html) {
      int health=0;

      double loadavg[3];
      if (getloadavg(loadavg, 3)!=-1) {
            if(cli) cli_bufprint(cli, "%s: %2.0f%%", Locale(LC_H_SYSTAT_LOAD, !is_html), 100*loadavg[1]);
            if (loadavg[1]>=0.8) health++;
      }

      struct statvfs_name_local vfs;
      Service *sh = Services->getServiceNextByType(SERVICE_HTML, NULL);
      if (sh) {
            Service_Html *sh_cfg = (Service_Html*)sh;
            if (!statvfs_name_local(sh_cfg->path, &vfs))
                  if(cli) cli_bufprint(cli, ", %s: %2.0f%%",
                        Locale(LC_H_SYSTAT_HTML_ST, !is_html),
                        100*(double)vfs.f_bfree/vfs.f_blocks);
            if ((double)vfs.f_bfree/vfs.f_blocks<=0.1) health++;
      }

      if(cli) cli_bufprint(cli, "\n");
      return health;
}

int cShowSystemHealth(struct cli_def *cli, const char *cmd, char **argv, int argc) {
      aShowSystemHealth(cli);
      return CLI_OK;
}
//////////////////////////////////////////////////////////////////////////////////////////
int getAddr(char *str, in_addr *addr, in_addr *mask) {
      int mlen=32;
      char *p=strchr(str, '/');
      if (p) {
            *p=0;
            if(inet_aton(str, addr)==0) {
                  *p='/';
                  return -1;
            }
            p++;
            mlen=atoi(p);
            if(mlen>32) {
                  in_addr ia;
                  inet_aton(p, &ia);
                  mlen=MASK2MLEN(ia);
            }
            if(mask) {
                  mask->s_addr=htonl(MLEN2MASK(mlen));
                  addr->s_addr&=mask->s_addr; //auto-correction
            }
      } else {
            if(inet_aton(str, addr)==0)
                  return -1;
            if(mask) mask->s_addr=INADDR_BROADCAST;
      }
      return mlen;
}

u_char mask2mlen(in_addr *mask) {
      unsigned tmp=mask->s_addr;
        u_char m=0;

        for(u_char i=0;i<32;i++) {
                if(tmp&1) m++;
                tmp=tmp>>1;
        }

      return m;
}
//////////////////////////////////////////////////////////////////////////////////////////
int getdayofweek(const char *str){
      int res=-1;
      if (STRNEQ(str, "mon", 3)) res=0;
      else if (STRNEQ(str, "tue", 3)) res=1;
      else if (STRNEQ(str, "wed", 3)) res=2;
      else if (STRNEQ(str, "thr", 3)) res=3;
      else if (STRNEQ(str, "fri", 3)) res=4;
      else if (STRNEQ(str, "sat", 3)) res=5;
      else if (STRNEQ(str, "sun", 3)) res=6;
      return res;
}

const char *daysofweek[7] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
//////////////////////////////////////////////////////////////////////////////////////////
#ifndef HAVE_BILLING
#ifndef MAKE_FOR
char *buildforstring=NULL;
#endif
#endif
//////////////////////////////////////////////////////////////////////////////////////////
// here is general command processing
// valid list is: save, exit, reload, shutdown, kill, debug, show connections, show config *
static pthread_mutex_t save_lock = PTHREAD_MUTEX_INITIALIZER;

int cLoad(struct cli_def *cli, const char *cmd, char **argv, int argc) {
      FILE *file;
      char *filename;

      if(argc==1) return CLI_ERROR;
      filename = argv[1];

      aLog(D_INFO, "Loading config from %s\n", filename);
      cli_error(cli, "Loading config from %s\n", filename);

      netams_mutex_lock(&save_lock);

      file = fopen(filename, "rt");
      if (file==NULL) {
            netams_mutex_unlock(&save_lock);
            return CLI_OK;
      }
      cli_file(cli, file, PRIVILEGE_UNPRIVILEGED, MODE_CONFIG);

      fclose(file);
      netams_mutex_unlock(&save_lock);

      return CLI_OK;
}

int cAutoSave(struct cli_def *cli, const char *cmd, char **argv, int argc){
      // this is for config auto-save feature
      // we must enable scheduler anyways and run "config changed" routine every ~minute
      char buffer[64];
      u_char no_flag=0;

      no_flag = CLI_CHECK_NO(argv[0]);
      if(no_flag) {
            sprintf(buffer, "no schedule oid 08FFFE");
            cli_error(cli, "autosave is disabled");
            is_autosave=0;
      } else {
            sprintf(buffer, "schedule oid 08FFFE action autosave-run time 62sec invisible");
            cli_error(cli, "autosave is enabled");
            is_autosave=1;
      }
      cli_run_command(CLI, buffer);
      return CLI_OK;
}

int cAutoSaveRun(struct cli_def *cli, const char *cmd, char **argv, int argc){
      if (when_config_changed.tv_sec!=0) {
            struct timeval now;
            gettimeofday(&now, NULL);
            if (now.tv_sec - when_config_changed.tv_sec >60) {
                  cSave(cli, cmd, argv, argc);
                  aLog(D_INFO,"Configuration file saved (autosave)\n");
            }
      }
      return CLI_OK;
}

int cSave(struct cli_def *cli, const char *cmd, char **argv, int argc){
      FILE *f;
      char tmp[265];

      sprintf(tmp, "%s.bak", config_file_name);

      netams_mutex_lock(&save_lock);
      rename(config_file_name, tmp);

      f=fopen(config_file_name, "wt");
      if (f==NULL)
            aLog(D_INFO, "config write failed: %s\n", strerror(errno));
      else {
            cli = cli_init();
            cli->client = f;
            cShowConfig(cli, NULL, NULL, 0);
            cli_done(cli);
            fclose(f);
      }
      netams_mutex_unlock(&save_lock);
      when_config_changed.tv_sec=0;
      return CLI_OK;
}

int cShowConfig(struct cli_def *cli, const char *cmd, char **argv, int argc){
      u_char flags=CFG_NONE;

      if (STRSTR(cmd, "unsecure"))
            flags|=CFG_NO_PASSWORDS;
      if (STRSTR(cmd, "oids"))
            flags|=CFG_SHOW_OIDS;
      if (STRSTR(cmd, "brief"))
            flags|=CFG_SHOW_BRIEF;

#ifdef HAVE_BILLING
        if (STRSTR(cmd, "billing")){
            if(Billing) Billing->ShowCfg(cli, flags);
            return CLI_OK;
      }
#endif

      // first we will output service-independent lines
      time_t t=time(NULL);
      cli_print(cli, "#%s", SHOW_VERSION);
      cli_print(cli, "#configuration built %s#begin", ctime(&t));
      cli_print(cli, "#global variables configuration");

      cli_bufprint(cli, "debug");
      if (aDebugIsSet(&debug, DEBUG_NONE)) cli_bufprint(cli, " none\n");
      else if (aDebugIsSet(&debug, DEBUG_ALL)) cli_bufprint(cli, " all\n");
      else {
            for (u_char i=1; i<63; i++)
                  if (aDebugIsSet(&debug, i)) cli_bufprint(cli, " %s", debug_list[i]);
            cli_bufprint(cli, "\n");
      }

      if (lang>=0 && lang<LANGUAGES_DEFINED)
            cli_print(cli, "language %s", language_str[lang]);

      if (is_autosave) cli_print(cli, "autosave");

      if(enable_password) cli_print(cli, "\nenable crypted %s", enable_password);

      Users->listUsersCfg(cli, flags);
      // then check if various services are registered and call config lines output for each of them
      cli_print(cli, "\n#services configuration\n");

      Services->ShowCfg(cli, flags);

      // end of output
      cli_print(cli, "\n#end");

      return CLI_OK;
}

int cDebug(struct cli_def *cli, const char *cmd, char **argv, int argc){
      u_char i=1;
      u_char no_flag=0;

      no_flag = CLI_CHECK_NO(argv[0]);
      if(no_flag) i++;

      if (STREQ(argv[i], "?")) {
            cli_print(cli, "turning %s debugging on following action:", no_flag?"OFF":"ON");
            for (u_char j=0; j<=63; j++)
                  if (debug_list[j])
                        cli_print(cli, "   %12s | %s", debug_list[j], debug_list_help[j]);
            return CLI_OK;
      }

      Connection *conn=(Connection*)cli->conn;
      for(; i<argc; i++) {
            if (!no_flag) {
                  if (aDebugAdd(&debug, argv[i])) {
                        if(conn) aDebugAdd(&conn->debug, argv[i]);
                        cli_error(cli, "debugging on %s is turned on", argv[i]);
                  }
                  else
                        cli_error(cli, "cannot debug on %s", argv[i]);
            }
            else {
                  if (aDebugRm(&debug, argv[i])) {
                        if(conn) aDebugRm(&conn->debug, argv[i]);
                        cli_error(cli, "debugging on %s is turned off", argv[i]);
                  }
                  else
                        cli_error(cli, "cannot un-debug on %s", argv[i]);
            }
      }
      #ifndef DEBUG
      cli_error(cli, "If you want enable debug compile it with DEBUG flag\n");
      #endif
      return CLI_OK;
}

int cRotate(struct cli_def *cli, const char *cmd, char **argv, int argc) {

      if (STREQ(argv[1], "log")) {
            if(!flag_log) {
                  cli_error(cli, "There is no log file");
                  return CLI_OK;
            }
            cli_error(cli, "Rotating log file %s", path_to_log);
            aLog(D_INFO, "Rotating log file %s\n",path_to_log);

            flag_log=0;
            fclose(LOGFILE);
            char filename[64],mytime[32];
                  time_t t;
                  time(&t);
                  strftime(mytime,32,"%Y-%m-%d_%H:%M",localtime(&t));
                  sprintf(filename,"%s.%s",path_to_log,mytime);
                  rename(path_to_log,filename);
                  LOGFILE=fopen(path_to_log, "at");
            flag_log=1;
      } else
            return CLI_ERROR;

      return CLI_OK;
}
/////////////////////////////////////////////////////////////////////////////////////////////
int netams_system(const char* command){
/* taken from :
   FreeBSD: src/lib/libc/stdlib/system.c,v 1.10 2002/03/22 21:53:10 obrien
   we do not wait for child process to complete
*/
        pid_t pid, savedpid;
        int pstat;
        struct sigaction ign, intact, quitact;
        sigset_t newsigblock, oldsigblock;

        if (!command)           /* just checking... */
                return(1);

        /*
         * Ignore SIGINT and SIGQUIT, block SIGCHLD. Remember to save
         * existing signal dispositions.
         */
        ign.sa_handler = SIG_IGN;
        (void)sigemptyset(&ign.sa_mask);
        ign.sa_flags = 0;
        (void)sigaction(SIGINT, &ign, &intact);
        (void)sigaction(SIGQUIT, &ign, &quitact);
        (void)sigemptyset(&newsigblock);
        (void)sigaddset(&newsigblock, SIGCHLD);
        (void)sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock);
        switch(pid = fork()) {
        case -1:                        /* error */
                break;
        case 0:                         /* child */
                /*
                 * Restore original signal dispositions and exec the command.
                 */
                (void)sigaction(SIGINT, &intact, NULL);
                (void)sigaction(SIGQUIT,  &quitact, NULL);
                (void)sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
                execl("/bin/sh", "sh", "-c", command, (char *)NULL);
                _exit(127);
        default:                        /* parent */
                savedpid = pid;
                /*do {
                        pid = _wait4(savedpid, &pstat, 0, (struct rusage *)0);
                } while (pid == -1 && errno == EINTR);
                */
                break;
        }
        (void)sigaction(SIGINT, &intact, NULL);
        (void)sigaction(SIGQUIT,  &quitact, NULL);
        (void)sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
        return(pid == -1 ? -1 : pstat);
}
/////////////////////////////////////////////////////////////////////////////////////////////
int cSchedule (struct cli_def *cli, const char *cmd, char **argv, int argc) {
      u_char no_flag;

      no_flag = CLI_CHECK_NO(argv[0]);
      if(no_flag) {
            argv=&argv[1];
            argc--;
      }
      if(!sSched) {
            if(no_flag) return CLI_OK;
            cli_set_configmode(CLI, MODE_CONFIG, NULL);
            cli_run_command(CLI, "service scheduler");
            sSched->Start();
      }
      //remove schedule world
      argc--;
      argv=&argv[1];
      return sSched->ProcessCfg(cli, argv, argc, no_flag);
}
/////////////////////////////////////////////////////////////////////////////////////////////

Generated by  Doxygen 1.6.0   Back to index