12 #include <libfossrepo.h>
17 #include <interface.h>
31 #include <sys/types.h>
44 #define TEST_ERROR(error, ...) \
47 log_printf("ERROR %s.%d: %s\n", \
48 __FILE__, __LINE__, error->message); \
49 log_printf("ERROR %s.%d: ", __FILE__, __LINE__); \
50 log_printf(__VA_ARGS__); \
52 g_clear_error(&error); \
62 #define SELECT_DECLS(type, name, l_op, w_op, val) type CONF_##name = val;
70 #define MASK_SIGCHLD (1 << 0)
71 #define MASK_SIGALRM (1 << 1)
72 #define MASK_SIGTERM (1 << 2)
73 #define MASK_SIGQUIT (1 << 3)
74 #define MASK_SIGHUP (1 << 4)
114 case SIGCHLD: __sync_fetch_and_or(&sigmask, MASK_SIGCHLD);
break;
115 case SIGTERM: __sync_fetch_and_or(&sigmask, MASK_SIGTERM);
break;
116 case SIGQUIT: __sync_fetch_and_or(&sigmask, MASK_SIGQUIT);
break;
117 case SIGHUP: __sync_fetch_and_or(&sigmask, MASK_SIGHUP);
break;
119 case SIGCHLD: sigmask |= MASK_SIGCHLD;
break;
120 case SIGALRM: sigmask |= MASK_SIGALRM;
break;
121 case SIGTERM: sigmask |= MASK_SIGTERM;
break;
122 case SIGQUIT: sigmask |= MASK_SIGQUIT;
break;
123 case SIGHUP: sigmask |= MASK_SIGHUP ;
break;
145 static time_t last_update = 0;
152 mask = __sync_fetch_and_and(&sigmask, 0);
160 last_update = time(NULL);
168 if(mask & MASK_SIGCHLD)
175 while((n = waitpid(-1, &status, WNOHANG)) > 0)
177 V_SCHED(
"SIGNALS: received sigchld for pid %d\n", n);
178 pass = g_new0(pid_t, 2);
190 if(mask & MASK_SIGTERM)
192 V_SCHED(
"SIGNALS: Scheduler received terminate signal, shutting down gracefully\n");
202 if(mask & MASK_SIGQUIT)
204 V_SCHED(
"SIGNALS: Scheduler received quit signal, shutting down scheduler\n");
213 if(mask & MASK_SIGHUP)
215 V_SCHED(
"SIGNALS: Scheduler received SGIHUP, reloading configuration data\n");
226 if((time(NULL) - last_update) > CONF_agent_update_interval )
228 V_SPECIAL(
"SIGNALS: Performing agent and database update\n");
231 last_update = time(NULL);
254 ret->
s_pid = getpid();
295 "([A-Z]+):([ \t]+)(\\d+)(([ \t]+)(\\d))?",
312 "\\$([A-Z_]*)(\\.([a-zA-Z_]*)\\.([a-zA-Z_]*))?",
334 "(\\w+)(\\s+(-?\\d+))?(\\s+((-?\\d+)|(\"(.*)\")))?",
335 0, G_REGEX_MATCH_NEWLINE_LF, NULL);
377 if(scheduler->
workers) g_thread_pool_free(scheduler->
workers, FALSE, TRUE);
389 g_tree_unref(scheduler->
agents);
436 static job_t* job = NULL;
437 static host_t* host = NULL;
438 static int lockout = 0;
441 int n_agents = g_tree_nnodes(scheduler->
agents);
445 if(scheduler->
s_startup && n_agents == 0)
452 if(
closing && n_agents == 0 && n_jobs == 0)
458 if(lockout && n_agents == 0 && n_jobs == 0)
461 if(job == NULL && !lockout)
469 V_SCHED(
"JOB_INIT: Unable to run agent %s due to max_run limit.\n",
478 host = g_tree_lookup(scheduler->
host_list, LOCAL_HOST);
499 job->
message =
"ERROR: jq_host not in the agent list!";
516 V_SCHED(
"JOB_INIT: exclusive, postponing initialization\n");
520 V_SCHED(
"Starting JOB[%d].%s\n", job->
id, job->
agent_type);
526 if(job != NULL && n_agents == 0 && n_jobs == 0)
545 #define GU_HEADER "DIRECTORIES"
546 #define GU_GROUP "PROJECTGROUP"
547 #define GU_USER "PROJECTUSER"
565 fo_config_get (config, GU_HEADER, GU_GROUP, NULL) : PROJECT_GROUP;
568 fo_config_get (config, GU_HEADER, GU_USER, NULL) : PROJECT_USER;
571 grp = getgrnam(group);
574 fprintf(stderr,
"FATAL %s.%d: could not find group \"%s\"\n",
575 __FILE__, __LINE__, group);
576 fprintf(stderr,
"FATAL set_usr_grp() aborting due to error: %s\n",
582 setgroups(1, &(grp->gr_gid));
583 if((setgid(grp->gr_gid) != 0) || (setegid(grp->gr_gid) != 0))
585 fprintf(stderr,
"FATAL %s.%d: %s must be run as root or %s\n",
586 __FILE__, __LINE__, process_name, user);
587 fprintf(stderr,
"FATAL Set group '%s' aborting due to error: %s\n",
588 group, strerror(errno));
593 pwd = getpwnam(user);
596 fprintf(stderr,
"FATAL %s.%d: user '%s' not found\n",
597 __FILE__, __LINE__, user);
602 if((setuid(pwd->pw_uid) != 0) || (seteuid(pwd->pw_uid) != 0))
604 fprintf(stderr,
"FATAL %s.%d: %s must run this as %s\n",
605 __FILE__, __LINE__, process_name, user);
606 fprintf(stderr,
"FATAL SETUID aborting due to error: %s\n",
622 gchar f_name[FILENAME_MAX];
627 pid_t s_pid = getpid();
629 if((dp = opendir(
"/proc/")) == NULL)
631 fprintf(stderr,
"ERROR %s.%d: Could not open /proc/ file system\n",
636 while((ep = readdir(dp)) != NULL)
640 snprintf(f_name,
sizeof(f_name),
"/proc/%s/cmdline", ep->d_name);
641 if((file = fopen(f_name,
"rt")))
643 if(fgets(f_name,
sizeof(f_name), file) != NULL &&
644 strstr(f_name,
"fo_scheduler") && s_pid != atoi(ep->d_name))
646 NOTIFY(
"KILL: send signal to process %s\n", ep->d_name);
648 kill(atoi(ep->d_name), SIGQUIT);
650 kill(atoi(ep->d_name), SIGTERM);
709 GList** ret = (GList**)data;
711 *ret = g_list_append(*ret, key);
728 for(iter = keys; iter != NULL; iter = iter->next)
729 g_tree_remove(tree, iter->data);
749 uint32_t special = 0;
754 GError* error = NULL;
758 if((dp = opendir(dirname)) == NULL)
760 FATAL(
"Could not open agent config directory: %s", dirname);
766 while((ep = readdir(dp)) != NULL)
768 if(ep->d_name[0] !=
'.')
770 dirname = g_strdup_printf(
"%s/%s/%s/%s.conf",
776 V_SCHED(
"CONFIG: Could not find %s\n", dirname);
777 g_clear_error(&error);
781 V_SCHED(
"CONFIG: loading config file %s\n", dirname);
785 log_printf(
"ERROR: %s must have a \"default\" group\n", dirname);
786 log_printf(
"ERROR: cause by %s.%d\n", __FILE__, __LINE__);
793 TEST_ERROR(error,
"%s: the special key should be of type list", dirname);
794 for(i = 0; i <
max; i++)
797 TEST_ERROR(error,
"%s: failed to load element %d of special list",
801 if(strncmp(cmd,
"EXCLUSIVE", 9) == 0)
803 else if(strncmp(cmd,
"NOEMAIL", 7) == 0)
805 else if(strncmp(cmd,
"NOKILL", 6) == 0)
807 else if(strncmp(cmd,
"LOCAL", 6) == 0)
809 else if(strlen(cmd) != 0)
810 WARNING(
"%s: Invalid special type for agent %s: %s",
816 TEST_ERROR(error,
"%s: the default group must have a command key", dirname);
818 TEST_ERROR(error,
"%s: the default group must have a max key", dirname);
822 V_SCHED(
"CONFIG: could not create meta agent using %s\n", ep->d_name);
826 log_printf(
"CONFIG: added new agent\n");
827 log_printf(
" name = %s\n", name);
828 log_printf(
" command = %s\n", cmd);
829 log_printf(
" max = %d\n",
max);
830 log_printf(
" special = %d\n", special);
860 gchar dirbuf[FILENAME_MAX];
861 GError* error = NULL;
870 tmp = g_strdup_printf(
"%s/fossology.conf", scheduler->
sysconfigdir);
872 if(error)
FATAL(
"%s", error->message);
879 if(scheduler->
i_port == 0)
881 "FOSSOLOGY",
"port", &error));
899 for(i = 0; i < special; i++)
904 WARNING(
"%s\n", error->message);
905 g_clear_error(&error);
909 sscanf(tmp,
"%s %s %d", addbuf, dirbuf, &
max);
914 log_printf(
"CONFIG: added new host\n");
915 log_printf(
" name = %s\n", keys[i]);
916 log_printf(
" address = %s\n", addbuf);
917 log_printf(
" directory = %s\n", dirbuf);
918 log_printf(
" max = %d\n",
max);
924 ERROR(
"configuration file failed repository validation");
925 ERROR(
"The offending line: \"%s\"", tmp);
931 tmp = g_strdup_printf(
"%s/VERSION", scheduler->
sysconfigdir);
933 if(error)
FATAL(
"%s", error->message);
956 #define SELECT_CONF_INIT(type, name, l_op, w_op, val) \
957 if(fo_config_has_key(scheduler->sysconfig, "SCHEDULER", #name)) \
958 CONF_##name = l_op(fo_config_get(scheduler->sysconfig, "SCHEDULER", #name, NULL)); \
959 V_SPECIAL("CONFIG: %s == " MK_STRING_LIT(w_op) "\n", #name, CONF_##name );
961 #undef SELECT_CONF_INIT
978 if((ret = daemon(0, 0)) != 0)
981 scheduler->
s_pid = getpid();
1043 int len = strlen(str);
1046 for(i = 0; i < len; i++)
1047 if(!isdigit(str[i]))
1062 return strcmp((
char*)a, (
char*)b);
1074 gint
int_compare(gconstpointer a, gconstpointer b, gpointer user_data)
1076 return *(
int*)a - *(
int*)b;
agent_t * agent_init(scheduler_t *scheduler, host_t *host, job_t *job)
Allocate and spawn a new agent.
void agent_update_event(scheduler_t *scheduler, void *unused)
void agent_destroy(agent_t *agent)
Frees the memory associated with an agent.
int add_meta_agent(GTree *meta_agents, char *name, char *cmd, int max, int spc)
void test_agents(scheduler_t *scheduler)
Calls the agent test function for every type of agent.
void kill_agents(scheduler_t *scheduler)
Call the agent_kill function for every agent within the system.
int is_meta_special(meta_agent_t *ma, int special_type)
tests if a particular meta agent has a specific special flag set
void agent_death_event(scheduler_t *scheduler, pid_t *pid)
void meta_agent_destroy(meta_agent_t *ma)
Header file with agent related operations.
#define SAG_NOEMAIL
This agent should not send notification emails.
#define SAG_NOKILL
This agent should not be killed when updating the agent.
#define SAG_EXCLUSIVE
This agent must not run at the same time as any other agent.
#define SAG_LOCAL
This agent should only run on localhost.
void event_loop_terminate()
Stops the event loop from executing.
void event_loop_destroy()
Frees any memory associated with the event queue.
Event handling operations.
char * fo_config_get_list(fo_conf *conf, char *group, char *key, int idx, GError **error)
int fo_config_list_length(fo_conf *conf, char *group, char *key, GError **error)
Gets the length of the list associated with a particular list key.
void fo_config_free(fo_conf *conf)
Frees the memory associated with the internal configuration data structures.
fo_conf * fo_config_load(char *rawname, GError **error)
Load the configuration information from the provided file.
char * fo_config_get(fo_conf *conf, const char *group, const char *key, GError **error)
Gets an element based on its group name and key name. If the group or key is not found,...
int fo_config_has_group(fo_conf *conf, char *group)
Checks if the currently parsed configuration file has a specific group.
void fo_config_join(fo_conf *dst, fo_conf *src, GError **error)
Takes all groups and key from a fo_conf and adds them to another.
char ** fo_config_key_set(fo_conf *conf, char *group, int *length)
Gets the set of key names for a particular group.
int fo_config_has_key(fo_conf *conf, char *group, char *key)
Checks if the a specific group in the currently parsed configuration file has a specific key.
FOSSology library to read config file.
@ fo_missing_file
File is missing.
void host_insert(host_t *host, scheduler_t *scheduler)
Inserts a new host into the scheduler structure.
host_t * host_init(char *name, char *address, char *agent_dir, int max)
Creates a new host, and adds it to the host list.
void host_destroy(host_t *host)
Frees and uninitializes any memory associated with the host struct.
host_t * get_host(GList **queue, uint8_t num)
void job_fail_event(scheduler_t *scheduler, job_t *job)
Events that causes a job to be marked a failed.
job_t * next_job(GSequence *job_queue)
Gets the next job from the job queue.
job_t * peek_job(GSequence *job_queue)
Gets the job that is at the top of the queue if there is one.
void job_destroy(job_t *job)
uint32_t active_jobs(GTree *job_list)
Gets the number of jobs that are not paused.
FUNCTION int max(int permGroup, int permPublic)
Get the maximum group privilege.
char * fo_RepValidate(fo_conf *config)
validates the repository configuration information.
log_t * log_new(gchar *log_name, gchar *pro_name, pid_t pro_pid)
Creates a new log.
void log_destroy(log_t *log)
Free memory associated with the log file.
void database_init(scheduler_t *scheduler)
void database_update_event(scheduler_t *scheduler, void *unused)
Checks the job queue for any new entries.
void email_init(scheduler_t *scheduler)
Loads information about the email that will be sent for job notifications.
int verbose
The verbose level.
void scheduler_config_event(scheduler_t *scheduler, void *unused)
Load both the fossology configuration and all the agent configurations.
int closing
Set if scheduler is shutting down.
void scheduler_agent_config(scheduler_t *scheduler)
Loads a particular agents configuration file.
int scheduler_daemonize(scheduler_t *scheduler)
Daemonizes the scheduler.
GThread * main_thread
Pointer to the main thread.
gint string_is_num(gchar *str)
Checks if a string is entirely composed of numeric characters.
void g_tree_clear(GTree *tree)
Clears the contents of a GTree.
static gboolean isMaxLimitReached(meta_agent_t *agent)
Check if the current agent's max limit is respected.
void scheduler_close_event(scheduler_t *scheduler, void *killed)
Sets the closing flag and possibly kills all currently running agents.
void scheduler_test_agents(scheduler_t *scheduler, void *unused)
Event used when the scheduler tests the agents.
static gboolean g_tree_collect(gpointer key, gpointer value, gpointer data)
GTraverseFunc used by g_tree_clear to collect all the keys in a tree.
void scheduler_update(scheduler_t *scheduler)
Update function called after every event.
void scheduler_sig_handle(int signo)
Handles any signals sent to the scheduler that are not SIGCHLD.
void scheduler_clear_config(scheduler_t *scheduler)
Clears any information that is loaded when loading the configuration.
scheduler_t * scheduler_init(gchar *sysconfigdir, log_t *log)
Create a new scheduler object.
gint int_compare(gconstpointer a, gconstpointer b, gpointer user_data)
void scheduler_foss_config(scheduler_t *scheduler)
Loads the configuration data from fossology.conf.
gint string_compare(gconstpointer a, gconstpointer b, gpointer user_data)
void set_usr_grp(gchar *process_name, fo_conf *config)
#define TEST_ERROR(error,...)
int kill_scheduler(int force)
Kills all other running scheduler.
void scheduler_destroy(scheduler_t *scheduler)
Free any memory associated with a scheduler_t.
void scheduler_signal(scheduler_t *scheduler)
Function that handles certain signals being delivered to the scheduler.
Header file for the scheduler.
#define SELECT_DECLS(type, name, l_op, w_op, val)
#define CONF_VARIABLES_TYPES(apply)
#define AGENT_CONF
Agent conf location.
int running
The number of agents currently running on this host.
int max
The max number of agents that can run on this host.
int32_t id
The identifier for this job.
char * required_host
If not NULL, this job must run on a specific host machine.
gchar * message
Message that will be sent with job notification email.
char * agent_type
The type of agent used to analyze the data.
gboolean s_pause
Has the scheduler been paused.
GThread * server
Thread that is listening to the server socket.
GTree * job_list
List of jobs that have been created.
gchar * email_header
The beginning of the email message.
gchar * email_command
The command that will sends emails, usually mailx.
GRegex * parse_interface_cmd
Parses the commands received by the interface.
gchar * sysconfigdir
The system directory that contain fossology.conf.
PGconn * db_conn
The database connection.
gboolean s_startup
Has the scheduler finished startup tests.
GList * host_queue
Round-robin queue for choosing which host use next.
GTree * host_list
List of all hosts available to the scheduler.
log_t * main_log
The main log file for the scheduler.
gboolean s_pid
The pid of the scheduler process.
GRegex * parse_agent_msg
Parses messages coming from the agents.
gchar * logdir
The directory to put the log file in.
GTree * meta_agents
List of all meta agents available to the scheduler.
GThreadPool * workers
Threads to handle incoming network communication.
gboolean default_footer
Is the footer the default footer.
gchar * process_name
The name of the scheduler process.
gboolean i_terminate
Has the interface been terminated.
GTree * agents
List of any currently running agents.
gboolean logcmdline
Was the log file set by the command line.
gchar * email_subject
The subject to be used for emails.
GCancellable * cancel
Used to stop the listening thread when it is running.
GRegex * parse_db_email
Parses database email text.
gboolean i_created
Has the interface been created.
gchar * email_footer
The end of the email message.
GSequence * job_queue
heap of jobs that still need to be started
gboolean s_daemon
Is the scheduler being run as a daemon.
gboolean default_header
Is the header the default header.
gchar * host_url
The url that is used to get to the FOSSology instance.
fo_conf * sysconfig
Configuration information loaded from the configuration file.
uint16_t i_port
The port that the scheduler is listening on.