Esempio n. 1
0
leaf *build(char *expr, hashtab *h)
{
  lstack s;
  char opr;
  int i = -1, num;
  char str[MAX_STR];
  leaf *l = NULL, *r = NULL, *tmp = NULL;
  
  lstack_init(&s, 1024);
  
  while (expr[++i])
    {
      if (is_digit(expr[i]))
	{
	  num = get_number(expr, &i);
	  l = new_num_leaf(num, INT, NULL, NULL, -1);
	  lpush(&s, l);
	}
      else
	if (is_opr(expr[i]))
	  {
	    lpop(&s, &r);
	    lpop(&s, &l);
	    
	    //Optimization : reducing the amount of registers !!
	    if ((expr[i] == '+' || expr[i] == '*') && l->typ == INT && r->typ != INT) 
	      tmp = l, l = r, r = tmp;

	    l = new_num_leaf(expr[i], CHAR, l, r, get_reg_num(l, r));
	    lpush(&s, l);
	  }
	else
	  if (is_alpha(expr[i]))
	    {
	      get_string(expr, str, &i);
	      
	      if (search(h, str))
		{
		  lpop(&s, &r);	  
		  r->reg = 1; //Premice to register allocation !!!
		  l = new_str_leaf(str, FUNC, NULL, r, 1);
		  lpush(&s, l);
		}
	      else //If not a function then a variable identifier ! [extend the grammar]
		{
		  l = new_str_leaf(str, VAR, NULL, NULL, -1);
		  lpush(&s, l);
		}
	    }
    }
   
  lstack_free(&s);

  return l;
}
Esempio n. 2
0
int main(void) {
  ACData tk = make_token("barf");
  ACData n = make_int(3);
  ACData bs = give_binding(tk,n);
  ACData tk2 = make_token("frab");
  ACData n2 = make_int(-3);
  ACData bs2 = give_binding(tk2,n2);
  ACData bs3, bs4;
  ACData t,l;
  bs3 = give_overriding(bs,bs2);
  bs4 = give_disjoint_union(bs3,bs2);
  print_ac_data(bs3);
  t = make_tuple(tk,bs3);
  print_ac_data(t);
  printf("\n");
  l = make_list(tk,bs3);
  print_ac_data(l);
  printf("\n");
  l = lpush(l,l);
  print_ac_data(l);
  printf("\n");
  l = lpop(l);
  print_ac_data(l);
  printf("\n");
  return 0;
}
Esempio n. 3
0
int parse_header(FILE *f, llist *l) {
  msg_header h;
  char s[MAX_FBUFFER_SIZE];

  if (!feof(f)) { 
    fgets((char *)s, MAX_FBUFFER_SIZE, f);
    strchop(s);
  }

  while ((strcmp(s,"")!=0) && (!feof(f))) {
    if (strstr(s, "From: ")) {
      char *tmp = strstr(s,": ")+2;
      if (tmp) strncpy(h.from, tmp, MAX_HINFO_SIZE);
    } else if (strstr(s, "Subject: ")) {
      char *tmp = strstr(s,": ")+2;
      if (tmp) strncpy(h.subject, tmp, MAX_HINFO_SIZE);
    } else if (strstr(s, "To: ")) {
      char *tmp = strstr(s,": ")+2;
      if (tmp) strncpy(h.to, tmp, MAX_HINFO_SIZE);
    } else if (strstr(s, "Date: ")) {
      char *tmp = strstr(s,": ")+2;
      if (tmp) strncpy(h.date, tmp, MAX_HINFO_SIZE);
    }
    fgets((char *)s, MAX_FBUFFER_SIZE, f);
    strchop(s);
  }
  h.body_offset = ftell(f);
  return(lpush(l, &h));
}
Esempio n. 4
0
int run_task(task_type_t type, metric_type_t metric, task_option_t *options, char *id) {
  switch (type) {
    case PROCESS:
      return handle_process(metric, options, id);
    case DIRECTORY:
      return handle_directory(options, id);
    case DISK:
      return handle_disk(metric, options, id);
    case SWAP:
      return handle_swap(id);
    case LOAD:
      return handle_load(id);
    case TOTAL:
      return handle_total(id, metric);
    default: {
      // We've been passed an incorrectly initialized task. Shouldn't happen, but handle
      // for debugging. Plus it gets GCC off my case.
      task_report_t report;
      init_task_report(&report, id, type, metric);
      sprintf(report.message, "FATAL CAUSE INVALID_TASK");
      lpush(&reports, &report);
      return NOTGIOS_GENERIC_ERROR;
    }
  }
}
Esempio n. 5
0
void
dsend(int idx, dbuf_t * d)
{
  debug(DBG_GLOBAL, 5, "pushing %d bytes for index %d", d->dsize, idx);
  debug_dump(DBG_GLOBAL, 100, d->buf, d->dsize);
  lpush(&cdata[idx].xmit_list, d);
  ufds[idx].events |= POLLOUT;
  // Will be unlocked by the send mechanism
  dlock(d);
}
Esempio n. 6
0
/*
 * Momentary layer
 */
