FOSSology  4.4.0
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 
39 const static char* sql_check = "\
40  SELECT * FROM agent \
41  WHERE agent_name = '%s' AND agent_rev='%s.%s'";
42 
44 const static char* sql_insert = "\
45  INSERT INTO agent (agent_name, agent_rev, agent_desc) \
46  VALUES ('%s', '%s.%s', '%s')";
47 
51 char* sysconfigdir = NULL;
52 
53 /* these will be freed in fo_scheduler_disconnect */
54 extern GRegex* fo_conf_parse;
55 extern GRegex* fo_conf_replace;
56 
65 
76 {
77  int processed = g_atomic_int_get(&items_processed);
78  // TODO these functions are not safe for a signal handler
79  fprintf(stdout, "HEART: %d %d\n", processed, alive);
80  fflush(stdout);
81  fflush(stderr);
82  alarm(ALARM_SECS);
83  alive = FALSE;
84 }
85 
94 {
95  PGresult* db_result = NULL;
96  char* db_sql = NULL;
97 
98  db_sql = g_strdup_printf(sql_check, module_name,
99  fo_config_get(sysconfig, module_name, "VERSION", NULL),
100  fo_config_get(sysconfig, module_name, "COMMIT_HASH", NULL));
101  db_result = PQexec(db_conn, db_sql);
102  if (PQresultStatus(db_result) != PGRES_TUPLES_OK)
103  {
104  fprintf(stderr, "FATAL %s.%d: unable to check agent table: %s",
105  __FILE__, __LINE__, PQresultErrorMessage(db_result));
106  fflush(stderr);
107  PQfinish(db_conn);
108  PQclear(db_result);
109  g_free(db_sql);
110  exit(252);
111  }
112 
113  if (PQntuples(db_result) != 1)
114  {
115  g_free(db_sql);
116  PQclear(db_result);
117 
118  db_sql = g_strdup_printf(sql_insert, module_name,
119  fo_config_get(sysconfig, module_name, "VERSION", NULL),
120  fo_config_get(sysconfig, module_name, "COMMIT_HASH", NULL),
121  fo_config_get(sysconfig, module_name, "DESCRIPTION", NULL));
122  db_result = PQexec(db_conn, db_sql);
123  if (PQresultStatus(db_result) != PGRES_COMMAND_OK)
124  {
125  fprintf(stderr, "FATAL %s.%d: unable to insert into agent table: %s",
126  __FILE__, __LINE__, PQresultErrorMessage(db_result));
127  fflush(stderr);
128  PQfinish(db_conn);
129  PQclear(db_result);
130  g_free(db_sql);
131  exit(251);
132  }
133  }
134 
135  g_free(db_sql);
136  PQclear(db_result);
137 }
138 
139 /* ************************************************************************** */
140 /* **** Global Functions **************************************************** */
141 /* ************************************************************************** */
142 
153 {
154  g_atomic_int_add(&items_processed, i);
155  alive = TRUE;
156 
157  fflush(stdout);
158  fflush(stderr);
159 }
160 
169 void fo_scheduler_connect_conf(int* argc, char** argv, PGconn** db_conn, char** db_conf)
170 {
171  /* locals */
172  GError* error = NULL;
173  GOptionContext* parsed;
174  fo_conf* version;
175  char fname[FILENAME_MAX + 1];
176 
177  char* db_config = NULL;
178  char* db_error = NULL;
179 
180  /* command line options */
181  GOptionEntry options[] =
182  {
183  {"config", 'c', 0, G_OPTION_ARG_STRING, &sysconfigdir, ""},
184  {"userID", 0, 0, G_OPTION_ARG_INT, &userID, ""},
185  {"groupID", 0, 0, G_OPTION_ARG_INT, &groupID, ""},
186  {"scheduler_start", 0, 0, G_OPTION_ARG_NONE, &sscheduler, ""},
187  {"jobId", 0, 0, G_OPTION_ARG_INT, &jobId, ""},
188  {NULL}
189  };
190 
191  /* initialize memory associated with agent connection */
192  module_name = g_strdup(basename(argv[0]));
193  sysconfigdir = DEFAULT_SETUP;
194  items_processed = 0;
195  valid = 0;
196  sscheduler = 0;
197  userID = -1;
198  groupID = -1;
199  agent_verbose = 0;
200  memset(buffer, 0, sizeof(buffer));
201 
202  if (sysconfig != NULL)
203  {
204  LOG_WARNING("fo_scheduler_connect() has already been called.");
205  sscheduler = 1;
206  return;
207  }
208 
209  if (getenv("FO_SYSCONFDIR"))
210  sysconfigdir = getenv("FO_SYSCONFDIR");
211 
212  /* parse command line options */
213  parsed = g_option_context_new("");
214  g_option_context_add_main_entries(parsed, options, NULL);
215  g_option_context_set_ignore_unknown_options(parsed, TRUE);
216  g_option_context_set_help_enabled(parsed, FALSE);
217  g_option_context_parse(parsed, argc, &argv, NULL);
218  g_option_context_free(parsed);
219 
220  /* load system configuration */
221  if (sysconfigdir)
222  {
223  snprintf(fname, FILENAME_MAX, "%s/%s", sysconfigdir, "fossology.conf");
224  sysconfig = fo_config_load(fname, &error);
225  if (error)
226  {
227  fprintf(stderr, "FATAL %s.%d: unable to open system configuration: %s\n",
228  __FILE__, __LINE__, error->message);
229  exit(255);
230  }
231 
232  snprintf(fname, FILENAME_MAX, "%s/mods-enabled/%s/VERSION",
234 
235  version = fo_config_load(fname, &error);
236  if (error)
237  {
238  fprintf(stderr, "FATAL %s.%d: unable to open VERSION configuration: %s\n",
239  __FILE__, __LINE__, error->message);
240  exit(254);
241  }
242 
243  fo_config_join(sysconfig, version, &error);
244  if (error)
245  {
246  fprintf(stderr, "FATAL %s.%d: unable to join configuration files: %s\n",
247  __FILE__, __LINE__, error->message);
248  exit(250);
249  }
250 
251 
252  fo_config_free(version);
253  }
254 
255  /* create the database connection */
256  if (db_conn)
257  {
258  db_config = g_strdup_printf("%s/Db.conf", sysconfigdir);
259  (*db_conn) = fo_dbconnect(db_config, &db_error);
260  if (db_conf)
261  *db_conf = db_config;
262  else
263  g_free(db_config);
264  if (db_error)
265  {
266  fprintf(stderr, "FATAL %s.%d: unable to open database connection: %s\n",
267  __FILE__, __LINE__, db_error);
268  fflush(stderr);
269  exit(253);
270  }
271  }
272 
273  /* send "OK" to the scheduler */
274  if (sscheduler)
275  {
276  /* check that the agent record exists */
277  if (db_conn)
279 
280  if (fo_config_has_key(sysconfig, module_name, "VERSION"))
281  fprintf(stdout, "VERSION: %s\n",
282  fo_config_get(sysconfig, module_name, "VERSION", &error));
283  else fprintf(stdout, "VERSION: unknown\n");
284  fprintf(stdout, "\nOK\n");
285  fflush(stdout);
286 
287  /* set up the heartbeat() */
288  signal(SIGALRM, fo_heartbeat);
289  alarm(ALARM_SECS);
290  }
291 
292  fflush(stdout);
293  fflush(stderr);
294 
295  alive = TRUE;
296 }
297 
319 void fo_scheduler_connect(int* argc, char** argv, PGconn** db_conn)
320 {
321  fo_scheduler_connect_conf(argc, argv, db_conn, NULL);
322 }
323 
329 void fo_scheduler_connect_dbMan(int* argc, char** argv, fo_dbManager** dbManager)
330 {
331  char* dbConf;
332  PGconn* dbConnection;
333  fo_scheduler_connect_conf(argc, argv, &dbConnection, &dbConf);
334  *dbManager = fo_dbManager_new_withConf(dbConnection, dbConf);
335  free(dbConf);
336 }
337 
346 void fo_scheduler_disconnect(int retcode)
347 {
348  if (module_name != NULL) {
349  /* send "CLOSED" to the scheduler */
350  if (sscheduler)
351  {
352  fo_heartbeat();
353  fprintf(stdout, "\nBYE %d\n", retcode);
354  fflush(stdout);
355 
356  valid = 0;
357  sscheduler = 0;
358 
359  g_free(module_name);
360  }
361 
362  if (strcmp(sysconfigdir, DEFAULT_SETUP))
363  g_free(sysconfigdir);
364 
366  }
367  g_regex_unref(fo_conf_parse);
368  g_regex_unref(fo_conf_replace);
369 
370  sysconfigdir = NULL;
371  sysconfig = NULL;
372  fo_conf_parse = NULL;
373  fo_conf_replace = NULL;
374  module_name = NULL;
375 
376  fflush(stdout);
377  fflush(stderr);
378 }
379 
401 {
402  fflush(stdout);
403 
404  /* get the next line from the scheduler and possibly WAIT */
405  while (fgets(buffer, sizeof(buffer), stdin) != NULL)
406  {
407  if (agent_verbose)
408  printf("\nNOTE: received %s\n", buffer);
409  if (strncmp(buffer, "CLOSE", 5) == 0)
410  break;
411  if (strncmp(buffer, "END", 3) == 0)
412  {
413  fprintf(stdout, "\nOK\n");
414  fflush(stdout);
415  fflush(stderr);
416  valid = 0;
417  continue;
418  }
419  else if (strncmp(buffer, "VERBOSE", 7) == 0)
420  {
421  agent_verbose = atoi(&buffer[8]);
422  valid = 0;
423  continue;
424  }
425  else if (strncmp(buffer, "VERSION", 7) == 0)
426  {
427  if (fo_config_has_key(sysconfig, module_name, "VERSION"))
428  fprintf(stdout, "VERSION: %s\n",
429  fo_config_get(sysconfig, module_name, "VERSION", NULL));
430  else fprintf(stdout, "VERSION: unknown\n");
431  fflush(stdout);
432  fflush(stderr);
433  valid = 0;
434  continue;
435  }
436 
437  buffer[strlen(buffer) - 1] = '\0';
438  valid = 1;
439  return buffer;
440  }
441 
442  valid = 0;
443 
444  fflush(stdout);
445  fflush(stderr);
446 
447  return NULL;
448 }
449 
459 {
460  return valid ? buffer : NULL;
461 }
462 
472 void fo_scheduler_set_special(int option, int value)
473 {
474  fprintf(stdout, "SPECIAL: %d %d\n", option, value);
475  fflush(stdout);
476 }
477 
491 {
492  int value;
493 
494  fprintf(stdout, "GETSPECIAL: %d\n", option);
495  fflush(stdout);
496 
497  if (fscanf(stdin, "VALUE: %d\n", &value) != 1)
498  return 0;
499  return value;
500 }
501 
508 {
509  return jobId;
510 }
511 
518 {
519  return userID;
520 }
521 
528 {
529  return groupID;
530 }
531 
542 char* fo_sysconfig(const char* sectionname, const char* variablename)
543 {
544  GError* error = NULL;
545  char* ret;
546 
547  ret = fo_config_get(
548  sysconfig,
549  sectionname,
550  variablename,
551  &error);
552 
553  fflush(stdout);
554  fflush(stderr);
555 
556  if (error)
557  {
558  g_clear_error(&error);
559  ret = NULL;
560  }
561 
562  return ret;
563 }
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
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