files/fcron.conf
convert-fcrontab
doc/stylesheets/fcron-doc.dsl
+PREVIOUS_VERSION
+doc/fcron-doc.mod
+exe_list_test
ifeq ($(FCRONDYN), 1)
LIBOBJS := socket.o $(LIBOBJS)
endif
-OBJSD := fcron.o subs.o save.o temp_file.o log.o database.o job.o conf.o $(LIBOBJS)
+OBJSD := fcron.o subs.o save.o temp_file.o log.o database.o job.o conf.o u_list.o exe_list.o lavg_list.o $(LIBOBJS)
OBJSTAB := fcrontab.o subs.o save.o temp_file.o log.o fileconf.o allow.o read_string.o
OBJSDYN := fcrondyn.o subs.o log.o allow.o read_string.o
OBJCONV := convert-fcrontab.o subs.o save.o log.o
convert-fcrontab: $(OBJCONV)
$(CC) $(CFLAGS) -o $@ $(OBJCONV) $(LIBS)
+exe_list_test: exe_list.o u_list.o exe_list_test.o log.o subs.o
+ $(CC) $(CFLAGS) -o $@ exe_list.o u_list.o exe_list_test.o log.o subs.o $(LIBS)
+
%.o: $(SRCDIR)/%.c $(HEADERSALL) $(SRCDIR)/%.h
$(CC) $(CFLAGS) -DPIDFILE="\"${PIDFILE}\"" \
-DFIFOFILE="\"${FIFOFILE}\"" -DETC="\"${ETC}\"" \
struct job_t *prev_j;
int i, k;
struct cl_t **s_a = NULL;
+ exe_t *e = NULL;
+ lavg_t *l = NULL;
file = file_base;
while ( file != NULL) {
continue;
}
- for ( i = 0; i < exe_num; i++)
- if ( exe_array[i].e_line != NULL &&
- exe_array[i].e_line->cl_file == file ) {
+ for ( e = exe_list_first(exe_list) ; e != NULL ; e = exe_list_next(exe_list) )
+ if ( e->e_line != NULL &&
+ e->e_line->cl_file == file ) {
/* we set the e_line to NULL, as so we know in wait_chld()
* and wait_all() the corresponding file has been removed.
* Plus, we decrement serial_running and lavg_serial_running
* as we won't be able to do it at the end of the job */
- if ( ( is_serial(exe_array[i].e_line->cl_option) ||
- is_serial_once(exe_array[i].e_line->cl_option) ) &&
- ! is_lavg(exe_array[i].e_line->cl_option) )
+ if ( ( is_serial(e->e_line->cl_option) ||
+ is_serial_once(e->e_line->cl_option) ) &&
+ ! is_lavg(e->e_line->cl_option) )
serial_running--;
- else if ( is_serial(exe_array[i].e_line->cl_option) &&
- is_lavg(exe_array[i].e_line->cl_option) )
+ else if ( is_serial(e->e_line->cl_option) &&
+ is_lavg(e->e_line->cl_option) )
lavg_serial_running--;
- exe_array[i].e_line = NULL;
+ e->e_line = NULL;
}
/* free lavg queue entries */
- i = 0;
- while (i < lavg_num)
- if ( lavg_array[i].l_line->cl_file == file ) {
- debug("removing %s from lavg queue",
- lavg_array[i].l_line->cl_shell);
- lavg_array[i].l_line->cl_numexe--;
- if (i < --lavg_num) {
- lavg_array[i] = lavg_array[lavg_num];
- lavg_array[lavg_num].l_line = NULL;
- }
- else
- lavg_array[i].l_line = NULL;
+ for (l = lavg_list_first(lavg_list) ; l != NULL ; l = lavg_list_next(lavg_list))
+ if ( l->l_line->cl_file == file ) {
+ debug("removing %s from lavg queue", l->l_line->cl_shell);
+ lavg_list_remove_cur(lavg_list);
}
- else
- i++;
/* free serial queue entries */
for ( i = 0; i < serial_array_size; i++)
-vers="3.0.5"
+vers="3.1.0"
vers_quoted="\"$vers\""
cat >>confdefs.h <<_ACEOF
#define VERSION $vers
AC_CONFIG_HEADER(config.h)
AC_PREREQ(2.57)
-vers="3.0.5"
+vers="3.1.0"
vers_quoted="\"$vers\""
AC_DEFINE_UNQUOTED(VERSION, $vers)
AC_DEFINE_UNQUOTED(VERSION_QUOTED, $vers_quoted)
#define BEGIN_NEXT_PERIOD 11 /* move_time_to()'s where possible value */
#define END_OF_INTERVAL 12 /* move_time_to()'s where possible value */
void run_serial_job(void);
-void run_lavg_job(int i);
+void run_lavg_job(lavg_t *l);
void run_queue_job(cl_t *line);
-void resize_exe_array(void);
#if ! defined(HAVE_SETENV) || ! defined(HAVE_UNSETENV)
}
void
-run_lavg_job(int i)
+run_lavg_job(lavg_t *l)
{
- run_queue_job(lavg_array[i].l_line);
+ run_queue_job(l->l_line);
- if ( is_serial(lavg_array[i].l_line->cl_option) )
+ if ( is_serial(l->l_line->cl_option) )
lavg_serial_running++;
- if (i < --lavg_num) {
- lavg_array[i] = lavg_array[lavg_num];
- lavg_array[lavg_num].l_line = NULL;
- }
- else
- lavg_array[i].l_line = NULL;
-
}
}
-void
-resize_exe_array(void)
- /* make exe_array bigger */
-{
- struct exe_t *ptr = NULL;
- short int old_size = exe_array_size;
-
- debug("Resizing exe_array");
- exe_array_size = (exe_array_size + EXE_GROW_SIZE);
-
- if ( (ptr = calloc(exe_array_size, sizeof(struct exe_t))) == NULL )
- die_e("could not calloc exe_array");
-
- memcpy(ptr, exe_array, (sizeof(struct exe_t) * old_size));
- free(exe_array);
- exe_array = ptr;
-}
-
-
void
run_queue_job(cl_t *line)
/* run a job */
{
+ exe_t e = { NULL, 0, 0 };
+
/* // */
/* debug("run_queue_job"); */
/* // */
- /* append job to the list of executed job */
- if ( exe_num >= exe_array_size )
- resize_exe_array();
-
- exe_array[exe_num].e_line = line;
- exe_num++;
+ e.e_line = line;
/* run the job */
- if ( run_job(&exe_array[exe_num-1]) != OK ) {
- /* The job could not be run: remove it from the exe_array */
- exe_array[exe_num-1].e_line->cl_numexe--;
- exe_array[exe_num-1].e_line = NULL;
- exe_num--;
+ if ( run_job(&e) == OK ) {
+ /* append job to the list of executed job */
+ exe_list_add(exe_list, &e);
+ line->cl_file->cf_running += 1;
}
}
/* WARNING : must be run before a set_next_exe() to get the strict option
* working correctly */
{
+ lavg_t *lavg_entry = NULL;
/* check if the line is already in the lavg queue
* (we consider serial jobs currently running as in the queue) */
/* // */
/* append job to the list of lavg job */
- if ( lavg_num >= lavg_array_size ) {
- if ( lavg_num >= lavg_queue_max ) {
- error_fd(info_fd, "Could not add job : lavg queue is full (%d jobs)."
- " Consider using options lavgonce, until, strict and/or "
- "fcron's option -q.", lavg_queue_max, line->cl_shell);
- if ( is_notice_notrun(line->cl_option) )
- mail_notrun(line, QUEUE_FULL, NULL);
- return;
- }
- else {
- struct lavg_t *ptr = NULL;
- short int old_size = lavg_array_size;
-
- debug("Resizing lavg_array");
- lavg_array_size = (lavg_array_size + LAVG_GROW_SIZE);
-
- if ( (ptr = calloc(lavg_array_size, sizeof(lavg_t))) == NULL )
- die_e("could not calloc lavg_array");
-
- memcpy(ptr, lavg_array, (sizeof(lavg_t) * old_size));
- free(lavg_array);
- lavg_array = ptr;
- }
+ lavg_entry = lavg_list_add_line(lavg_list, line);
+ if ( lavg_entry == NULL ) {
+ error_fd(info_fd, "Could not add job : lavg queue is full (%d jobs)."
+ " Consider using options lavgonce, until, strict and/or "
+ "fcron's option -q.", lavg_list->max_entries, line->cl_shell);
+ if ( is_notice_notrun(line->cl_option) )
+ mail_notrun(line, QUEUE_FULL, NULL);
+ return;
}
- lavg_array[lavg_num].l_line = line;
line->cl_numexe += 1;
set_run_if_late(line->cl_option);
if ( is_strict(line->cl_option) && line->cl_runfreq == 1) {
end_of_cur_int = mktime_no_dst(&ftime) + (line->cl_file->cf_tzdiff * 3600);
if ((line->cl_until > 0) && (line->cl_until + now < end_of_cur_int))
- lavg_array[lavg_num].l_until = line->cl_until + now;
+ lavg_entry->l_until = line->cl_until + now;
else {
- lavg_array[lavg_num].l_until = end_of_cur_int;
+ lavg_entry->l_until = end_of_cur_int;
clear_run_if_late(line->cl_option);
}
switch_back_timezone(orig_tz_envvar);
}
else
- lavg_array[lavg_num].l_until =
+ lavg_entry->l_until =
(line->cl_until > 0) ? now + line->cl_until : 0;
- lavg_num++;
}
wait_chld(void)
/* wait_chld() - check for job completion */
{
- short int i = 0;
int pid;
cl_t *line = NULL;
-
+ exe_t *e = NULL;
/* // */
/* debug("wait_chld"); */
while ( (pid = wait3(NULL, WNOHANG, NULL)) > 0 ) {
- i = 0;
- while ( i < exe_num ) {
+ for ( e = exe_list_first(exe_list) ; e != NULL ; e = exe_list_next(exe_list) ) {
- if (pid == exe_array[i].e_ctrl_pid) {
- if ( exe_array[i].e_line == NULL ) {
+ if (pid == e->e_ctrl_pid) {
+ if ( e->e_line == NULL ) {
/* the corresponding file has been removed from memory */
debug("job finished: pid %d", pid);
}
else {
- line = exe_array[i].e_line;
+ line = e->e_line;
/* debug("job finished: %s", line->cl_shell); */
line->cl_numexe -= 1;
line->cl_file->cf_running -= 1;
is_serial(line->cl_option) )
lavg_serial_running--;
}
- if (i < --exe_num) {
- exe_array[i] = exe_array[exe_num];
- exe_array[exe_num].e_line = NULL;
- }
- else
- exe_array[i].e_line = NULL;
+ exe_list_remove_cur(exe_list);
break;
}
-
- i++;
}
}
wait_all(int *counter)
/* return after all jobs completion. */
{
- short int i = 0;
int pid;
+ exe_t *e = NULL;
debug("Waiting for all jobs");
while ( (*counter > 0) && (pid = wait3(NULL, 0, NULL)) > 0 ) {
- i = 0;
- while ( i < exe_num ) {
- if (pid == exe_array[i].e_ctrl_pid) {
- if ( exe_array[i].e_line == NULL ) {
+ for ( e = exe_list_first(exe_list) ; e != NULL ; e = exe_list_next(exe_list) ) {
+ if (pid == e->e_ctrl_pid) {
+ if ( e->e_line == NULL ) {
/* the corresponding file has been removed from memory */
debug("job finished: pid %d", pid);
}
else {
- debug("job finished: %s", exe_array[i].e_line->cl_shell);
- exe_array[i].e_line->cl_numexe -= 1;
- exe_array[i].e_line->cl_file->cf_running -= 1;
+ debug("job finished: %s", e->e_line->cl_shell);
+ e->e_line->cl_numexe -= 1;
+ e->e_line->cl_file->cf_running -= 1;
- if ( is_serial_once(exe_array[i].e_line->cl_option) )
- clear_serial_once(exe_array[i].e_line->cl_option);
+ if ( is_serial_once(e->e_line->cl_option) )
+ clear_serial_once(e->e_line->cl_option);
}
- if (i < --exe_num) {
- exe_array[i] = exe_array[exe_num];
- exe_array[exe_num].e_line = NULL;
- }
- else
- exe_array[i].e_line = NULL;
+ exe_list_remove_cur(exe_list);
break;
}
- i++;
}
}
line->cl_shell, pid);
/* // */
- /* create an entry in exe_array */
- if ( exe_num >= exe_array_size )
- resize_exe_array();
+ /* create an entry in exe_list */
/* set line to NULL as this is not a line ... */
- exe_array[exe_num].e_line = NULL;
- exe_array[exe_num].e_ctrl_pid = pid;
- exe_num++;
+ exe_list_add_line(exe_list, NULL);
return;
}
* and return the time to sleep */
{
time_t tts = 0;
+ lavg_t *l = NULL;
#ifdef NOLOADAVG
- while ( lavg_num > 0 )
- run_lavg_job(0);
+ for ( l = lavg_list_first(lavg_list) ; l != NULL ; l = lavg_list_next(lavg_list) ) {
+ run_lavg_job(l);
+ lavg_list_remove_cur(lavg_list);
+ }
+
tts = time_to_sleep(lim);
return tts;
double l_avg[3]= {0, 0, 0};
/* first, check if some lines must be executed because of until */
- while ( i < lavg_num )
- if ( (lavg_array[i].l_line->cl_until > 0
- || lavg_array[i].l_line->cl_runfreq == 1)
- && lavg_array[i].l_until < now){
- if ( ! is_run_if_late(lavg_array[i].l_line->cl_option) ) {
- if ( ! is_nolog(lavg_array[i].l_line->cl_option) )
+ for ( l = lavg_list_first(lavg_list) ; l != NULL ; l = lavg_list_next(lavg_list) )
+ if ( (l->l_line->cl_until > 0 || l->l_line->cl_runfreq == 1)
+ && l->l_until < now) {
+ if ( ! is_run_if_late(l->l_line->cl_option) ) {
+ if ( ! is_nolog(l->l_line->cl_option) )
explain("Interval of execution exceeded : %s (not run)",
- lavg_array[i].l_line->cl_shell);
+ l->l_line->cl_shell);
/* set time of the next execution and send a mail if needed */
- if ( is_td(lavg_array[i].l_line->cl_option) &&
- is_notice_notrun(lavg_array[i].l_line->cl_option) )
- set_next_exe_notrun(lavg_array[i].l_line, LAVG);
+ if ( is_td(l->l_line->cl_option) &&
+ is_notice_notrun(l->l_line->cl_option) )
+ set_next_exe_notrun(l->l_line, LAVG);
else
- set_next_exe(lavg_array[i].l_line, NO_GOTO_LOG, -1);
+ set_next_exe(l->l_line, NO_GOTO_LOG, -1);
/* remove this job from the lavg queue */
- lavg_array[i].l_line->cl_numexe -= 1;
- if (i < --lavg_num) {
- lavg_array[i] = lavg_array[lavg_num];
- lavg_array[lavg_num].l_line = NULL;
- }
- else
- lavg_array[i].l_line = NULL;
-
+ l->l_line->cl_numexe -= 1;
+ lavg_list_remove_cur(lavg_list);
}
else {
- debug("until %s %d", lavg_array[i].l_line->cl_shell,
- lavg_array[i].l_until);
- run_lavg_job(i);
+ debug("until %s %d", l->l_line->cl_shell,
+ l->l_until);
+ run_lavg_job(l);
+ lavg_list_remove_cur(lavg_list);
}
- } else
- i++;
+ }
/* we do this set here as the nextexe of lavg line may change before */
tts = time_to_sleep(lim);
- if ( lavg_num == 0 )
+ if ( lavg_list->num_entries == 0 )
return tts;
if ( (i = getloadavg(l_avg, 3)) != 3 )
l_avg[0] *= 10;
l_avg[1] *= 10;
l_avg[2] *= 10;
- i = 0;
- while ( i < lavg_num ) {
+ for ( l = lavg_list_first(lavg_list) ; l != NULL ; l = lavg_list_next(lavg_list) ) {
/* check if the line should be executed */
if ( lavg_serial_running >= serial_max_running &&
- is_serial(lavg_array[i].l_line->cl_option) ) {
- i++;
+ is_serial(l->l_line->cl_option) ) {
continue;
}
- if ( ( is_land(lavg_array[i].l_line->cl_option)
- && ( l_avg[0] < lavg_array[i].l_line->cl_lavg[0]
- || lavg_array[i].l_line->cl_lavg[0] == 0 )
- && ( l_avg[1] < lavg_array[i].l_line->cl_lavg[1]
- || lavg_array[i].l_line->cl_lavg[1] == 0 )
- && ( l_avg[2] < lavg_array[i].l_line->cl_lavg[2]
- || lavg_array[i].l_line->cl_lavg[2] == 0 )
+ if ( ( is_land(l->l_line->cl_option)
+ && ( l_avg[0] < l->l_line->cl_lavg[0] || l->l_line->cl_lavg[0] == 0 )
+ && ( l_avg[1] < l->l_line->cl_lavg[1] || l->l_line->cl_lavg[1] == 0 )
+ && ( l_avg[2] < l->l_line->cl_lavg[2] || l->l_line->cl_lavg[2] == 0 )
)
||
- ( is_lor(lavg_array[i].l_line->cl_option)
- && ( l_avg[0] < lavg_array[i].l_line->cl_lavg[0]
- || l_avg[1] < lavg_array[i].l_line->cl_lavg[1]
- || l_avg[2] < lavg_array[i].l_line->cl_lavg[2] )
+ ( is_lor(l->l_line->cl_option)
+ && ( l_avg[0] < l->l_line->cl_lavg[0]
+ || l_avg[1] < l->l_line->cl_lavg[1]
+ || l_avg[2] < l->l_line->cl_lavg[2] )
)
) {
debug("lavg %s %s %.0f:%d %.0f:%d %.0f:%d",
- lavg_array[i].l_line->cl_shell,
- (is_lor(lavg_array[i].l_line->cl_option)) ? "or" : "and",
- l_avg[0], lavg_array[i].l_line->cl_lavg[0],
- l_avg[1], lavg_array[i].l_line->cl_lavg[1],
- l_avg[2], lavg_array[i].l_line->cl_lavg[2]);
- run_lavg_job(i);
-
- } else
- i++;
+ l->l_line->cl_shell,
+ (is_lor(l->l_line->cl_option)) ? "or" : "and",
+ l_avg[0], l->l_line->cl_lavg[0],
+ l_avg[1], l->l_line->cl_lavg[1],
+ l_avg[2], l->l_line->cl_lavg[2]);
+ run_lavg_job(l);
+ lavg_list_remove_cur(lavg_list);
+
+ }
}
- if ( lavg_num == 0 )
+ if ( lavg_list->num_entries == 0 )
return tts;
else
return (LAVG_SLEEP < tts) ? LAVG_SLEEP : tts;
# Build all the HTML, text and manual pages in all the languages
@(for i in $(LANGUAGES); \
do \
- make $$i/HTML/index.html $$i/txt/readme.txt $$i/man/fcron.8 ; \
+ test -d $(SRCDIR)/$$i/HTML || mkdir $(SRCDIR)/$$i/HTML ; \
+ test -d $(SRCDIR)/$$i/txt || mkdir $(SRCDIR)/$$i/txt ; \
+ test -d $(SRCDIR)/$$i/man || mkdir $(SRCDIR)/$$i/man ; \
+ make $(SRCDIR)/$$i/HTML/index.html $(SRCDIR)/$$i/txt/readme.txt \
+ $(SRCDIR)/$$i/man/fcron.8 ; \
+ done)
+
+doc-if-none:
+# Only generate the doc if there is none (e.g. if the sources came from git
+# and not a tarball)
+# The reason we don't try to generate the doc everytime is that we want the user
+# to be able to compile and install fcron without needing all the tools required
+#Â to generate the documentations.
+#
+# "make doc" will be called once at max, as all the tests will
+#Â succeed after the first time "make doc" is called
+ @(for i in $(LANGUAGES); \
+ do \
+ test -f $(SRCDIR)/$$i/HTML/index.html || make doc ; \
+ test -f $(SRCDIR)/$$i/txt/readme.txt || make doc ; \
+ test -f $(SRCDIR)/$$i/man/fcron.8 || make doc ; \
done)
# man/fcron.8 means in fact "build *all* the man pages"
install: install-staged perms
-install-staged: clean
+install-staged: doc-if-none clean
@(echo "Installing man pages in $(DESTDIR)$(DESTMAN)...")
@(for l in $(LANGUAGES); do \
if test "x$$l" = "xen"; then \
}
exe_t *
-exe_list_add(exe_list_t *list, struct cl_t *line)
+exe_list_add_line(exe_list_t *list, struct cl_t *line)
{
exe_t e = { NULL, 0, 0};
e.e_line = line; /* ANSI C does not allow us to directly replace NULL by line above*/
return (exe_t *) u_list_add( (u_list_t *) list, (u_list_entry_t *) &e);
}
+exe_t *
+exe_list_add(exe_list_t *list, exe_t *e)
+{
+ return (exe_t *) u_list_add( (u_list_t *) list, (u_list_entry_t *) e);
+}
+
exe_t *
exe_list_first(exe_list_t *list)
{
}
exe_t *
-exe_list_next(exe_list_t *list, exe_t *cur_entry)
+exe_list_next(exe_list_t *list)
+{
+ return (exe_t *) u_list_next((u_list_t *) list);
+}
+
+void
+exe_list_end_iteration(exe_list_t *list)
{
- return (exe_t *) u_list_next((u_list_t *) list, (u_list_entry_t *) cur_entry);
+ u_list_end_iteration((u_list_t *) list);
}
void
-exe_list_remove(exe_list_t *list, exe_t *entry)
+exe_list_remove_cur(exe_list_t *list)
{
- u_list_remove((u_list_t *) list, (u_list_entry_t *) entry);
+ u_list_remove_cur((u_list_t *) list);
}
exe_list_t *
/* functions prototypes */
extern exe_list_t *exe_list_init(void);
-/* WARNING: exe_t pointers returned by those functions are only
- * valid for as long as the list is not modified (add/remove) */
-extern exe_t *exe_list_add(exe_list_t *list, struct cl_t *line);
+extern exe_t *exe_list_add_line(exe_list_t *list, struct cl_t *line);
+extern exe_t *exe_list_add(exe_list_t *list, exe_t *e);
+/* WARNING: there should always be a unique iteration loop based on
+ * u_list_first()/u_list_next() running at any one time in the code */
extern exe_t *exe_list_first(exe_list_t *list);
-extern exe_t *exe_list_next(exe_list_t *list, exe_t *cur_entry);
-extern void exe_list_remove(exe_list_t *list, exe_t *entry);
+extern exe_t *exe_list_next(exe_list_t *list);
+extern void exe_list_end_iteration(exe_list_t *list);
+extern void exe_list_remove_cur(exe_list_t *list);
extern exe_list_t *exe_list_destroy(exe_list_t *list);
/* do not run more than this number of serial job simultaneously */
short int serial_max_running = SERIAL_MAX_RUNNING;
short int serial_queue_max = SERIAL_QUEUE_MAX;
-short int lavg_queue_max = LAVG_QUEUE_MAX;
-struct lavg_t *lavg_array; /* jobs waiting for a given system load value */
-short int lavg_array_size; /* size of lavg_array */
-short int lavg_num; /* number of job being queued */
+lavg_list_t *lavg_list; /* jobs waiting for a given system load value */
+short int lavg_queue_max = LAVG_QUEUE_MAX;
short int lavg_serial_running;/* number of serialized lavg job being running */
-struct exe_t *exe_array; /* jobs which are executed */
-short int exe_array_size; /* size of exe_array */
-short int exe_num; /* number of job being executed */
+exe_list_t *exe_list; /* jobs which are executed */
time_t begin_sleep; /* the time at which sleep began */
time_t now; /* the current time */
next_id = 0;
/* initialize exe_array */
- exe_num = 0;
- exe_array_size = EXE_INITIAL_SIZE;
- if ( (exe_array = calloc(exe_array_size, sizeof(struct exe_t))) == NULL )
- die_e("could not calloc exe_array");
+ exe_list = exe_list_init();
/* initialize serial_array */
serial_running = 0;
die_e("could not calloc serial_array");
/* initialize lavg_array */
- lavg_num = 0;
+ lavg_list = lavg_list_init();
+ lavg_list->max_entries = lavg_queue_max;
lavg_serial_running = 0;
- lavg_array_size = LAVG_INITIAL_SIZE;
- if ( (lavg_array = calloc(lavg_array_size, sizeof(lavg_t))) == NULL )
- die_e("could not calloc lavg_array");
#ifdef FCRONDYN
/* initialize socket */
#define __FCRON_H__
#include "global.h"
+#include "exe_list.h"
+#include "lavg_list.h"
#ifdef HAVE_CRYPT_H
#include <crypt.h>
extern short int serial_max_running;
extern short int serial_queue_max;
extern short int lavg_queue_max;
-extern struct exe_t *exe_array;
-extern short int exe_array_size;
-extern short int exe_num;
-extern struct lavg_t *lavg_array;
-extern short int lavg_array_size;
-extern short int lavg_num;
+extern exe_list_t *exe_list;
+extern lavg_list_t *lavg_list;
extern short int lavg_serial_running;
/* end of global variables */
struct job_t *j_next;
} job_t;
-typedef struct lavg_t {
- struct cl_t *l_line;
- time_t l_until; /* the timeout of the wait for load averages */
-} lavg_t;
-
-typedef struct exe_t {
- struct cl_t *e_line;
- pid_t e_ctrl_pid; /* pid of the fcron process controling the job */
- pid_t e_job_pid; /* pid of the job itself */
-} exe_t;
-
#if SIZEOF_TIME_T == SIZEOF_SHORT_INT
#define ATTR_SIZE_TIMET "h"
error_e("parent: could not close(pipe_pid_fd[1])");
exeent->e_ctrl_pid = pid;
- line->cl_file->cf_running += 1;
#ifdef CHECKRUNJOB
debug("run_job(): about to read grand-child pid...");
}
lavg_t *
-lavg_list_add(lavg_list_t *list, struct cl_t *line)
+lavg_list_add_line(lavg_list_t *list, struct cl_t *line)
{
lavg_t e = { NULL, 0};
e.l_line = line; /* ANSI C does not allow us to directly replace NULL by line above*/
return (lavg_t *) u_list_add( (u_list_t *) list, (u_list_entry_t *) &e);
}
+lavg_t *
+lavg_list_add(lavg_list_t *list, lavg_t *entry)
+{
+ return (lavg_t *) u_list_add( (u_list_t *) list, (u_list_entry_t *) entry);
+}
+
lavg_t *
lavg_list_first(lavg_list_t *list)
{
}
lavg_t *
-lavg_list_next(lavg_list_t *list, lavg_t *cur_entry)
+lavg_list_next(lavg_list_t *list)
+{
+ return (lavg_t *) u_list_next((u_list_t *) list);
+}
+
+void
+lavg_list_end_iteration(lavg_list_t *list)
{
- return (lavg_t *) u_list_next((u_list_t *) list, (u_list_entry_t *) cur_entry);
+ u_list_end_iteration((u_list_t *) list);
}
void
-lavg_list_remove(lavg_list_t *list, lavg_t *entry)
+lavg_list_remove_cur(lavg_list_t *list)
{
- u_list_remove((u_list_t *) list, (u_list_entry_t *) entry);
+ u_list_remove_cur((u_list_t *) list);
}
lavg_list_t *
/* functions prototypes */
extern lavg_list_t *lavg_list_init(void);
-/* WARNING: lavg_t pointers returned by those functions are only
- * valid for as long as the list is not modified (add/remove) */
-extern lavg_t *lavg_list_add(lavg_list_t *list, struct cl_t *line);
+extern lavg_t *lavg_list_add_line(lavg_list_t *list, struct cl_t *line);
+extern lavg_t *lavg_list_add(lavg_list_t *list, lavg_t *entry);
+/* WARNING: there should always be a unique iteration loop based on
+ * u_list_first()/u_list_next() running at any one time in the code */
extern lavg_t *lavg_list_first(lavg_list_t *list);
-extern lavg_t *lavg_list_next(lavg_list_t *list, lavg_t *cur_entry);
-extern void lavg_list_remove(lavg_list_t *list, lavg_t *entry);
+extern lavg_t *lavg_list_next(lavg_list_t *list);
+extern void lavg_list_end_iteration(lavg_list_t *list);
+extern void lavg_list_remove_cur(lavg_list_t *list);
extern lavg_list_t *lavg_list_destroy(lavg_list_t *list);
void print_line(int fd, struct cl_t *line, unsigned char *details, pid_t pid, int index,
time_t until);
void cmd_on_exeq(struct fcrondyn_cl *client, long int *cmd, int fd, int is_root);
-void cmd_renice(struct fcrondyn_cl *client, long int *cmd, int fd, int exe_index,
+void cmd_renice(struct fcrondyn_cl *client, long int *cmd, int fd, exe_t *e,
int is_root);
-void cmd_send_signal(struct fcrondyn_cl *client, long int *cmd, int fd, int exe_index);
+void cmd_send_signal(struct fcrondyn_cl *client, long int *cmd, int fd, exe_t *e);
void cmd_run(struct fcrondyn_cl *client, long int *cmd, int fd, int is_root);
void add_to_select_set(int fd, fd_set *set, int *max_fd);
void remove_from_select_set(int fd, fd_set *set, int *max_fd);
struct job_t *j;
int i;
unsigned char fields[FIELD_NUM_SIZE];
+ exe_t *e = NULL;
+ lavg_t *l = NULL;
for (i = 0; i < FIELD_NUM_SIZE; i++)
fields[i] = 0;
break;
case CMD_LIST_EXEQ:
- for ( i = 0; i < exe_num; i++) {
- if ( exe_array[i].e_line == NULL ) {
+ for (e = exe_list_first(exe_list); e != NULL; e = exe_list_next(exe_list)) {
+ if ( e->e_line == NULL ) {
if ( is_root ) {
send_msg_fd(fd, "job no more in an fcrontab: pid %d",
- exe_array[i].e_job_pid);
+ e->e_job_pid);
found = 1;
}
}
else
- Test_line(exe_array[i].e_line, exe_array[i].e_job_pid,
- 0, 0)
+ Test_line(e->e_line, e->e_job_pid, 0, 0)
}
break;
case CMD_LIST_LAVGQ:
- for ( i = 0; i < lavg_num; i++)
- Test_line(lavg_array[i].l_line, 0, 0, lavg_array[i].l_until);
+ for (l=lavg_list_first(lavg_list); l!=NULL; l=lavg_list_next(lavg_list))
+ Test_line(l->l_line, 0, 0, l->l_until);
break;
case CMD_LIST_SERIALQ:
cmd_on_exeq(struct fcrondyn_cl *client, long int *cmd, int fd, int is_root)
/* common code to all cmds working on jobs in the exeq */
{
- int exe_index;
int found = 0;
char *err_str = NULL;
+ exe_t *e = NULL;
/* find the corresponding job */
- for ( exe_index = 0 ; exe_index < exe_num; exe_index++ ) {
- if ( exe_array[exe_index].e_line != NULL
- && cmd[2] == exe_array[exe_index].e_line->cl_id ) {
+ for (e = exe_list_first(exe_list); e != NULL; e = exe_list_next(exe_list)) {
+ if ( e->e_line != NULL
+ && cmd[2] == e->e_line->cl_id ) {
found = 1;
/* check if the request is valid */
if ( ! is_root &&
- strcmp(client->fcl_user,
- exe_array[exe_index].e_line->cl_file->cf_user) != 0 ) {
+ strcmp(client->fcl_user, e->e_line->cl_file->cf_user) != 0 ) {
if ( cmd[0] == CMD_RENICE )
err_str = "%s tried to renice to %ld job id %ld for %s : "
/* request is valid : do it */
if ( cmd[0] == CMD_SEND_SIGNAL )
- cmd_send_signal(client, cmd, fd, exe_index);
+ cmd_send_signal(client, cmd, fd, e);
else if ( cmd[0] == CMD_RENICE )
- cmd_renice(client, cmd, fd, exe_index, is_root);
+ cmd_renice(client, cmd, fd, e, is_root);
else {
Send_err_msg_end(fd, err_cmd_unknown_str);
return;
void
-cmd_renice(struct fcrondyn_cl *client, long int *cmd, int fd, int exe_index, int is_root)
+cmd_renice(struct fcrondyn_cl *client, long int *cmd, int fd, exe_t *e, int is_root)
/* change nice value of a running job */
{
#ifdef HAVE_SETPRIORITY
/* check if arguments are valid */
- if ( exe_array[exe_index].e_job_pid <= 0 || ((int)cmd[1] < 0 && ! is_root)
+ if ( e->e_job_pid <= 0 || ((int)cmd[1] < 0 && ! is_root)
|| (int)cmd[1] > 20 || (int)cmd[1] < -20 ) {
warn("renice: invalid args : pid: %d nice_value: %d user: %s.",
- exe_array[exe_index].e_job_pid, (int)cmd[1], client->fcl_user);
+ e->e_job_pid, (int)cmd[1], client->fcl_user);
Send_err_msg_end(fd, err_invalid_args_str);
return;
}
/* ok, now setpriority() the job */
- if ( setpriority(PRIO_PROCESS, exe_array[exe_index].e_job_pid, (int)cmd[1]) != 0) {
+ if ( setpriority(PRIO_PROCESS, e->e_job_pid, (int)cmd[1]) != 0) {
error_e("could not setpriority(PRIO_PROCESS, %d, %d)",
- exe_array[exe_index].e_job_pid, (int)cmd[1]);
+ e->e_job_pid, (int)cmd[1]);
Send_err_msg_end(fd, err_unknown_str);
return;
}
else {
send_msg_fd(fd, "Command successfully completed on process %d.",
- exe_array[exe_index].e_job_pid);
+ e->e_job_pid);
return;
}
#else /* HAVE_SETPRIORITY */
warn("System has no setpriority() : cannot renice. pid: %d nice_value: %d user: %s.",
- exe_array[exe_index].e_job_pid, (int)cmd[1], client->fcl_user);
+ e->e_job_pid, (int)cmd[1], client->fcl_user);
Send_err_msg_end(fd, err_cmd_unknown_str);
#endif /* HAVE_SETPRIORITY */
void
-cmd_send_signal(struct fcrondyn_cl *client, long int *cmd, int fd, int exe_index)
+cmd_send_signal(struct fcrondyn_cl *client, long int *cmd, int fd, exe_t *e)
/* send a signal to a running job */
{
- if ( exe_array[exe_index].e_job_pid <= 0 || (int)cmd[1] <= 0 ) {
+ if ( e->e_job_pid <= 0 || (int)cmd[1] <= 0 ) {
warn("send_signal: invalid args : pid: %d signal: %d user: %s",
- exe_array[exe_index].e_job_pid, (int)cmd[1], client->fcl_user);
+ e->e_job_pid, (int)cmd[1], client->fcl_user);
Send_err_msg_end(fd, err_invalid_args_str);
return;
}
/* ok, now kill() the job */
- if ( kill(exe_array[exe_index].e_job_pid, (int)cmd[1]) != 0) {
- error_e("could not kill(%d, %d)", exe_array[exe_index].e_job_pid, (int)cmd[1]);
+ if ( kill(e->e_job_pid, (int)cmd[1]) != 0) {
+ error_e("could not kill(%d, %d)", e->e_job_pid, (int)cmd[1]);
Send_err_msg_end(fd, err_unknown_str);
return;
}
else {
send_msg_fd(fd, "Command successfully completed on process %d.",
- exe_array[exe_index].e_job_pid);
+ e->e_job_pid);
return;
}
}
return(ptr);
}
+void
+free_safe(void *ptr)
+ /* free() p and set it to NULL to prevent errors if it is free()ed again */
+{
+ free(ptr);
+ ptr = NULL;
+}
int
get_word(char **str)
free_conf(void)
/* free() the memory allocated in init_conf() */
{
- free(fcronconf);
- free(fcrontabs);
- free(pidfile);
- free(fifofile);
- free(fcronallow);
- free(fcrondeny);
- free(shell);
- free(sendmail);
- free(editor);
+ free_safe(fcronconf);
+ free_safe(fcrontabs);
+ free_safe(pidfile);
+ free_safe(fifofile);
+ free_safe(fcronallow);
+ free_safe(fcrondeny);
+ free_safe(shell);
+ free_safe(sendmail);
+ free_safe(editor);
}
extern gid_t get_group_gid_safe(char *groupname);
extern int remove_blanks(char *str);
extern char *strdup2(const char *);
+extern void free_safe(void *ptr);
extern int get_word(char **str);
extern int temp_file(char **name);
extern void read_conf(void);
l->array_size = init_size;
l->entry_size = entry_size;
l->grow_size = grow_size;
+ l->cur_entry = NULL;
+ l->cur_removed = 0;
l->entries_array = calloc(init_size, entry_size);
if ( l->entries_array == NULL )
die_e("Failed creating a new unordered list: could not calloc array"
* Returns OK on success, ERR if the array is already at maximum size */
{
u_list_entry_t *e = NULL;
+ int offset = 0;
int old_size = l->array_size;
/* sanity check */
return ERR;
}
+ if ( l->cur_entry != NULL )
+ /* Compute cur_entry's offset so as we can set cur_entry to the right place
+ * after we have allocated a new chunk of memory for the entries_array */
+ offset = (char *) l->cur_entry - (char *) l->entries_array;
+
l->array_size = (l->array_size + l->grow_size);
if ( l->max_entries > 0 && l->array_size > l->max_entries )
l->array_size = l->max_entries;
free_safe(l->entries_array);
l->entries_array = e;
+ if ( l->cur_entry != NULL )
+ l->cur_entry = (u_list_entry_t *) ( (char *) l->entries_array + offset );
+
return OK;
}
/* sanity check */
if ( l == NULL )
die("Invalid argument for u_list_first(): list=%d", l);
+ if ( l->cur_entry != NULL )
+ die("u_list_first() called but there is already an iteration");
- return (l->num_entries > 0) ? l->entries_array : NULL;
+ if (l->num_entries > 0) {
+ l->cur_entry = l->entries_array;
+ }
+
+ return l->cur_entry;
}
u_list_entry_t *
-u_list_next(u_list_t *l, u_list_entry_t *e)
+u_list_next(u_list_t *l)
/* Return the entry after e */
{
+ /* // WHAT IF I CALL _ADD() (+RESIZE?) OR _REMOVE() BETWEEN TWO _NEXT CALLS? */
+
/* sanity checks */
- if (l==NULL||e==NULL)
- die("Invalid arguments for u_list_next(): list=%d, entry=%d", l, e);
- if (e < l->entries_array || e > u_list_last(l) )
- die("u_list_next(): entry out of list! (entries_array: %d, entry: %d,"
- "num_entries: %d)", l->entries_array, e, l->num_entries);
-
- /* // */
- /* Undefined? -- convert soustraction to float and check if result is an int ? */
-/* if ( ( (char *) e - (char *) l->entries_array ) % l->entry_size != 0 )
- die("u_list_next(): entry shifted! (entries_array: %d, entry_size: %d, "
- "entry: %d", l->entries_array, l->entry_size, e);
-*/
- if ( e < u_list_last(l) )
- return (u_list_entry_t *) ( (char *) e + l->entry_size);
- else
- return NULL;
+ if ( l == NULL )
+ die("Invalid arguments for u_list_next(): list=%d", l);
+ if ( l->cur_entry == NULL )
+ die("u_list_next() called outside an iteration: l->cur_entry=%d", l->cur_entry);
+
+ if ( l->cur_removed > 0 ) {
+ l->cur_removed = 0;
+ /* the current entry has just been removed and replaced by another one:
+ * we can return the same pointer again.
+ * However if the removed entry was the last one then we reached the end
+ * of the list */
+ if ( l->cur_entry > u_list_last(l) )
+ l->cur_entry = NULL;
+ }
+ else {
+ /* cur_entry *not* removed (standard behavior) */
+
+ if ( l->cur_entry < u_list_last(l) )
+ l->cur_entry = (u_list_entry_t *) ( (char *) l->cur_entry + l->entry_size);
+ else
+ /* reached the end of the list */
+ l->cur_entry = NULL;
+ }
+
+ return l->cur_entry;
}
void
-u_list_remove(u_list_t *l, u_list_entry_t *e)
+u_list_end_iteration(u_list_t *list)
+ /* Stop an iteration before _next() reached the end of the list by itself */
{
+ list->cur_entry = NULL;
+ list->cur_removed = 0;
+}
+
+
+void
+u_list_remove_cur(u_list_t *l)
+{
+ /* // MANAGE L->NEXT_ENTRY (+ SPECIAL CASE FIRST/LAST ENTRY) */
u_list_entry_t *last = NULL;
/* sanity checks */
- if ( l == NULL || e == NULL )
- die("Invalid arguments for u_list_remove(): list=%d, entry=%d", l, e);
- if (e < l->entries_array || e > u_list_last(l) )
- die("u_list_next(): entry out of list! (entries_array: %d, entry: %d,"
- "num_entries: %d)", l->entries_array, e, l->num_entries);
+ if ( l == NULL )
+ die("Invalid arguments for u_list_remove(): list=%d", l);
+ if ( l->cur_entry == NULL )
+ die("u_list_remove_cur() called outside of an iteration");
last = u_list_last(l);
- if ( e < last ) {
+ if ( l->cur_entry < last ) {
/* Override e with the last entry */
- memcpy(e, last, l->entry_size);
+ memcpy(l->cur_entry, last, l->entry_size);
}
/* erase the last entry and update the number of entries */
memset(last, 0, l->entry_size);
l->num_entries--;
-
+ l->cur_removed = 1;
}
int array_size; /* size of the array (in number of entries) */
size_t entry_size; /* number of element currently in the array */
int grow_size; /* grow array by grow_size entries at a time */
+ u_list_entry_t *cur_entry; /* Current entry in iteration
+ * (null if not in iteration, i.e. X_first() has
+ * not been called or we reached the list end */
+ char cur_removed; /* >0 if cur_entry has just been removed */
u_list_entry_t *entries_array; /* pointer to the actual array */
} u_list_t;
/* functions prototypes */
extern u_list_t *u_list_init(size_t entry_size, int init_size, int grow_size);
-/* WARNING: u_list_entry_t pointers returned by those functions are only
- * valid for as long as the list is not modified (add/remove) */
extern u_list_entry_t *u_list_add(u_list_t *list, u_list_entry_t *entry);
+/* WARNING: - there should always be a unique iteration loop based on
+ * u_list_first()/u_list_next() running at any one time in the code
+ * - the u_list_entry_t* returned by _first() and _next() should not
+ * be used anymore after a _add() or a _remove_cur() */
extern u_list_entry_t *u_list_first(u_list_t *list);
-extern u_list_entry_t *u_list_next(u_list_t *list, u_list_entry_t *cur_entry);
-extern void u_list_remove(u_list_t *list, u_list_entry_t *entry);
+extern u_list_entry_t *u_list_next(u_list_t *list);
+extern void u_list_end_iteration(u_list_t *list);
+extern void u_list_remove_cur(u_list_t *list);
extern u_list_t *u_list_destroy(u_list_t *list);