void layer_momentary(uint8_t pressed, const struct key *key)
{
    const uint8_t usage = pgm_read_byte(&key->usage);

    if (pressed) {
        Config.keys.mods.dumb |=  pdata8(key, struct mods, req)
                               & ~pdata8(key, struct mods, ign);
        lpush(usage);

    } else {
Esempio n. 7
0
int handle_total(char *id, metric_type_t metric) {
  task_report_t report;
  init_task_report(&report, id, PROCESS, metric);

  int retval;
  switch (metric) {
    case MEMORY:
      retval = total_memory_collect(&report);
      if (retval == NOTGIOS_UNSUPP_DISTRO) RETURN_UNSUPPORTED_DISTRO(report, id);
      write_log(LOG_DEBUG, "Task %s: Total memory info collected...\n", id);
      break;
    case CPU:
      retval = total_cpu_collect(&report);
      if (retval == NOTGIOS_UNSUPP_DISTRO) RETURN_UNSUPPORTED_DISTRO(report, id);
      write_log(LOG_DEBUG, "Task %s: Total CPU usage collected...\n", id);
      break;
    case IO:
      // This is currently unimplemented.
      retval = total_io_collect(&report);
      break;
    default:
      // We've been passed a task containing invalid options. Shouldn't happen, but handle it
      // for debugging.
      sprintf(report.message, "FATAL CAUSE INVALID_TASK");
      lpush(&reports, &report);
      return NOTGIOS_GENERIC_ERROR;
  }

  if (retval == NOTGIOS_UNSUPP_TASK) {
    write_log(LOG_DEBUG, "Task %s: Received an unsupported task. Removing...\n", id);
    sprintf(report.message, "FATAL CAUSE UNSUPPORTED_TASK");
    lpush(&reports, &report);
    return NOTGIOS_TASK_FATAL;
  }

  write_log(LOG_DEBUG, "Task %s: Enqueuing report an returning...\n", id);
  lpush(&reports, &report);
  return NOTGIOS_SUCCESS;
}
Esempio n. 8
0
int redis_list::lpush(const char* key, const char* first_value, ...)
{
	std::vector<const char*> values;
	values.push_back(first_value);

	va_list ap;
	va_start(ap, first_value);
	const char* value;

	while ((value = va_arg(ap, const char*)) != NULL)
		values.push_back(value);
	va_end(ap);

	return lpush(key, values);
}
Esempio n. 9
0
 void Ardb::WakeBlockedConnCallback(Channel* ch, void* data)
 {
     if (NULL != ch)
     {
         Context* ctx = (Context*) data;
         if (-1 != ctx->block->blocking_timer_task_id)
         {
             ch->GetService().GetTimer().Cancel(ctx->block->blocking_timer_task_id);
             ctx->block->blocking_timer_task_id = -1;
         }
         if (ctx->block->dest_key.empty())
         {
             ctx->reply.type = REDIS_REPLY_ARRAY;
             if (!ctx->block->waked_value.empty())
             {
                 RedisReply& r1 = ctx->reply.AddMember();
                 RedisReply& r2 = ctx->reply.AddMember();
                 fill_str_reply(r1, ctx->block->waked_key.key);
                 fill_str_reply(r2, ctx->block->waked_value);
                 RedisCommandFrame lpop("lpop");
                 lpop.AddArg(ctx->block->waked_key.key);
                 g_db->m_master.FeedSlaves(ctx->currentDB, lpop);
             }
         }
         else
         {
             if (!ctx->block->waked_value.empty())
             {
                 fill_str_reply(ctx->reply, ctx->block->waked_value);
                 RedisCommandFrame lpush("lpush");
                 lpush.AddArg(ctx->block->dest_key);
                 lpush.AddArg(ctx->block->waked_value);
                 g_db->LPush(*ctx, lpush);
                 RedisCommandFrame lpop("lpop");
                 lpop.AddArg(ctx->block->waked_key.key);
                 g_db->m_master.FeedSlaves(ctx->currentDB, lpop);
                 g_db->m_master.FeedSlaves(ctx->currentDB, lpush);
             }
             else
             {
                 ctx->reply.type = REDIS_REPLY_NIL;
             }
         }
         ch->Write(ctx->reply);
         g_db->ClearBlockKeys(*ctx);
         ch->AttachFD();
     }
 }
Esempio n. 10
0
void
timer_enqueue_internal(uint32_t timer_idx, uint32_t msec)
{
  timerwheel_entry_t *timers = (timerwheel_entry_t *) timers_list->buf;
  uint32_t ticks = (msec * TIMER_WHEEL_TICKS_PER_SEC / 1000);
  uint32_t next_wheel_idx = (timerwheel_idx + ticks) % TIMER_WHEEL_SIZE;

  if(ticks >= TIMER_WHEEL_SIZE) {
    debug(DBG_TIMERS, 0, "%d ticks is bigger than the wheel size", ticks);
    return;
  }
  debug(DBG_TIMERS, 10, "enqueue index %d with interval %d", timer_idx, msec);
  debug(DBG_TIMERS, 10, "current tw index: %d, ticks from it: %d",
        timerwheel_idx, ticks);
  // These two fields are primarily used to remove the timer beforehand,
  // but rpush is important :)
  timers[timer_idx].wheel_li =
    lpush(&timerwheel[next_wheel_idx], (void *) ((long int) timer_idx));
  timers[timer_idx].wheel_idx = next_wheel_idx;
  debug(DBG_TIMERS, 10, "Pushed timer index %d onto wheel index %d",
        timer_idx, next_wheel_idx);
}
Esempio n. 11
0
/** \brief Set the argument offsets for a function, then kick off compiling
 *  of the function
 *
 *  \param prevarg  - Last argument
 *  \param currfn   - Current function
 */
void setlocvar(SYMBOL *prevarg,SYMBOL *currfn)
{
    int lgh,where;
    int *iptr;
    SYMBOL *copyarg;
    int argnumber;
    char buffer2[120];
    unsigned char tester;

	lgh = 0;  /* Initialise it */
    if ( prevarg != NULL && currfn->prototyped == 0 ) {
        StoreFunctionSignature(prevarg);
    }

    argnumber=currfn->prototyped;
    /*
     *      If we have filled up our number of arguments, then pretend
     *      we don't have any..nasty, nasty
     */
    if (argnumber==(MAXARGS-1)) argnumber=0;
    else   if (argnumber) argnumber=1;
    /*
     *      Dump some info about defining the function etc
     */
    if (verbose){
        toconsole();
        outstr("Defining function: "); outstr(currfn->name); nl();
        tofile();
    }

    nl();prefix();outname(currfn->name,dopref(currfn));col();nl();  /* print function name */

    infunc=1;       /* In a function for sure! */
    copyarg=prevarg;

    if ( ( (currfn->flags&SHARED) && makeshare ) || sharedfile ) {
        /* Shared library definition, offset the stack */
        where= 2 +shareoffset;
    } else
        where = 2 ;
    /* If we use frame pointer we preserve previous framepointer on entry
     * to each function
     */
#ifdef USEFRAME
	if (useframe) where+=2;
#endif
    while ( prevarg ) {
        lgh = 2 ;      /* Default length */
        /* This is strange, previously double check for ->type */
        if ( prevarg->type == LONG && prevarg->ident != POINTER )
            lgh=4;
        if ( prevarg->type == DOUBLE && prevarg->ident != POINTER )
            lgh=6;
		/* Far pointers */
		if ( (prevarg->flags&FARPTR)==FARPTR && prevarg->ident == POINTER)
			lgh=4;
        prevarg->size=lgh;
#ifdef CODSWALLOP
        /* All pointers are pushed onto the stack for functions as 4 bytes, if
         * needed, near pointers are padded out to compensate for this by dummy
         * loading with zero, this allows us to have one set of routines to
         * cope with this and hence solve a lot of duplication
         */
        if (prevarg->ident == POINTER && lpointer) lgh=4;
        prevarg->size=lgh;
#endif
        /*
         * Check the definition against prototypes here...
         */
        if (argnumber) {
            tester=CalcArgValue(prevarg->type,prevarg->ident,prevarg->flags);
            if (currfn->args[argnumber] != tester ) {
                if (currfn->args[argnumber] != PELLIPSES ) {
                    if (currfn->args[argnumber] == 0 ) {
                        warning(W_2MADECL);
                    } else {
                        if ( (currfn->args[argnumber]&PMASKSIGN) == (tester&PMASKSIGN) ) {
                            warning(W_SIGNARG);
                        } else {
                            error(E_ARGMIS1,currfn->name,currfn->prototyped-argnumber+1, ExpandArgValue(tester,buffer2,prevarg->tag_idx) );
                            error(E_ARGMIS2,ExpandArgValue(currfn->args[argnumber],buffer2, currfn->tagarg[argnumber]));
                        }
                    }
                }
            }
            argnumber++;
        }
        iptr = &prevarg->offset.i ;
        prevarg = prevarg->offset.p ;           /* follow ptr to prev. arg */
        *iptr = where ;                                         /* insert offset */
        where += lgh ;                                          /* calculate next offset */
    }
#ifdef USEFRAME
	pushframe();
#endif
	currfn->handled=YES;
    if (currfn->prototyped==1 && (currfn->flags&REGCALL) ) {
        /*
         * Fast call routine..
         */
        if (lgh==2) zpush();
        else if (lgh==4) lpush();
        else if (lgh==6) dpush();
        /* erk, if not matched, dodgy type! */
        copyarg->offset.i=-lgh;
        where=2;
    }

    stackargs=where;
    lstdecl=0;       /* Set number of local statics to zero */
    if ( statement() != STRETURN ) {
        if (lstdecl) postlabel(lstlab);
        lstdecl=0;
        /* do a statement, but if it's a return, skip */
        /* cleaning up the stack */
        leave(NO,NO) ;
    }
    CleanGoto();
    /* Asz80 needs a label at the end to sort out local symbols */
	if (asxx) {
        nl();prefix();
		outstr("smce_");
		outname(currfn->name,NO);
		col();nl();
	}
#ifdef INBUILT_OPTIMIZER
    generate();
#endif
    infunc = 0 ;                    /* not in fn. any more */
}
Esempio n. 12
0
int handle_process(metric_type_t metric, task_option_t *options, char *id) {
  int keepalive = 0;
  uint16_t pid;
  char *pidfile, *runcmd;
  task_report_t report;
  init_task_report(&report, id, PROCESS, metric);

  // Pull out options.
  // FIXME: Need to go over this again to make sure all necessary validation of parameters
  // is performed.
  for (int i = 0; i < NOTGIOS_MAX_OPTIONS; i++) {
    task_option_t *option = &options[i];
    switch (option->type) {
      case KEEPALIVE:
        keepalive = strcmp(option->value, "TRUE") ? 0 : 1;
        break;
      case PIDFILE:
        pidfile = option->value;
        break;
      case RUNCMD:
        runcmd = option->value;
        break;
      case EMPTY:
        // User chose not to specify an option. This is fine, move on.
        break;
      default:
        // We've been passed a task containing invalid options. Shouldn't happen, but handle
        // it for debugging.
        sprintf(report.message, "FATAL CAUSE INVALID_TASK");
        lpush(&reports, &report);
        return NOTGIOS_GENERIC_ERROR;
    }
  }
  write_log(LOG_DEBUG, "Task %s: Finished parsing arguments for process task...\n", id);

  // Figure out process running/not running situation.
  if (keepalive) {
    FILE *file = fopen(pidfile, "w+");
    if (!file) {
      // We cannot write to the given pidfile path. Most likely the directory just
      // doesn't exist, but I'm defining this as an unrecoverable error, so send a message
      // to the frontend and remove the task.
      write_log(LOG_ERR, "Task %s: Pidfile inaccessible for keepalive process...\n", id);
      sprintf(report.message, "FATAL CAUSE NO_PIDFILE");
      lpush(&reports,  &report);
      return NOTGIOS_TASK_FATAL;
    }
    write_log(LOG_DEBUG, "Task %s: Successfully opened pidfile for keepalive process...\n", id);

    uint16_t *tmp_pid = hash_get(&children, id);
    if (tmp_pid) {
      write_log(LOG_DEBUG, "Task %s: Keepalive Process is already running...\n", id);
      pid = *tmp_pid;
      fprintf(file, "%hu", pid);
    } else {
      pid = fork();
      if (pid) {
        write_log(LOG_DEBUG, "Task %s: Forked...\n", id);
        uint16_t *pid_cpy = malloc(sizeof(uint16_t));
        *pid_cpy = pid;

        // Put the new pid into the children hash, update the pidfile, and just make
        // sure we aren't doing all of this for nothing.
        int retval = hash_put(&children, id, pid_cpy);
        fprintf(file, "%hu", pid);
        if (retval == HASH_FROZEN) return NOTGIOS_IN_SHUTDOWN;
      } else {
        int elem = 0;
        char *args[NOTGIOS_MAX_ARGS];
        memset(args, 0, sizeof(char *) * NOTGIOS_MAX_ARGS);

        // Just sleep for a tiny bit to make sure our pid got into the children table.
        // No validation has been done on the run command, so, odds are, it won't work
        // and exec will fail. If so, need to make sure our pid is in the children table
        // so that the SIGCHLD handler will know what to do with our exit status.
        sleep(0.1);

        // Get our base command and arguments.
        char *path = strtok(runcmd, "\t"), *arg;
        while ((arg = strtok(NULL, "\t")) && elem < NOTGIOS_MAX_ARGS) args[elem++] = arg;

        // Moment of truth!
        execv(path, args);
        exit(NOTGIOS_EXEC_FAILED);
      }
    }
    fclose(file);
  } else {
    uint16_t other_pid;
    FILE *file = fopen(pidfile, "r");
    if (file) {
      // We can access the file.
      int retval = fscanf(file, "%hu", &other_pid);
      fclose(file);
      write_log(LOG_DEBUG, "Task %s: Got pid for watched process...\n", id);

      if (retval && retval != EOF) {
        // We read the pid successfully.
        retval = kill(other_pid, 0);
        if (!retval) {
          // The process is running!
          write_log(LOG_DEBUG, "Task %s: Watched process is still running...\n", id);
          pid = other_pid;
        } else {
          // The process is not currently running, enqueue a report saying this, then return.
          write_log(LOG_ERR, "Task %s: Kill revealed watched process is not running...\n", id);
          sprintf(report.message, "ERROR CAUSE PROC_NOT_RUNNING");
          lpush(&reports, &report);
          return NOTGIOS_SUCCESS;
        }
      } else {
        // The process is not currently running, enqueue a report saying this, then return.
        write_log(LOG_ERR, "Task %s: Pidfile not formatted correctly for watched process...\n", id);
        sprintf(report.message, "ERROR CAUSE PROC_NOT_RUNNING");
        lpush(&reports, &report);
        return NOTGIOS_SUCCESS;
      }
    } else {
      // We can't access the file. I'm defining this as an unrecoverable error, so
      // send a message to the frontend, and then remove the task.
      write_log(LOG_ERR, "Task %s: Pidfile not accessible for watched process...\n", id);
      sprintf(report.message, "FATAL CAUSE NO_PIDFILE");
      lpush(&reports, &report);
      return NOTGIOS_TASK_FATAL;
    }
  }

  // Collect metrics.
  int retval;
  switch (metric) {
    case MEMORY:
      retval = process_memory_collect(pid, &report);
      if (retval == NOTGIOS_NOPROC && keepalive) {
        if (check_statm()) {
          // FIXME: This was written before the child handler was figured out. Could need to revisit this
          // after implementing the child handler.
          // Since we're keeping alive, this most likely means that the user gave us an invalid command.
          // Send an error message, and the frontend will eventually kill the task if necessary.
          write_log(LOG_ERR, "Task %s: Watched/Keepalive process is not running for collection...\n", id);
          sprintf(report.message, "ERROR CAUSE PROC_NOT_RUNNING");
        } else {
          // We can't even read from /proc/self/statm, which should be guaranteed to work on any version of
          // linux that supports statm at all. Let the front end know that we're running on an unsupported
          // distro.
          RETURN_UNSUPPORTED_DISTRO(report, id);
        } 
      } else {
        write_log(LOG_DEBUG, "Task %s: Memory info collected...\n", id);
      }
      break;
    case CPU:
      retval = process_cpu_collect(pid, &report);
      if (retval == NOTGIOS_NOPROC) {
        if (check_stat()) {
          write_log(LOG_ERR, "Task %s: Watched/Keepalive process is not running for collection...\n", id);
          sprintf(report.message, "ERROR CAUSE PROC_NOT_RUNNING");
        } else {
          // We can't even read from /proc/self/stat, which means it either doesn't exist, or we don't
          // support the format it's using. Either way, we're done.
          RETURN_UNSUPPORTED_DISTRO(report, id);
        }
      } else if (retval == NOTGIOS_UNSUPP_DISTRO) {
        // Collection function encountered an error condition that suggests we're running on an
        // unsupported distro.
        RETURN_UNSUPPORTED_DISTRO(report, id);
      } else {
        write_log(LOG_DEBUG, "Task %s: CPU Time collected...\n", id);
      }
      break;
    case IO:
      // This is currently unimplemented.
      retval = process_io_collect(pid, &report);
      break;
    default:
      // We've been passed a task containing invalid options. Shouldn't happen, but handle it
      // for debugging.
      sprintf(report.message, "FATAL CAUSE INVALID_TASK");
      lpush(&reports, &report);
      return NOTGIOS_GENERIC_ERROR;
  }

  if (retval == NOTGIOS_UNSUPP_TASK) {
    write_log(LOG_DEBUG, "Task %s: Received an unsupported task. Removing...");
    sprintf(report.message, "FATAL CAUSE UNSUPPORTED_TASK");
    lpush(&reports, &report);
    return NOTGIOS_TASK_FATAL;
  }

  // Enqueue metrics for sending.
  write_log(LOG_DEBUG, "Task %s: Enqueuing report and returning...\n", id);
  lpush(&reports, &report);
  return NOTGIOS_SUCCESS;
}
Esempio n. 13
0
int handle_directory(task_option_t *options, char *id) {
  char *path = NULL;
  task_report_t report;
  init_task_report(&report, id, DIRECTORY, MEMORY);

  // Pull out options
  for (int i = 0; i < NOTGIOS_MAX_OPTIONS; i++) {
    task_option_t *option = &options[i];
    switch (option->type) {
      case PATH:
        path = option->value;
        break;
      case EMPTY:
        // There's only one option for directory tasks, so this will be the most common branch.
        break;
      default:
        // We've been passed a task containing invalid options. Shouldn't happen, but handle
        // it for debugging.
        sprintf(report.message, "FATAL CAUSE INVALID_TASK");
        lpush(&reports, &report);
        return NOTGIOS_GENERIC_ERROR;
    }
  }
  write_log(LOG_DEBUG, "Task %s: Finished parsing arguments for directory task...\n", id);

  // Perform some error handling on the given path.
  if (!path) {
    // The server should take care of making sure this doesn't happen, but the directory option
    // wasn't sent.
    write_log(LOG_ERR, "Task %s: Recevied directory task with no path option...\n", id);
    sprintf(report.message, "FATAL CAUSE TASK_MISSING_OPTIONS");
    lpush(&reports, &report);
    return NOTGIOS_TASK_FATAL;
  } else if (access(path, F_OK)) {
    // We can't access the directory for some reason.
    write_log(LOG_ERR, "Task %s: Cannot access directory...\n", id);
    if (errno == EACCES || errno == ENOENT) sprintf(report.message, "FATAL CAUSE DIR_NOT_ACCESSIBLE");
    else if (errno == ELOOP) sprintf(report.message, "FATAL CAUSE DIR_INFINITE_LOOP");
    else if (errno == ENAMETOOLONG) sprintf(report.message, "FATAL CAUSE DIR_NAME_TOO_LONG");
    else sprintf(report.message, "FATAL CAUSE UNKNOWN");
    lpush(&reports, &report);
    return NOTGIOS_TASK_FATAL;
  }

  // Recursively calculate the directory size.
  write_log(LOG_DEBUG, "Task %s: Calculating directory size...\n", id);
  long retval = directory_memory_collect(path);
  if (retval >= 0) {
    report.value = (double) retval;
    report.time_taken = time(NULL);
  } else if (retval == NOTGIOS_BAD_ACCESS) {
    write_log(LOG_ERR, "Task %s: Access was refused for a subdirectory...\n", id);
    sprintf(report.message, "FATAL CAUSE SUBDIR_NOT_ACCESSIBLE");
    lpush(&reports, &report);
    return NOTGIOS_TASK_FATAL;
  } else if (retval == NOTGIOS_NO_FILES) {
    write_log(LOG_ERR, "Task %s: Failed to open a file due to too many files being open...\n", id);
    sprintf(report.message, "ERROR CAUSE TOO_MANY_FILES");
  }

  // Enqueue metrics for sending.
  write_log(LOG_DEBUG, "Task %s: Enqueuing report and returning...\n", id);
  lpush(&reports, &report);
  return NOTGIOS_SUCCESS;
}