FOSSology  3.2.0rc1
Open Source License Compliance by Open Source Software
fo_cli.c
Go to the documentation of this file.
1 /* **************************************************************
2 Copyright (C) 2010, 2011, 2012 Hewlett-Packard Development Company, L.P.
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 version 2 as published by the Free Software Foundation.
7 
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 
13 You should have received a copy of the GNU General Public License along
14 with this program; if not, write to the Free Software Foundation, Inc.,
15 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 ************************************************************** */
22 /* std library includes */
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 /* unix includes */
28 #include <ctype.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <pwd.h>
32 #include <sys/socket.h>
33 #include <sys/types.h>
34 #include <netinet/in.h>
35 #include <netdb.h>
36 #include <unistd.h>
37 
38 /* other library includes */
39 #include <libfossology.h>
40 #include <glib.h>
41 
42 #define P_WIDTH 27
43 #define F_WIDTH 10
44 
45 #define vprintf(...) if(verbose) printf(__VA_ARGS__);
46 
47 int response = 1;
48 int s;
49 int verbose;
51 
52 /* ************************************************************************** */
53 /* **** utility functions *************************************************** */
54 /* ************************************************************************** */
55 
65 int socket_connect(char* host, char* port)
66 {
67  int fd;
68  struct addrinfo hints;
69  struct addrinfo* servs, * curr = NULL;
70 
71  memset(&hints, 0, sizeof(hints));
72  hints.ai_family = AF_UNSPEC;
73  hints.ai_socktype = SOCK_STREAM;
74  if(getaddrinfo(host, port, &hints, &servs) == -1)
75  {
76  fprintf(stderr, "ERROR: %s.%d: unable to connect to %s port: %s\n",
77  __FILE__, __LINE__, host, port);
78  fprintf(stderr, "ERROR: errno: %s\n", strerror(errno));
79  return -1;
80  }
81 
82  for(curr = servs; curr != NULL; curr = curr->ai_next)
83  {
84  if((fd = socket(curr->ai_family, hints.ai_socktype, curr->ai_protocol)) < 0)
85  continue;
86 
87  if(connect(fd, curr->ai_addr, curr->ai_addrlen) == -1)
88  continue;
89 
90  break;
91  }
92 
93  if(curr == NULL)
94  {
95  fprintf(stderr, "ERROR: %s.%d: unable to connect to %s port: %s\n",
96  __FILE__, __LINE__, host, port);
97  return -1;
98  }
99 
100  freeaddrinfo(servs);
101  return fd;
102 }
103 
113 uint8_t receive(int s, char* buffer, size_t max, uint8_t end)
114 {
115  size_t bytes = 0;
116  uint8_t closing = 0;
117  char* poss;
118 
119  do
120  {
121  /* start by clearing the buffer */
122  memset(buffer, '\0', max);
123  bytes = 0;
124 
125  /* read from the socket */
126  do
127  {
128  bytes = read(s, buffer + bytes, max - bytes);
129 
130  if(bytes == 0)
131  {
132  printf("ERROR: connection to scheduler closed\nERROR: closing cli\n");
133  closing = 1;
134  }
135 
136  bytes = strlen(buffer);
137  } while(!closing && buffer[bytes - 1] != '\n');
138 
139  /* interpret the results */
140  for(poss = strtok(buffer, "\n"); !closing && poss != NULL;
141  poss = strtok(NULL, "\n"))
142  {
143  if(strncmp(poss, "received", 8) == 0)
144  {
145  if(response)
146  printf("Command received\n");
147  }
148  else if(strncmp(poss, "CLOSE", 5) == 0)
149  {
150  closing = 1;
151  }
152  else if(strcmp(poss, "end") != 0)
153  {
154  printf("%s\n", poss);
155  }
156  else
157  {
158  end = 0;
159  }
160  }
161 
162  fflush(stdout);
163  } while(end);
164 
165  return closing;
166 }
167 
174 {
175  printf("FOSSology scheduler command line interface\n");
176  printf("+-----------------------------------------------------------------------------+\n");
177  printf("|%*s: EFFECT |\n", P_WIDTH, "CMD [optional] <required>");
178  printf("+-----------------------------------------------------------------------------+\n");
179  printf("|%*s: prints this usage statement |\n", P_WIDTH, "help");
180  printf("|%*s: close the connection and exit cli |\n", P_WIDTH, "close");
181  printf("|%*s: shutdown will wait for agents be stopping |\n", P_WIDTH, "stop");
182  printf("|%*s: shutdown will shutdown immediately |\n", P_WIDTH, "die");
183  printf("|%*s: get load information for host machines |\n", P_WIDTH, "load");
184  printf("|%*s: kills a currently running job (ungraceful) |\n", P_WIDTH, "kill <jq_pk> <\"message\">");
185  printf("|%*s: pauses a job indefinitely |\n", P_WIDTH, "pause <jq_pk>");
186  printf("|%*s: reload the configuration information |\n", P_WIDTH, "reload");
187  printf("|%*s: prints a list of valid agents |\n", P_WIDTH, "agents");
188  printf("|%*s: scheduler responds with status information |\n", P_WIDTH, "status [jq_pk]");
189  printf("|%*s: restart a paused job |\n", P_WIDTH, "restart <jq_pk>");
190  printf("|%*s: query/change the scheduler/job verbosity |\n", P_WIDTH, "verbose [jq_pk] [level]");
191  printf("|%*s: change priority for job that this jq_pk is in |\n", P_WIDTH, "priority <jq_pk> <level>");
192  printf("|%*s: causes the scheduler to check the job queue |\n", P_WIDTH, "database");
193  printf("+-----------------------------------------------------------------------------+\n");
194  fflush(stdout);
195 }
196 
197 /* ************************************************************************** */
198 /* **** main **************************************************************** */
199 /* ************************************************************************** */
200 
201 int main(int argc, char** argv)
202 {
203  /* local variables */
204  fd_set fds; // file descriptor set used in select statement
205  int closing; // flags and loop variables
206  size_t bytes; // variable to capture return of read
207  char* host; // string to hold the name of the host
208  char* port; // string port number to connect to
209  char buffer[1024]; // string buffer used to read
210  char* config; // FOSSology configuration directory
211  GOptionContext* options; // the command line options parser
212  GError* error = NULL;
213 
214  /* command bool and info */
215  uint8_t c_die = 0;
216  uint8_t c_stop = 0;
217  uint8_t c_load = 0;
218  uint8_t c_pause = 0;
219  uint8_t c_reload = 0;
220  uint8_t c_status = 0;
221  uint8_t c_agents = 0;
222  uint8_t c_restart = 0;
223  uint8_t c_verbose = 0;
224  uint8_t c_database = 0;
225 
226  /* initialize memory */
227  host = NULL;
228  port = NULL;
229  config = DEFAULT_SETUP;
230  memset(buffer, '\0', sizeof(buffer));
231  closing = 0;
232  verbose = 0;
233 
234  GOptionEntry entries[] =
235  {
236  {"config", 'c', 0, G_OPTION_ARG_STRING, &config,
237  "Set the directory for the system configuration", "string"},
238  {"host", 'H', 0, G_OPTION_ARG_STRING, &host,
239  "Set the host that the scheduler is on", "string"},
240  {"port", 'p', 0, G_OPTION_ARG_STRING, &port,
241  "Set the port that the scheduler is listening on", "integer"},
242  {"quiet", 'q', 0, G_OPTION_ARG_NONE, &verbose,
243  "Cause the CLI to not print usage hints", NULL},
244  {"load", 'l', 0, G_OPTION_ARG_NONE, &c_load,
245  "CLI will send a load command and close"},
246  {"agents", 'a', 0, G_OPTION_ARG_NONE, &c_agents,
247  "CLI will send an agents command and close"},
248  {"status", 'S', 0, G_OPTION_ARG_NONE, &c_status,
249  "CLI will send a status command and close"},
250  {"stop", 's', 0, G_OPTION_ARG_NONE, &c_stop,
251  "CLI will send stop command and close", NULL},
252  {"die", 'D', 0, G_OPTION_ARG_NONE, &c_die,
253  "CLI will send a die command and close"},
254  {"pause", 'P', 0, G_OPTION_ARG_INT, &c_pause,
255  "CLI will send a pause command and close", "integer"},
256  {"reload", 'r', 0, G_OPTION_ARG_NONE, &c_reload,
257  "CLI will send a reload command and close", NULL},
258  {"restart", 'R', 0, G_OPTION_ARG_INT, &c_restart,
259  "CLI will send a restart command and close", "integer"},
260  {"verbose", 'v', 0, G_OPTION_ARG_INT, &c_verbose,
261  "CLI will change the scheduler's verbose level", "integer"},
262  {"database", 'd', 0, G_OPTION_ARG_NONE, &c_database,
263  "CLI will send a database command to scheduler", NULL},
264  {NULL}
265  };
266 
267  options = g_option_context_new("- command line tool for FOSSology scheduler");
268  g_option_context_add_main_entries(options, entries, NULL);
269  g_option_context_set_ignore_unknown_options(options, FALSE);
270  g_option_context_parse(options, &argc, &argv, &error);
271 
272  if(error)
273  {
274  config = g_option_context_get_help(options, FALSE, NULL);
275  fprintf(stderr, "ERROR: %s\n%s", error->message, config);
276  g_free(config);
277  return -1;
278  }
279 
280  g_option_context_free(options);
281 
282  /* set the basic configuration */
283  /* change the verbose to conform to quite option */
284  verbose = !verbose;
285 
286  snprintf(buffer, sizeof(buffer), "%s/fossology.conf", config);
287  conf = fo_config_load(buffer, &error);
288  if(error)
289  {
290  fprintf(stderr, "ERROR: %s.%d: error loading config: %s\n",
291  __FILE__, __LINE__, error->message);
292  return -1;
293  }
294 
295  /* check the scheduler config for port number */
296  if(port == NULL)
297  port = fo_config_get(conf, "FOSSOLOGY", "port", &error);
298  if(!error && host == NULL)
299  host = fo_config_get(conf, "FOSSOLOGY", "address", &error);
300 
301  /* open the connection to the scheduler */
302  if((s = socket_connect(host, port)) < 0)
303  return -1;
304 
305  /* check specific command instructions */
306  if(c_die || c_stop || c_load || c_pause || c_reload || c_status || c_agents
307  || c_restart || c_verbose || c_database)
308  {
309  response = 0;
310 
311  /* simple no parameter commands */
312  if(c_reload)
313  bytes = write(s, "reload", 6);
314  if(c_database)
315  bytes = write(s, "database", 8);
316  if(c_stop)
317  bytes = write(s, "stop", 4);
318  if(c_die)
319  bytes = write(s, "die", 3);
320 
321  /* simple commands that require a parameter */
322  if(c_verbose)
323  {
324  snprintf(buffer, sizeof(buffer) - 1, "verbose %d", c_verbose);
325  bytes = write(s, buffer, strlen(buffer));
326  }
327 
328  if(c_pause)
329  {
330  snprintf(buffer, sizeof(buffer) - 1, "pause %d", c_pause);
331  bytes = write(s, buffer, strlen(buffer));
332  }
333 
334  if(c_restart)
335  {
336  snprintf(buffer, sizeof(buffer) - 1, "restart %d", c_restart);
337  bytes = write(s, buffer, strlen(buffer));
338  }
339 
340  /* requests for information */
341  if(c_load)
342  {
343  bytes = write(s, "load", 4);
344  receive(s, buffer, sizeof(buffer), TRUE);
345  }
346 
347  if(c_status)
348  {
349  bytes = write(s, "status", 6);
350  receive(s, buffer, sizeof(buffer), TRUE);
351  }
352 
353  if(c_agents)
354  {
355  bytes = write(s, "agents", 6);
356  receive(s, buffer, sizeof(buffer), TRUE);
357  }
358 
359  return 0;
360  }
361 
362  /* listen to the scheulder */
363  if(verbose)
364  interface_usage();
365  while(!closing)
366  {
367  /* prepare for read */
368  FD_ZERO(&fds);
369  FD_SET(s, &fds);
370  FD_SET(fileno(stdin), &fds);
371  memset(buffer, '\0', sizeof(buffer));
372  select(s + 1, &fds, NULL, NULL, NULL);
373 
374  /* check the socket */
375  if(FD_ISSET(s, &fds))
376  closing = receive(s, buffer, sizeof(buffer), FALSE);
377 
378  /* check stdin */
379  if(FD_ISSET(fileno(stdin), &fds))
380  {
381  if(read(fileno(stdin), buffer, sizeof(buffer)) == 0)
382  break;
383 
384  if(strcmp(buffer, "help\n") == 0)
385  {
386  interface_usage();
387  continue;
388  }
389 
390  response = (strncmp(buffer, "agents", 6) == 0 ||
391  strncmp(buffer, "status", 6) == 0 ||
392  strcmp (buffer, "verbose\n" ) == 0 ||
393  strcmp (buffer, "load\n" ) == 0) ?
394  FALSE : TRUE;
395 
396  if((bytes = write(s, buffer, strlen(buffer) - 1)) != strlen(buffer) - 1)
397  {
398  printf("ERROR: couldn't write %lu bytes to socket\n", bytes);
399  closing = 1;
400  }
401  }
402  }
403 
404  return 0;
405 }
int closing
Set if scheduler is shutting down.
Definition: scheduler.c:69
int s
The socket that the CLI will use to communicate.
Definition: fo_cli.c:48
void interface_usage()
Interface usage print.
Definition: fo_cli.c:173
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.
Definition: fossconfig.c:341
fo_conf * conf
The loaded configuration data.
Definition: fo_cli.c:50
int verbose
The verbose flag for the cli.
Definition: fo_cli.c:49
FUNCTION int max(int permGroup, int permPublic)
Get the maximum group privilege.
Definition: libfossagent.c:309
int socket_connect(char *host, char *port)
Create a socket connection.
Definition: fo_cli.c:65
The main FOSSology C library.
char buffer[2048]
The last thing received from the scheduler.
uint8_t receive(int s, char *buffer, size_t max, uint8_t end)
Performs the actions necessary to receive from the scheduler.
Definition: fo_cli.c:113
int response
Is a response expected from the scheduler.
Definition: fo_cli.c:47
fo_conf * fo_config_load(char *rawname, GError **error)
Load the configuration information from the provided file.
Definition: fossconfig.c:280