26 #include <emailformatter.h> 29 #include <libfossdb.h> 48 #define EMAIL_ERROR(...) { \ 49 WARNING(__VA_ARGS__); \ 53 #define EMAIL_BUILD_CMD "%s %s -s '%s' %s" 54 #define DEFAULT_HEADER "FOSSology scan complete\nmessage:\"" 55 #define DEFAULT_FOOTER "\"" 56 #define DEFAULT_SUBJECT "FOSSology scan complete\n" 57 #define DEFAULT_COMMAND "/usr/bin/mailx" 59 #define min(x, y) (x < y ? x : y) 98 gchar* m_str = g_match_info_fetch(match, 1);
102 GPtrArray* rows = NULL;
112 if(strcmp(m_str,
"UPLOADNAME") == 0)
117 if(PQresultStatus(db_result) != PGRES_TUPLES_OK)
119 g_string_append_printf(ret,
120 "[ERROR: unable to select upload file name for job %d]", job->
id);
122 else if(PQntuples(db_result) == 0)
125 g_string_append_printf(ret,
126 "[File has been deleted by job %d]", job->
id);
128 g_string_append_printf(ret,
129 "[ERROR: file has not been uploaded or unpacked yet for job %d]", job->
id);
133 g_string_append(ret, PQgetvalue(db_result, 0, 0));
145 else if(strcmp(m_str,
"BROWSELINK") == 0)
150 if(PQresultStatus(db_result) != PGRES_TUPLES_OK)
152 g_string_append_printf(ret,
153 "[ERROR: unable to select upload primary key for job %d]", job->
id);
155 else if(PQntuples(db_result) == 0)
158 g_string_append_printf(ret,
159 "[File has been deleted by job %d]", job->
id);
161 g_string_append_printf(ret,
162 "[ERROR: file has not been uploaded or unpacked yet for job %d]", job->
id);
166 g_string_append_printf(ret,
167 "http://%s?mod=browse&upload=%s&item=%s&show=detail",
168 fossy_url, PQgetvalue(db_result, 0, 0), PQgetvalue(db_result, 0, 1));
179 else if(strcmp(m_str,
"JOBQUEUELINK") == 0)
184 if(PQresultStatus(db_result) != PGRES_TUPLES_OK)
186 g_string_append_printf(ret,
187 "[ERROR: unable to select file name for upload %d]", job->
id);
191 g_string_append_printf(ret,
"http://%s?mod=showjobs&upload=%s",
192 fossy_url, PQgetvalue(db_result, 0, 0));
203 else if(strcmp(m_str,
"SCHEDULERLOG") == 0)
205 g_string_append_printf(ret,
"http://%s?mod=showjobs&job=%d",
213 else if(strcmp(m_str,
"UPLOADFOLDERNAME") == 0)
218 if(PQresultStatus(db_result) != PGRES_TUPLES_OK || PQntuples(db_result) == 0)
220 g_string_append_printf(ret,
221 "[NOTICE: unable to select folder name for upload %d]", job->
id);
225 rows = g_ptr_array_new();
226 GString *foldername = g_string_new(PQgetvalue(db_result, 0, 0));
227 guint folder_pk = atoi(PQget(db_result, 0,
"folder_pk"));
228 g_ptr_array_add(rows, foldername);
240 while(PQresultStatus(db_result) == PGRES_TUPLES_OK && PQntuples(db_result) == 1)
242 GString *foldername = g_string_new(PQgetvalue(db_result, 0, 0));
243 guint folder_pk = atoi(PQget(db_result, 0,
"folder_pk"));
244 g_ptr_array_add(rows, foldername);
255 for(i = rows->len - 1; i > 0; i--)
257 GString *folder = g_ptr_array_index(rows, i);
258 g_string_append(ret, folder->str);
259 g_string_append(ret,
" / ");
261 GString *folder = g_ptr_array_index(rows, 0);
262 g_string_append(ret, folder->str);
263 g_ptr_array_free(rows, TRUE);
274 else if(strcmp(m_str,
"JOBRESULT") == 0)
278 case JB_COMPLETE: g_string_append(ret,
"COMPLETE");
break;
279 case JB_FAILED: g_string_append(ret,
"FAILED");
break;
281 g_string_append_printf(ret,
"[ERROR: illegal job status \"%s\"]",
282 job_status_strings[job->
status]);
291 else if(strcmp(m_str,
"AGENTSTATUS") == 0)
295 if(PQresultStatus(db_result) != PGRES_TUPLES_OK)
297 g_string_append_printf(ret,
298 "[ERROR: unable to select agent info for job %d]", job->
id);
302 rows = g_ptr_array_sized_new(PQntuples(db_result));
307 for(i = 0; i < PQntuples(db_result) && ret; i++)
310 data->
id = atoi(PQget(db_result, i,
"jq_pk"));
311 data->
agent = g_string_new(PQget(db_result, i,
"jq_type"));
312 if(atoi(PQget(db_result, i,
"jq_end_bits")) == 1)
320 g_ptr_array_add(rows, data);
324 g_ptr_array_free(rows, TRUE);
334 else if(strcmp(m_str,
"DB") == 0)
336 g_string_append(ret,
"[DB. syntax is NOT IMPLEMENTED]");
385 if(PQresultStatus(db_result) != PGRES_TUPLES_OK)
387 PQ_ERROR(db_result,
"unable to check job status for jq_pk %d", job->
id);
394 if(PQntuples(db_result) != 0)
406 for(i = 0; i < PQntuples(db_result) && ret; i++)
408 id = atoi(PQget(db_result, i,
"jq_pk"));
409 if(
id != job->
id && g_tree_lookup(scheduler->
job_list, &
id) != NULL)
417 for(i = 0; i < PQntuples(db_result) && ret; i++)
419 if(atoi(PQget(db_result, i,
"jq_end_bits")) == (1 << 1))
448 char* final_cmd = NULL;
452 job_status curr_status = job->
status;
461 if(PQresultStatus(db_result) != PGRES_TUPLES_OK || PQntuples(db_result) == 0)
463 PQ_ERROR(db_result,
"unable to select the upload id for job %d", j_id);
467 upload_id = atoi(PQgetvalue(db_result, 0, 0));
472 if(PQresultStatus(db_result) != PGRES_TUPLES_OK)
474 PQ_ERROR(db_result,
"unable to check common uploads to job %d", j_id);
481 if(PQresultStatus(db_result) != PGRES_TUPLES_OK)
483 PQ_ERROR(db_result,
"unable to access email info for job %d", j_id);
490 if(PQntuples(db_result) == 0)
495 if(PQresultStatus(db_result) != PGRES_TUPLES_OK || PQntuples(db_result) == 0)
497 PQ_ERROR(db_result,
"unable to access email info for job %d", j_id);
502 if(PQget(db_result, 0,
"email_notify")[0] ==
'y')
507 email_txt = g_string_new(
"");
509 g_string_append(email_txt, job->
message == NULL ?
"" : job->
message);
518 val = g_regex_replace_eval(scheduler->
parse_db_email, email_txt->str,
519 email_txt->len, 0, 0, (GRegexEvalCallback)
email_replace, &args, NULL);
523 val = email_txt->str;
527 if(final_cmd == NULL)
531 g_string_free(email_txt, TRUE);
534 if((mail_io = popen(final_cmd,
"w")) != NULL)
536 fprintf(mail_io,
"%s", val);
538 retcode = WEXITSTATUS(pclose(mail_io));
546 WARNING(
"Unable to spawn email notification process: '%s'.\n",
549 job->
status = curr_status;
553 g_string_free(email_txt, TRUE);
570 int email_notify, fd;
571 struct stat header_sb = {};
572 struct stat footer_sb = {};
574 GError* error = NULL;
584 fname = g_strdup_printf(
"%s/%s", scheduler->
sysconfigdir,
587 EMAIL_ERROR(
"email notification setting group \"[EMAILNOTIFY]\" missing. Using defaults");
589 EMAIL_ERROR(
"email notification setting key \"header\" missing. Using default header");
590 if(email_notify && (fd = open(fname, O_RDONLY)) == -1)
591 EMAIL_ERROR(
"unable to open file for email header: %s", fname);
592 if(email_notify && fstat(fd, &header_sb) == -1)
593 EMAIL_ERROR(
"unable to fstat email header: %s", fname);
594 if(email_notify && (scheduler->
email_header = mmap(NULL, header_sb.st_size, PROT_READ,
595 MAP_SHARED, fd, 0)) == MAP_FAILED)
596 EMAIL_ERROR(
"unable to mmap email header: %s", fname);
602 fname = g_strdup_printf(
"%s/%s", scheduler->
sysconfigdir,
607 EMAIL_ERROR(
"email notification setting key \"footer\" missing. Using default footer");
608 if(email_notify && (fd = open(fname, O_RDONLY)) == -1)
609 EMAIL_ERROR(
"unable to open file for email footer: %s", fname);
610 if(email_notify && fstat(fd, &footer_sb) == -1)
611 EMAIL_ERROR(
"unable to fstat email footer: %s", fname);
612 if(email_notify && (scheduler->
email_footer = mmap(NULL, footer_sb.st_size, PROT_READ,
613 MAP_SHARED, fd, 0)) == MAP_FAILED)
614 EMAIL_ERROR(
"unable to mmap email footer: %s", fname);
625 EMAIL_ERROR(
"email notification setting key \"subject\" missing. Using default subject");
636 EMAIL_ERROR(
"email notification setting key \"client\" missing. Using default client");
675 char sqltmp[1024] = {0};
685 "jq_args",
"jq_end_bits",
"jq_endtext",
"jq_endtime",
"jq_host",
686 "jq_itemsprocessed",
"jq_job_fk",
"jq_log",
"jq_pk",
"jq_runonpfile",
687 "jq_schedinfo",
"jq_starttime",
"jq_type" }},
688 {
"sysconfig", 2, {
"conf_value",
"variablename" }},
689 {
"job", 2, {
"job_pk",
"job_upload_fk" }},
690 {
"folder", 2, {
"folder_name",
"folder_pk" }},
691 {
"foldercontents", 3, {
"child_id",
"foldercontents_mode",
"parent_fk" }},
692 {
"upload", 2, {
"upload_filename",
"upload_pk" }},
693 {
"uploadtree", 3, {
"parent",
"upload_fk",
"uploadtree_pk" }},
694 {
"users", 4, {
"email_notify",
"user_email",
"user_name",
"user_pk" }},
700 for(curr = cols; curr->
table; curr++)
703 sql = g_string_new(sqltmp);
704 g_string_append_printf(sql,
"'%s' AND column_name IN (", curr->
table);
705 for(i = 0; i < curr->
ncols; i++)
707 g_string_append_printf(sql,
"'%s'", curr->
columns[i]);
708 if(i != curr->
ncols - 1)
709 g_string_append(sql,
", ");
711 g_string_append(sql,
") ORDER BY column_name");
715 if(PQresultStatus(db_result) != PGRES_TUPLES_OK)
718 PQ_ERROR(db_result,
"could not check database tables");
723 if(PQntuples(db_result) != curr->
ncols)
729 for(i = 0, curr_row = 0; i < curr->
ncols; i++)
731 if(curr_row>=PQntuples(db_result) || strcmp(PQgetvalue(db_result, curr_row, 0), curr->
columns[i]) != 0)
743 g_string_free(sql, TRUE);
748 log_printf(
"FATAL %s.%d: Scheduler did not pass database check\n", __FILE__, __LINE__);
749 log_printf(
"FATAL %s.%d: Running fo_postinstall should fix the database schema\n", __FILE__, __LINE__);
763 gchar* dbconf = NULL;
766 dbconf = g_strdup_printf(
"%s/Db.conf", configdir);
769 if(error || PQstatus(ret) != CONNECTION_OK)
770 FATAL(
"Unable to connect to the database: \"%s\"", error);
790 if(PQresultStatus(db_result) == PGRES_TUPLES_OK && PQntuples(db_result) != 0)
791 scheduler->
host_url = g_strdup(PQgetvalue(db_result, 0, 0));
816 PGresult* ret = NULL;
818 V_SPECIAL(
"DATABASE: exec \"%s\"\n", sql);
820 ret = PQexec(scheduler->
db_conn, sql);
821 if(ret == NULL || PQstatus(scheduler->
db_conn) != CONNECTION_OK)
826 ret = PQexec(scheduler->
db_conn, sql);
841 if(PQresultStatus(db_result) != PGRES_COMMAND_OK)
842 PQ_ERROR(db_result,
"failed to perform database exec: %s", sql);
856 PGresult* pri_result;
859 char* value, * type, * host, * pfile, * parent, *jq_cmd_args;
864 WARNING(
"scheduler is closing, will not check the job queue");
870 if(PQresultStatus(db_result) != PGRES_TUPLES_OK)
872 PQ_ERROR(db_result,
"database update failed on call to PQexec");
876 V_SPECIAL(
"DB: retrieved %d entries from the job queue\n",
877 PQntuples(db_result));
878 for(i = 0; i < PQntuples(db_result); i++)
881 j_id = atoi(PQget(db_result, i,
"jq_pk"));
882 if(g_tree_lookup(scheduler->
job_list, &j_id) != NULL)
886 parent = PQget(db_result, i,
"jq_job_fk");
887 host = PQget(db_result, i,
"jq_host");
888 type = PQget(db_result, i,
"jq_type");
889 pfile = PQget(db_result, i,
"jq_runonpfile");
890 value = PQget(db_result, i,
"jq_args");
891 jq_cmd_args =PQget(db_result, i,
"jq_cmd_args");
894 host = (strlen(host) == 0) ? NULL : host;
895 if(jq_cmd_args != NULL)
896 jq_cmd_args = (strlen(jq_cmd_args) == 0) ? NULL : jq_cmd_args;
898 V_DATABASE(
"DB: jq_pk[%d] added:\n jq_type = %s\n jq_host = %s\n " 899 "jq_runonpfile = %d\n jq_args = %s\n jq_cmd_args = %s\n",
900 j_id, type, host, (pfile != NULL && pfile[0] !=
'\0'), value, jq_cmd_args);
903 if(strcmp(type,
"command") == 0)
905 WARNING(
"DB: commands in the job queue not implemented," 906 " using the interface api instead");
912 if(PQresultStatus(pri_result) != PGRES_TUPLES_OK)
914 PQ_ERROR(pri_result,
"database update failed on call to PQexec");
917 if(PQntuples(pri_result)==0)
919 WARNING(
"can not find the user information of job_pk %s\n", parent);
925 atoi(PQget(pri_result, 0,
"user_pk")),
926 atoi(PQget(pri_result, 0,
"group_pk")),
927 atoi(PQget(pri_result, 0,
"job_priority")), jq_cmd_args);
928 job_set_data(scheduler, job, value, (pfile && pfile[0] !=
'\0'));
945 if(PQresultStatus(db_result) != PGRES_COMMAND_OK)
946 PQ_ERROR(db_result,
"failed to reset job queue");
967 case JB_NOT_AVAILABLE:
case JB_CHECKEDOUT:
970 sql = g_strdup_printf(
jobsql_started,
"localhost", getpid(), j_id);
988 if(sql != NULL && PQresultStatus(db_result) != PGRES_COMMAND_OK)
989 PQ_ERROR(db_result,
"failed to update job status in job queue");
991 if(status == JB_COMPLETE || status == JB_FAILED)
1021 sql = g_strdup_printf(
jobsql_log, log_name, j_id);
1035 PGresult* db_result;
1039 if(sql != NULL && PQresultStatus(db_result) != PGRES_COMMAND_OK)
1040 PQ_ERROR(db_result,
"failed to change job queue entry priority");
1053 PGresult* db_result_smtp;
1055 GString* client_cmd;
1056 GHashTable* smtpvariables;
1057 char* temp_smtpvariable;
1058 char* final_command;
1061 if(PQresultStatus(db_result_smtp) != PGRES_TUPLES_OK || PQntuples(db_result_smtp) == 0)
1063 PQ_ERROR(db_result_smtp,
"unable to get conf variables for SMTP from sysconfig");
1066 client_cmd = g_string_new(
"");
1067 smtpvariables = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
1068 for(i = 0; i < PQntuples(db_result_smtp); i++)
1070 if(PQget(db_result_smtp, i,
"conf_value")[0])
1072 g_hash_table_insert(smtpvariables, g_strdup(PQget(db_result_smtp, i,
"variablename")),
1073 g_strdup(PQget(db_result_smtp, i,
"conf_value")));
1077 if(g_hash_table_contains(smtpvariables,
"SMTPHostName") && g_hash_table_contains(smtpvariables,
"SMTPPort"))
1079 g_string_append_printf(client_cmd,
" -S smtp=\"%s:%s\"", (
char *)g_hash_table_lookup(smtpvariables,
"SMTPHostName"),
1080 (
char *)g_hash_table_lookup(smtpvariables,
"SMTPPort"));
1081 if(g_hash_table_contains(smtpvariables,
"SMTPStartTls"))
1083 temp_smtpvariable = (
char *)g_hash_table_lookup(smtpvariables,
"SMTPStartTls");
1084 if(g_strcmp0(temp_smtpvariable,
"1") == 0)
1086 g_string_append_printf(client_cmd,
" -S smtp-use-starttls");
1089 if(g_hash_table_contains(smtpvariables,
"SMTPAuth"))
1091 temp_smtpvariable = (
char *)g_hash_table_lookup(smtpvariables,
"SMTPAuth");
1092 if(g_strcmp0(temp_smtpvariable,
"L") == 0)
1094 g_string_append_printf(client_cmd,
" -S smtp-auth=login");
1096 else if(g_strcmp0(temp_smtpvariable,
"P") == 0)
1098 g_string_append_printf(client_cmd,
" -S smtp-auth=plain");
1102 if(g_hash_table_contains(smtpvariables,
"SMTPAuthUser"))
1104 g_string_append_printf(client_cmd,
" -S smtp-auth-user=\"%s\"" ,
1105 (
char *)g_hash_table_lookup(smtpvariables,
"SMTPAuthUser"));
1108 if(g_hash_table_contains(smtpvariables,
"SMTPFrom"))
1110 g_string_append_printf(client_cmd,
" -S from=\"%s\"",
1111 (
char *)g_hash_table_lookup(smtpvariables,
"SMTPFrom"));
1113 if(g_hash_table_contains(smtpvariables,
"SMTPAuthPasswd"))
1115 g_string_append_printf(client_cmd,
" -S smtp-auth-password=\"%s\"",
1116 (
char *)g_hash_table_lookup(smtpvariables,
"SMTPAuthPasswd"));
1118 if(g_hash_table_contains(smtpvariables,
"SMTPSslVerify"))
1120 temp_smtpvariable = (
char *)g_hash_table_lookup(smtpvariables,
"SMTPSslVerify");
1121 g_string_append(client_cmd,
" -S ssl-verify=");
1122 if(g_strcmp0(temp_smtpvariable,
"I") == 0)
1124 g_string_append(client_cmd,
"ignore");
1126 else if(g_strcmp0(temp_smtpvariable,
"S") == 0)
1128 g_string_append(client_cmd,
"strict");
1130 else if(g_strcmp0(temp_smtpvariable,
"W") == 0)
1132 g_string_append(client_cmd,
"warn");
1135 temp_smtpvariable = NULL;
1141 NOTIFY(
"Unable to send email. SMTP host or port not found in the configuration.\n" 1142 "Please check Configuration Variables.");
1143 final_command = NULL;
1145 g_hash_table_destroy(smtpvariables);
1146 g_string_free(client_cmd, TRUE);
1147 return final_command;
PGconn * db_conn
The database connection.
gboolean status
Agent status (Pass => true, fail => false)
const char * jobsql_email_job
gchar * email_header
The beginning of the email message.
gboolean default_footer
Is the footer the default footer.
char * columns[13]
The columns that the scheduler uses for this table.
const char * jobsql_started
GTree * meta_agents
List of all meta agents available to the scheduler.
const char * jobsql_paused
const char * jobsql_resetqueue
void database_reset_queue(scheduler_t *scheduler)
Resets any jobs in the job queue that are not completed.
int closing
Set if scheduler is shutting down.
const char * upload_common
GRegex * parse_db_email
Parses database email text.
const char * jobsql_processed
fo_conf * sysconfig
Configuration information loaded from the configuration file.
Store the results of a regex match.
#define DEFAULT_HEADER
Default email header.
int is_meta_special(meta_agent_t *ma, int special_type)
tests if a particular meta agent has a specific special flag set
char * table
The name of the table to check columns in.
gboolean default_header
Is the header the default header.
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 database_update_event(scheduler_t *scheduler, void *unused)
Checks the job queue for any new entries.
#define EMAIL_BUILD_CMD
Email command format.
const char * jobsql_complete
#define DEFAULT_SUBJECT
Default email subject.
void database_update_job(scheduler_t *scheduler, job_t *job, job_status status)
Change the status of a job in the database.
void database_job_log(int j_id, char *log_name)
Enters the name of the log file for a job into the database.
#define DEFAULT_COMMAND
Default email command to use.
gchar * foss_url
Fossology URL string.
gchar * sysconfigdir
The system directory that contain fossology.conf.
const char * jobsql_restart
GSequence * job_queue
heap of jobs that still need to be started
PGresult * database_exec(scheduler_t *scheduler, const char *sql)
Executes an sql statement for the scheduler.
const char * url_checkout
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.
void job_set_data(scheduler_t *scheduler, job_t *job, char *data, int sql)
const char * jobsql_email
const char * basic_checkout
#define SAG_NOEMAIL
This agent should not send notification emails.
const char * jobsql_jobendbits
GTree * job_list
List of jobs that have been created.
#define PQ_ERROR(pg_r,...)
job_t * job
Current job structure.
#define SafePQclear(pgres)
const char * jobsql_anyrunnable
gchar * email_footer
The end of the email message.
Required group is missing.
void database_exec_event(scheduler_t *scheduler, char *sql)
char * agent_type
The type of agent used to analyze the data.
gchar * email_command
The command that will sends emails, usually mailx.
scheduler_t * scheduler
Current scheduler reference.
const char * jobsql_priority
static PGconn * database_connect(gchar *configdir)
Creates and performs error checking for a new database connection.
const char * parent_folder_name
Data type used to check if the database is correct.
const char * jobsql_information
void database_job_processed(int j_id, int num)
Updates the number of items that a job queue entry has processed.
guint id
Job queue id for the agent.
const char * jobsql_failed
GString * agent
Agent name.
Header file with agent related operations.
uint8_t ncols
The number of columns in the table that the scheduler uses.
gchar * message
Message that will be sent with job notification email.
const char * check_scheduler_tables
const char * jobsql_jobinfo
#define DEFAULT_FOOTER
Default email footer.
const char * select_upload_fk
static gboolean email_replace(const GMatchInfo *match, GString *ret, email_replace_args *args)
Replaces the variables that are in the header and footer files.
job_t * job_init(GTree *job_list, GSequence *job_queue, char *type, char *host, int id, int parent_id, int user_id, int group_id, int priority, char *jq_cmd_args)
Create a new job.
static void check_tables(scheduler_t *scheduler)
Checks that any part of the database used by the scheduler is correct.
static void email_notification(scheduler_t *scheduler, job_t *job)
void database_job_priority(scheduler_t *scheduler, job_t *job, int priority)
Changes the priority of a job queue entry in the database.
static gint email_checkjobstatus(scheduler_t *scheduler, job_t *job)
Checks the database for the status of the job.
job_status status
The current status for the job.
PGconn * fo_dbconnect(char *DBConfFile, char **ErrorBuf)
Connect to a database. The default is Db.conf.
gchar * email_subject
The subject to be used for emails.
char * get_email_command(scheduler_t *scheduler, char *user_email)
Build command to run to send email.
int32_t id
The identifier for this job.