23 #include <libfossrepo.h> 28 #include <interface.h> 42 #include <sys/types.h> 55 #define TEST_ERROR(error, ...) \ 58 log_printf("ERROR %s.%d: %s\n", \ 59 __FILE__, __LINE__, error->message); \ 60 log_printf("ERROR %s.%d: ", __FILE__, __LINE__); \ 61 log_printf(__VA_ARGS__); \ 63 g_clear_error(&error); \ 73 #define SELECT_DECLS(type, name, l_op, w_op, val) type CONF_##name = val; 81 #define MASK_SIGCHLD (1 << 0) 82 #define MASK_SIGALRM (1 << 1) 83 #define MASK_SIGTERM (1 << 2) 84 #define MASK_SIGQUIT (1 << 3) 85 #define MASK_SIGHUP (1 << 4) 125 case SIGCHLD: __sync_fetch_and_or(&sigmask, MASK_SIGCHLD);
break;
126 case SIGTERM: __sync_fetch_and_or(&sigmask, MASK_SIGTERM);
break;
127 case SIGQUIT: __sync_fetch_and_or(&sigmask, MASK_SIGQUIT);
break;
128 case SIGHUP: __sync_fetch_and_or(&sigmask, MASK_SIGHUP);
break;
130 case SIGCHLD: sigmask |= MASK_SIGCHLD;
break;
131 case SIGALRM: sigmask |= MASK_SIGALRM;
break;
132 case SIGTERM: sigmask |= MASK_SIGTERM;
break;
133 case SIGQUIT: sigmask |= MASK_SIGQUIT;
break;
134 case SIGHUP: sigmask |= MASK_SIGHUP ;
break;
156 static time_t last_update = 0;
163 mask = __sync_fetch_and_and(&sigmask, 0);
171 last_update = time(NULL);
179 if(mask & MASK_SIGCHLD)
186 while((n = waitpid(-1, &status, WNOHANG)) > 0)
188 V_SCHED(
"SIGNALS: received sigchld for pid %d\n", n);
189 pass = g_new0(pid_t, 2);
201 if(mask & MASK_SIGTERM)
203 V_SCHED(
"SIGNALS: Scheduler received terminate signal, shutting down gracefully\n");
213 if(mask & MASK_SIGQUIT)
215 V_SCHED(
"SIGNALS: Scheduler received quit signal, shutting down scheduler\n");
224 if(mask & MASK_SIGHUP)
226 V_SCHED(
"SIGNALS: Scheduler received SGIHUP, reloading configuration data\n");
237 if((time(NULL) - last_update) > CONF_agent_update_interval )
239 V_SPECIAL(
"SIGNALS: Performing agent and database update\n");
242 last_update = time(NULL);
265 ret->
s_pid = getpid();
306 "([A-Z]+):([ \t]+)(\\d+)(([ \t]+)(\\d))?",
323 "\\$([A-Z_]*)(\\.([a-zA-Z_]*)\\.([a-zA-Z_]*))?",
345 "(\\w+)(\\s+(-?\\d+))?(\\s+((-?\\d+)|(\"(.*)\")))?",
346 0, G_REGEX_MATCH_NEWLINE_LF, NULL);
388 if(scheduler->
workers) g_thread_pool_free(scheduler->
workers, FALSE, TRUE);
400 g_tree_unref(scheduler->
agents);
447 static job_t* job = NULL;
448 static host_t* host = NULL;
449 static int lockout = 0;
452 int n_agents = g_tree_nnodes(scheduler->
agents);
456 if(scheduler->
s_startup && n_agents == 0)
463 if(
closing && n_agents == 0 && n_jobs == 0)
469 if(lockout && n_agents == 0 && n_jobs == 0)
472 if(job == NULL && !lockout)
480 V_SCHED(
"JOB_INIT: Unable to run agent %s due to max_run limit.\n",
489 host = g_tree_lookup(scheduler->
host_list, LOCAL_HOST);
510 job->
message =
"ERROR: jq_host not in the agent list!";
527 V_SCHED(
"JOB_INIT: exclusive, postponing initialization\n");
531 V_SCHED(
"Starting JOB[%d].%s\n", job->
id, job->
agent_type);
537 if(job != NULL && n_agents == 0 && n_jobs == 0)
556 #define GU_HEADER "DIRECTORIES" 557 #define GU_GROUP "PROJECTGROUP" 558 #define GU_USER "PROJECTUSER" 576 fo_config_get (config, GU_HEADER, GU_GROUP, NULL) : PROJECT_GROUP;
579 fo_config_get (config, GU_HEADER, GU_USER, NULL) : PROJECT_USER;
582 grp = getgrnam(group);
585 fprintf(stderr,
"FATAL %s.%d: could not find group \"%s\"\n",
586 __FILE__, __LINE__, group);
587 fprintf(stderr,
"FATAL set_usr_grp() aborting due to error: %s\n",
593 setgroups(1, &(grp->gr_gid));
594 if((setgid(grp->gr_gid) != 0) || (setegid(grp->gr_gid) != 0))
596 fprintf(stderr,
"FATAL %s.%d: %s must be run as root or %s\n",
597 __FILE__, __LINE__, process_name, user);
598 fprintf(stderr,
"FATAL Set group '%s' aborting due to error: %s\n",
599 group, strerror(errno));
604 pwd = getpwnam(user);
607 fprintf(stderr,
"FATAL %s.%d: user '%s' not found\n",
608 __FILE__, __LINE__, user);
613 if((setuid(pwd->pw_uid) != 0) || (seteuid(pwd->pw_uid) != 0))
615 fprintf(stderr,
"FATAL %s.%d: %s must run this as %s\n",
616 __FILE__, __LINE__, process_name, user);
617 fprintf(stderr,
"FATAL SETUID aborting due to error: %s\n",
633 gchar f_name[FILENAME_MAX];
638 pid_t s_pid = getpid();
640 if((dp = opendir(
"/proc/")) == NULL)
642 fprintf(stderr,
"ERROR %s.%d: Could not open /proc/ file system\n",
647 while((ep = readdir(dp)) != NULL)
651 snprintf(f_name,
sizeof(f_name),
"/proc/%s/cmdline", ep->d_name);
652 if((file = fopen(f_name,
"rt")))
654 if(fgets(f_name,
sizeof(f_name), file) != NULL &&
655 strstr(f_name,
"fo_scheduler") && s_pid != atoi(ep->d_name))
657 NOTIFY(
"KILL: send signal to process %s\n", ep->d_name);
659 kill(atoi(ep->d_name), SIGQUIT);
661 kill(atoi(ep->d_name), SIGTERM);
720 GList** ret = (GList**)data;
722 *ret = g_list_append(*ret, key);
739 for(iter = keys; iter != NULL; iter = iter->next)
740 g_tree_remove(tree, iter->data);
760 uint32_t special = 0;
765 GError* error = NULL;
769 if((dp = opendir(dirname)) == NULL)
771 FATAL(
"Could not open agent config directory: %s", dirname);
777 while((ep = readdir(dp)) != NULL)
779 if(ep->d_name[0] !=
'.')
781 dirname = g_strdup_printf(
"%s/%s/%s/%s.conf",
787 V_SCHED(
"CONFIG: Could not find %s\n", dirname);
788 g_clear_error(&error);
792 V_SCHED(
"CONFIG: loading config file %s\n", dirname);
796 log_printf(
"ERROR: %s must have a \"default\" group\n", dirname);
797 log_printf(
"ERROR: cause by %s.%d\n", __FILE__, __LINE__);
804 TEST_ERROR(error,
"%s: the special key should be of type list", dirname);
805 for(i = 0; i <
max; i++)
808 TEST_ERROR(error,
"%s: failed to load element %d of special list",
812 if(strncmp(cmd,
"EXCLUSIVE", 9) == 0)
814 else if(strncmp(cmd,
"NOEMAIL", 7) == 0)
816 else if(strncmp(cmd,
"NOKILL", 6) == 0)
818 else if(strncmp(cmd,
"LOCAL", 6) == 0)
820 else if(strlen(cmd) != 0)
821 WARNING(
"%s: Invalid special type for agent %s: %s",
827 TEST_ERROR(error,
"%s: the default group must have a command key", dirname);
829 TEST_ERROR(error,
"%s: the default group must have a max key", dirname);
833 V_SCHED(
"CONFIG: could not create meta agent using %s\n", ep->d_name);
837 log_printf(
"CONFIG: added new agent\n");
838 log_printf(
" name = %s\n", name);
839 log_printf(
" command = %s\n", cmd);
840 log_printf(
" max = %d\n", max);
841 log_printf(
" special = %d\n", special);
871 gchar dirbuf[FILENAME_MAX];
872 GError* error = NULL;
881 tmp = g_strdup_printf(
"%s/fossology.conf", scheduler->
sysconfigdir);
883 if(error)
FATAL(
"%s", error->message);
890 if(scheduler->
i_port == 0)
892 "FOSSOLOGY",
"port", &error));
910 for(i = 0; i < special; i++)
915 WARNING(
"%s\n", error->message);
916 g_clear_error(&error);
920 sscanf(tmp,
"%s %s %d", addbuf, dirbuf, &max);
921 host =
host_init(keys[i], addbuf, dirbuf, max);
925 log_printf(
"CONFIG: added new host\n");
926 log_printf(
" name = %s\n", keys[i]);
927 log_printf(
" address = %s\n", addbuf);
928 log_printf(
" directory = %s\n", dirbuf);
929 log_printf(
" max = %d\n", max);
935 ERROR(
"configuration file failed repository validation");
936 ERROR(
"The offending line: \"%s\"", tmp);
942 tmp = g_strdup_printf(
"%s/VERSION", scheduler->
sysconfigdir);
944 if(error)
FATAL(
"%s", error->message);
967 #define SELECT_CONF_INIT(type, name, l_op, w_op, val) \ 968 if(fo_config_has_key(scheduler->sysconfig, "SCHEDULER", #name)) \ 969 CONF_##name = l_op(fo_config_get(scheduler->sysconfig, "SCHEDULER", #name, NULL)); \ 970 V_SPECIAL("CONFIG: %s == " MK_STRING_LIT(w_op) "\n", #name, CONF_##name ); 972 #undef SELECT_CONF_INIT 989 if((ret = daemon(0, 0)) != 0)
992 scheduler->
s_pid = getpid();
1054 int len = strlen(str);
1057 for(i = 0; i < len; i++)
1058 if(!isdigit(str[i]))
1073 return strcmp((
char*)a, (
char*)b);
1085 gint
int_compare(gconstpointer a, gconstpointer b, gpointer user_data)
1087 return *(
int*)a - *(
int*)b;
PGconn * db_conn
The database connection.
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.
gchar * email_header
The beginning of the email message.
gboolean default_footer
Is the footer the default footer.
GTree * host_list
List of all hosts available to the scheduler.
int verbose
The verbose level.
void scheduler_close_event(scheduler_t *scheduler, void *killed)
Sets the closing flag and possibly kills all currently running agents.
GTree * meta_agents
List of all meta agents available to the scheduler.
int fo_config_has_group(fo_conf *conf, char *group)
Checks if the currently parsed configuration file has a specific group.
FOSSology library to read config file.
int closing
Set if scheduler is shutting down.
GRegex * parse_db_email
Parses database email text.
int scheduler_daemonize(scheduler_t *scheduler)
Daemonizes the scheduler.
int add_meta_agent(GTree *meta_agents, char *name, char *cmd, int max, int spc)
fo_conf * sysconfig
Configuration information loaded from the configuration file.
GCancellable * cancel
Used to stop the listening thread when it is running.
int is_meta_special(meta_agent_t *ma, int special_type)
tests if a particular meta agent has a specific special flag set
gboolean s_pause
Has the scheduler been paused.
void scheduler_destroy(scheduler_t *scheduler)
Free any memory associated with a scheduler_t.
gboolean default_header
Is the header the default header.
void agent_death_event(scheduler_t *scheduler, pid_t *pid)
void log_destroy(log_t *log)
Free memory associated with the log file.
GRegex * parse_interface_cmd
Parses the commands received by the interface.
void email_init(scheduler_t *scheduler)
Loads information about the email that will be sent for job notifications.
void database_init(scheduler_t *scheduler)
void host_destroy(host_t *host)
Frees and uninitializes any memory associated with the host struct.
GList * host_queue
Round-robin queue for choosing which host use next.
gboolean i_created
Has the interface been created.
int max
The max number of agents that can run on this host.
void database_update_event(scheduler_t *scheduler, void *unused)
Checks the job queue for any new entries.
#define AGENT_CONF
Agent conf location.
void set_usr_grp(gchar *process_name, fo_conf *config)
uint16_t i_port
The port that the scheduler is listening on.
#define SAG_NOKILL
This agent should not be killed when updating the agent.
GThread * server
Thread that is listening to the server socket.
void scheduler_test_agents(scheduler_t *scheduler, void *unused)
Event used when the scheduler tests the agents.
gchar * sysconfigdir
The system directory that contain fossology.conf.
char * fo_RepValidate(fo_conf *config)
validates the repository configuration information.
gboolean logcmdline
Was the log file set by the command line.
host_t * host_init(char *name, char *address, char *agent_dir, int max)
Creates a new host, and adds it to the host list.
GSequence * job_queue
heap of jobs that still need to be started
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, the error object is set and NULL is returned.
gchar * host_url
The url that is used to get to the FOSSology instance.
#define CONF_VARIABLES_TYPES(apply)
void g_tree_clear(GTree *tree)
Clears the contents of a GTree.
#define SAG_NOEMAIL
This agent should not send notification emails.
void meta_agent_destroy(meta_agent_t *ma)
char * required_host
If not NULL, this job must run on a specific host machine.
int kill_scheduler(int force)
Kills all other running scheduler.
void kill_agents(scheduler_t *scheduler)
Call the agent_kill function for every agent within the system.
gint int_compare(gconstpointer a, gconstpointer b, gpointer user_data)
void scheduler_update(scheduler_t *scheduler)
Update function called after every event.
GTree * job_list
List of jobs that have been created.
agent_t * agent_init(scheduler_t *scheduler, host_t *host, job_t *job)
Allocate and spawn a new agent.
uint32_t active_jobs(GTree *job_list)
Gets the number of jobs that are not paused.
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...
void host_insert(host_t *host, scheduler_t *scheduler)
Inserts a new host into the scheduler structure.
gint string_is_num(gchar *str)
Checks if a string is entirely composed of numeric characters.
void scheduler_clear_config(scheduler_t *scheduler)
Clears any information that is loaded when loading the configuration.
void event_loop_terminate()
Stops the event loop from executing.
static gboolean isMaxLimitReached(meta_agent_t *agent)
Check if the current agent's max limit is respected.
void agent_destroy(agent_t *agent)
Frees the memory associated with an agent.
void job_destroy(job_t *job)
gboolean s_daemon
Is the scheduler being run as a daemon.
log_t * log_new(gchar *log_name, gchar *pro_name, pid_t pro_pid)
Creates a new log.
gchar * email_footer
The end of the email message.
#define SAG_LOCAL
This agent should only run on localhost.
gint string_compare(gconstpointer a, gconstpointer b, gpointer user_data)
job_t * peek_job(GSequence *job_queue)
Gets the job that is at the top of the queue if there is one.
#define SAG_EXCLUSIVE
This agent must not run at the same time as any other agent.
void scheduler_sig_handle(int signo)
Handles any signals sent to the scheduler that are not SIGCHLD.
void scheduler_agent_config(scheduler_t *scheduler)
Loads a particular agents configuration file.
char * fo_config_get_list(fo_conf *conf, char *group, char *key, int idx, GError **error)
FUNCTION int max(int permGroup, int permPublic)
Get the maximum group privilege.
void scheduler_foss_config(scheduler_t *scheduler)
Loads the configuration data from fossology.conf.
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.
gboolean i_terminate
Has the interface been terminated.
GTree * agents
List of any currently running agents.
scheduler_t * scheduler_init(gchar *sysconfigdir, log_t *log)
Create a new scheduler object.
char * agent_type
The type of agent used to analyze the data.
job_t * next_job(GSequence *job_queue)
Gets the next job from the job queue.
gchar * email_command
The command that will sends emails, usually mailx.
#define SELECT_DECLS(type, name, l_op, w_op, val)
void fo_config_free(fo_conf *conf)
Frees the memory associated with the internal configuration data structures.
void agent_update_event(scheduler_t *scheduler, void *unused)
Event handling operations.
gboolean s_startup
Has the scheduler finished startup tests.
char ** fo_config_key_set(fo_conf *conf, char *group, int *length)
Gets the set of key names for a particular group.
host_t * get_host(GList **queue, uint8_t num)
Header file with agent related operations.
gchar * message
Message that will be sent with job notification email.
void scheduler_config_event(scheduler_t *scheduler, void *unused)
Load both the fossology configuration and all the agent configurations.
GRegex * parse_agent_msg
Parses messages coming from the agents.
fo_conf * fo_config_load(char *rawname, GError **error)
Load the configuration information from the provided file.
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.
gboolean s_pid
The pid of the scheduler process.
log_t * main_log
The main log file for the scheduler.
GThreadPool * workers
Threads to handle incoming network communication.
#define TEST_ERROR(error,...)
void scheduler_signal(scheduler_t *scheduler)
Function that handles certain signals being delivered to the scheduler.
GThread * main_thread
Pointer to the main thread.
gchar * logdir
The directory to put the log file in.
void event_loop_destroy()
Frees any memory associated with the event queue.
Header file for the scheduler.
void test_agents(scheduler_t *scheduler)
Calls the agent test function for every type of agent.
void job_fail_event(scheduler_t *scheduler, job_t *job)
Events that causes a job to be marked a failed.
gchar * email_subject
The subject to be used for emails.
int running
The number of agents currently running on this host.
int32_t id
The identifier for this job.
gchar * process_name
The name of the scheduler process.