FOSSology  4.5.1
Open Source License Compliance by Open Source Software
libfossscheduler.c
Go to the documentation of this file.
1 /*
2  SPDX-FileCopyrightText: © 2010-2011 Hewlett-Packard Development Company, L.P.
3  SPDX-FileCopyrightText: © 2015 Siemens AG
4 
5  SPDX-License-Identifier: GPL-2.0-only
6 */
7 
13 /* local includes */
14 #include "libfossscheduler.h"
15 #include "libfossdb.h"
16 #include "fossconfig.h"
17 
18 /* unix includes */
19 #include <stdio.h>
20 #include <getopt.h>
21 #include <libgen.h>
22 #include <glib.h>
23 
24 /* ************************************************************************** */
25 /* **** Locals ************************************************************** */
26 /* ************************************************************************** */
27 
28 volatile gint items_processed;
29 volatile int alive;
30 char buffer[2048];
31 int valid;
33 int userID;
34 int groupID;
35 int jobId;
36 char* module_name = NULL;
37 int should_connect_to_db = 1;
38 
40 const static char* sql_check = "\
41  SELECT * FROM agent \
42  WHERE agent_name = '%s' AND agent_rev='%s.%s'";
43 
45 const static char* sql_insert = "\
46  INSERT INTO agent (agent_name, agent_rev, agent_desc) \
47  VALUES ('%s', '%s.%s', '%s')";
48 
52 char* sysconfigdir = NULL;
53 
54 /* these will be freed in fo_scheduler_disconnect */
55 extern GRegex* fo_conf_parse;
56 extern GRegex* fo_conf_replace;
57 
66 
77 {
78  int processed = g_atomic_int_get(&items_processed);
79  // TODO these functions are not safe for a signal handler
80  fprintf(stdout, "HEART: %d %d\n", processed, alive);
81  fflush(stdout);
82  fflush(stderr);
83  alarm(ALARM_SECS);
84  alive = FALSE;
85 }
86 
95 {
96  PGresult* db_result = NULL;
97  char* db_sql = NULL;
98 
99  db_sql = g_strdup_printf(sql_check, module_name,
100  fo_config_get(sysconfig, module_name, "VERSION", NULL),
101  fo_config_get(sysconfig, module_name, "COMMIT_HASH", NULL));
102  db_result = PQexec(db_conn, db_sql);
103  if (PQresultStatus(db_result) != PGRES_TUPLES_OK)
104  {
105  fprintf(stderr, "FATAL %s.%d: unable to check agent table: %s",
106  __FILE__, __LINE__, PQresultErrorMessage(db_result));
107  fflush(stderr);
108  PQfinish(db_conn);
109  PQclear(db_result);
110  g_free(db_sql);
111  exit(252);
112  }
113 
114  if (PQntuples(db_result) != 1)
115  {
116  g_free(db_sql);
117  PQclear(db_result);
118 
119  db_sql = g_strdup_printf(sql_insert, module_name,
120  fo_config_get(sysconfig, module_name, "VERSION", NULL),
121  fo_config_get(sysconfig, module_name, "COMMIT_HASH", NULL),
122  fo_config_get(sysconfig, module_name, "DESCRIPTION", NULL));
123  db_result = PQexec(db_conn, db_sql);
124  if (PQresultStatus(db_result) != PGRES_COMMAND_OK)
125  {
126  fprintf(stderr, "FATAL %s.%d: unable to insert into agent table: %s",
127  __FILE__, __LINE__, PQresultErrorMessage(db_result));
128  fflush(stderr);
129  PQfinish(db_conn);
130  PQclear(db_result);
131  g_free(db_sql);
132  exit(251);
133  }
134  }
135 
136  g_free(db_sql);
137  PQclear(db_result);
138 }
139 
140 /* ************************************************************************** */
141 /* **** Global Functions **************************************************** */
142 /* ************************************************************************** */
143 
154 {
155  g_atomic_int_add(&items_processed, i);
156  alive = TRUE;
157 
158  fflush(stdout);
159  fflush(stderr);
160 }
161 
170 void fo_scheduler_connect_conf(int* argc, char** argv, PGconn** db_conn, char** db_conf)
171 {
172  /* locals */
173  GError* error = NULL;
174  GOptionContext* parsed;
175  fo_conf* version;
176  char fname[FILENAME_MAX + 1];
177 
178  char* db_config = NULL;
179  char* db_error = NULL;
180 
181  /* command line options */
182  GOptionEntry options[] =
183  {
184  {"config", 'c', 0, G_OPTION_ARG_STRING, &sysconfigdir, ""},
185  {"userID", 0, 0, G_OPTION_ARG_INT, &userID, ""},
186  {"groupID", 0, 0, G_OPTION_ARG_INT, &groupID, ""},
187  {"scheduler_start", 0, 0, G_OPTION_ARG_NONE, &sscheduler, ""},
188  {"jobId", 0, 0, G_OPTION_ARG_INT, &jobId, ""},
189  {NULL}
190  };
191 
192  /* initialize memory associated with agent connection */
193  module_name = g_strdup(basename(argv[0]));
194  sysconfigdir = DEFAULT_SETUP;
195  items_processed = 0;
196  valid = 0;
197  sscheduler = 0;
198  userID = -1;
199  groupID = -1;
200  agent_verbose = 0;
201  memset(buffer, 0, sizeof(buffer));
202 
203  if (sysconfig != NULL)
204  {
205  LOG_WARNING("fo_scheduler_connect() has already been called.");
206  sscheduler = 1;
207  return;
208  }
209 
210  if (getenv("FO_SYSCONFDIR"))
211  sysconfigdir = getenv("FO_SYSCONFDIR");
212 
213  /* parse command line options */
214  parsed = g_option_context_new("");
215  g_option_context_add_main_entries(parsed, options, NULL);
216  g_option_context_set_ignore_unknown_options(parsed, TRUE);
217  g_option_context_set_help_enabled(parsed, FALSE);
218  g_option_context_parse(parsed, argc, &argv, NULL);
219  g_option_context_free(parsed);
220 
221  /* load system configuration */
222  if (sysconfigdir)
223  {
224  snprintf(fname, FILENAME_MAX, "%s/%s", sysconfigdir, "fossology.conf");
225  sysconfig = fo_config_load(fname, &error);
226  if (error)
227  {
228  fprintf(stderr, "FATAL %s.%d: unable to open system configuration: %s\n",
229  __FILE__, __LINE__, error->message);
230  exit(255);
231  }
232 
233  snprintf(fname, FILENAME_MAX, "%s/mods-enabled/%s/VERSION",
235 
236  version = fo_config_load(fname, &error);
237  if (error)
238  {
239  fprintf(stderr, "FATAL %s.%d: unable to open VERSION configuration: %s\n",
240  __FILE__, __LINE__, error->message);
241  exit(254);
242  }
243 
244  fo_config_join(sysconfig, version, &error);
245  if (error)
246  {
247  fprintf(stderr, "FATAL %s.%d: unable to join configuration files: %s\n",
248  __FILE__, __LINE__, error->message);
249  exit(250);
250  }
251 
252 
253  fo_config_free(version);
254  }
255 
256  /* create the database connection only if needed */
257  if (db_conn && should_connect_to_db) // Add a condition
258  {
259  db_config = g_strdup_printf("%s/Db.conf", sysconfigdir);
260  (*db_conn) = fo_dbconnect(db_config, &db_error);
261  if (db_conf)
262  *db_conf = db_config;
263  else
264  g_free(db_config);
265  if (db_error)
266  {
267  fprintf(stderr, "FATAL %s.%d: unable to open database connection: %s\n",
268  __FILE__, __LINE__, db_error);
269  fflush(stderr);
270  exit(253);
271  }
272  }
273 
274  /* send "OK" to the scheduler */
275  if (sscheduler)
276  {
277  /* check that the agent record exists */
278  if (db_conn)
280 
281  if (fo_config_has_key(sysconfig, module_name, "VERSION"))
282  fprintf(stdout, "VERSION: %s\n",
283  fo_config_get(sysconfig, module_name, "VERSION", &error));
284  else fprintf(stdout, "VERSION: unknown\n");
285  fprintf(stdout, "\nOK\n");
286  fflush(stdout);
287 
288  /* set up the heartbeat() */
289  signal(SIGALRM, fo_heartbeat);
290  alarm(ALARM_SECS);
291  }
292 
293  fflush(stdout);
294  fflush(stderr);
295 
296  alive = TRUE;
297 }
298 
320 void fo_scheduler_connect(int* argc, char** argv, PGconn** db_conn)
321 {
322  fo_scheduler_connect_conf(argc, argv, db_conn, NULL);
323 }
324 
330 void fo_scheduler_connect_dbMan(int* argc, char** argv, fo_dbManager** dbManager)
331 {
332  char* dbConf;
333  PGconn* dbConnection;
334  fo_scheduler_connect_conf(argc, argv, &dbConnection, &dbConf);
335  *dbManager = fo_dbManager_new_withConf(dbConnection, dbConf);
336  free(dbConf);
337 }
338 
347 void fo_scheduler_disconnect(int retcode)
348 {
349  if (module_name != NULL) {
350  /* send "CLOSED" to the scheduler */
351  if (sscheduler)
352  {
353  fo_heartbeat();
354  fprintf(stdout, "\nBYE %d\n", retcode);
355  fflush(stdout);
356 
357  valid = 0;
358  sscheduler = 0;
359 
360  g_free(module_name);
361  }
362 
363  if (strcmp(sysconfigdir, DEFAULT_SETUP))
364  g_free(sysconfigdir);
365 
367  }
368  g_regex_unref(fo_conf_parse);
369  g_regex_unref(fo_conf_replace);
370 
371  sysconfigdir = NULL;
372  sysconfig = NULL;
373  fo_conf_parse = NULL;
374  fo_conf_replace = NULL;
375  module_name = NULL;
376 
377  fflush(stdout);
378  fflush(stderr);
379 }
380 
402 {
403  fflush(stdout);
404 
405  /* get the next line from the scheduler and possibly WAIT */
406  while (fgets(buffer, sizeof(buffer), stdin) != NULL)
407  {
408  if (agent_verbose)
409  printf("\nNOTE: received %s\n", buffer);
410  if (strncmp(buffer, "CLOSE", 5) == 0)
411  break;
412  if (strncmp(buffer, "END", 3) == 0)
413  {
414  fprintf(stdout, "\nOK\n");
415  fflush(stdout);
416  fflush(stderr);
417  valid = 0;
418  continue;
419  }
420  else if (strncmp(buffer, "VERBOSE", 7) == 0)
421  {
422  agent_verbose = atoi(&buffer[8]);
423  valid = 0;
424  continue;
425  }
426  else if (strncmp(buffer, "VERSION", 7) == 0)
427  {
428  if (fo_config_has_key(sysconfig, module_name, "VERSION"))
429  fprintf(stdout, "VERSION: %s\n",
430  fo_config_get(sysconfig, module_name, "VERSION", NULL));
431  else fprintf(stdout, "VERSION: unknown\n");
432  fflush(stdout);
433  fflush(stderr);
434  valid = 0;
435  continue;
436  }
437 
438  buffer[strlen(buffer) - 1] = '\0';
439  valid = 1;
440  return buffer;
441  }
442 
443  valid = 0;
444 
445  fflush(stdout);
446  fflush(stderr);
447 
448  return NULL;
449 }
450 
460 {
461  return valid ? buffer : NULL;
462 }
463 
473 void fo_scheduler_set_special(int option, int value)
474 {
475  fprintf(stdout, "SPECIAL: %d %d\n", option, value);
476  fflush(stdout);
477 }
478 
492 {
493  int value;
494 
495  fprintf(stdout, "GETSPECIAL: %d\n", option);
496  fflush(stdout);
497 
498  if (fscanf(stdin, "VALUE: %d\n", &value) != 1)
499  return 0;
500  return value;
501 }
502 
509 {
510  return jobId;
511 }
512 
519 {
520  return userID;
521 }
522 
529 {
530  return groupID;
531 }
532 
543 char* fo_sysconfig(const char* sectionname, const char* variablename)
544 {
545  GError* error = NULL;
546  char* ret;
547 
548  ret = fo_config_get(
549  sysconfig,
550  sectionname,
551  variablename,
552  &error);
553 
554  fflush(stdout);
555  fflush(stderr);
556 
557  if (error)
558  {
559  g_clear_error(&error);
560  ret = NULL;
561  }
562 
563  return ret;
564 }
void fo_config_free(fo_conf *conf)
Frees the memory associated with the internal configuration data structures.
Definition: fossconfig.c:506
fo_conf * fo_config_load(char *rawname, GError **error)
Load the configuration information from the provided file.
Definition: fossconfig.c:275
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,...
Definition: fossconfig.c:336
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.
Definition: fossconfig.c:531
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.
Definition: fossconfig.c:668
FOSSology library to read config file.
PGconn * fo_dbconnect(char *DBConfFile, char **ErrorBuf)
Connect to a database. The default is Db.conf.
Definition: libfossdb.c:29
void fo_scheduler_disconnect(int retcode)
Disconnect the scheduler connection.
void fo_scheduler_heart(int i)
This function must be called by agents to let the scheduler know they are alive and how many items th...
int groupID
The id of the group of the user that created the job.
void fo_heartbeat()
Internal function to send a heartbeat to the scheduler along with the number of items processed.
volatile int alive
If the agent has updated with a hearbeat.
volatile gint items_processed
The number of items processed by the agent.
void fo_scheduler_set_special(int option, int value)
Sets something special about the agent within the scheduler.
char * fo_sysconfig(const char *sectionname, const char *variablename)
gets a system configuration variable from the configuration data.
int jobId
The id of the job.
int agent_verbose
Common verbose flags for the agents, this is used so that the scheduler can change the verbose level ...
int fo_scheduler_get_special(int option)
Gets if a particular special attribute is set in the scheduler.
static const char * sql_insert
void fo_scheduler_connect_dbMan(int *argc, char **argv, fo_dbManager **dbManager)
Make a connection from an agent to the scheduler and create a DB manager as well.
char * module_name
The name of the agent.
char * sysconfigdir
int fo_scheduler_userID()
Gets the id of the user that created the job that the agent is running.
static const char * sql_check
Default: connect to DB unless explicitly disabled.
char * fo_scheduler_current()
Get the last read string from the scheduler.
GRegex * fo_conf_parse
Regex for parsing.
Definition: fossconfig.c:57
int fo_scheduler_jobId()
Gets the id of the job that the agent is running.
char * fo_scheduler_next()
Get the next data to process from the scheduler.
void fo_scheduler_connect(int *argc, char **argv, PGconn **db_conn)
Establish a connection between an agent and the scheduler.
int fo_scheduler_groupID()
Gets the id of the group that created the job that the agent is running.
int sscheduler
Whether the agent was started by the scheduler.
fo_conf * sysconfig
GRegex * fo_conf_replace
Regex for replace.
Definition: fossconfig.c:58
int userID
The id of the user that created the job.
void fo_scheduler_connect_conf(int *argc, char **argv, PGconn **db_conn, char **db_conf)
Establish a connection between an agent and the scheduler.
void fo_check_agentdb(PGconn *db_conn)
Checks that the agent is already in the agent table.
int valid
If the information stored in buffer is valid.
char buffer[2048]
The last thing received from the scheduler.
fo_dbManager * dbManager
fo_dbManager object
Definition: process.c:16
const ALARM_SECS
Definition: Agent.php:32
PGconn * db_conn
The connection to Database.
Definition: pkgagent.c:22
FUNCTION int processed(PGconn *pgConn, int agent_pk, int nomos_agent_pk, int pfile_pk, int uploadtree_pk, int bucketpool_pk, int bucket_pk)
Has this pfile or uploadtree_pk already been bucket processed? This only works if the bucket has been...
Definition: validate.c:139