~brianaker/gearmand/hostile-target

« back to all changes in this revision

Viewing changes to gearmand/gearmand.cc

  • Committer: Brian Aker
  • Date: 2011-02-14 18:07:15 UTC
  • Revision ID: brian@tangent.org-20110214180715-svy2htofdfhx21wq
Merge in partial set of work from DD branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
8
8
 
9
9
#include "config.h"
10
10
 
 
11
#include <stdint.h>
 
12
 
11
13
#ifdef HAVE_ERRNO_H
12
14
#include <errno.h>
13
15
#endif
80
82
#define GEARMAND_LOG_REOPEN_TIME 60
81
83
#define GEARMAND_LISTEN_BACKLOG 32
82
84
 
83
 
typedef struct
 
85
#include "util/error.h"
 
86
#include "util/pidfile.h"
 
87
 
 
88
using namespace gearman_util;
 
89
 
 
90
struct gearmand_log_info_st
84
91
{
85
92
  const char *file;
86
93
  int fd;
87
94
  time_t reopen;
88
 
} gearmand_log_info_st;
 
95
 
 
96
  gearmand_log_info_st() :
 
97
    file(NULL),
 
98
    fd(-1),
 
99
    reopen(0)
 
100
  {
 
101
  }
 
102
};
89
103
 
90
104
static gearmand_st *_gearmand;
91
105
 
92
106
static bool _set_fdlimit(rlim_t fds);
93
 
static bool _pid_write(const char *pid_file);
94
 
static void _pid_delete(const char *pid_file);
95
107
static bool _switch_user(const char *user);
 
108
extern "C" {
96
109
static bool _set_signals(void);
 
110
}
97
111
static void _shutdown_handler(int signal_arg);
98
112
static void _log(const char *line, gearman_verbose_t verbose, void *context);
99
113
 
120
134
  int fd;
121
135
  bool round_robin= false;
122
136
 
123
 
  log_info.file= NULL;
124
 
  log_info.fd= -1;
125
 
  log_info.reopen= 0;
126
 
 
127
137
  if (gearman_conf_create(&conf) == NULL)
128
138
  {
129
 
    fprintf(stderr, "gearmand: gearman_conf_create: NULL\n");
 
139
    error::message("gearman_conf_create: NULL");
130
140
    return 1;
131
141
  }
132
142
 
133
143
  if (gearman_conf_module_create(&conf, &module, NULL) == NULL)
134
144
  {
135
 
    fprintf(stderr, "gearmand: gearman_conf_module_create: NULL\n");
 
145
    error::message("gearman_conf_module_create: NULL");
136
146
    return 1;
137
147
  }
138
148
 
173
183
  /* Make sure none of the gearman_conf_module_add_option calls failed. */
174
184
  if (gearman_conf_return(&conf) != GEARMAN_SUCCESS)
175
185
  {
176
 
    fprintf(stderr, "gearmand: gearman_conf_module_add_option: %s\n",
177
 
            gearman_conf_error(&conf));
 
186
    error::message("gearman_conf_module_add_option", gearman_conf_error(&conf));
178
187
    return 1;
179
188
  }
180
189
 
183
192
#ifdef HAVE_LIBDRIZZLE
184
193
  if (gearman_server_queue_libdrizzle_conf(&conf) != GEARMAN_SUCCESS)
185
194
  {
186
 
    fprintf(stderr, "gearmand: gearman_queue_libdrizzle_conf: %s\n",
187
 
            gearman_conf_error(&conf));
 
195
    error::message("gearman_queue_libdrizzle_conf", gearman_conf_error(&conf));
188
196
    return 1;
189
197
  }
190
198
#endif
192
200
#ifdef HAVE_LIBMEMCACHED
193
201
  if (gearman_server_queue_libmemcached_conf(&conf) != GEARMAN_SUCCESS)
194
202
  {
195
 
    fprintf(stderr, "gearmand: gearman_queue_libmemcached_conf: %s\n",
196
 
            gearman_conf_error(&conf));
 
203
    error::message("gearman_queue_libmemcached_conf", gearman_conf_error(&conf));
197
204
    return 1;
198
205
  }
199
206
#endif
200
207
#ifdef HAVE_LIBTOKYOCABINET
201
208
  if (gearman_server_queue_libtokyocabinet_conf(&conf) != GEARMAN_SUCCESS)
202
209
  {
203
 
    fprintf(stderr, "gearmand: gearman_queue_libtokyocabinet_conf: %s\n",
204
 
            gearman_conf_error(&conf));
 
210
    error::message("gearman_queue_libtokyocabinet_conf", gearman_conf_error(&conf));
205
211
    return 1;
206
212
  }
207
213
#endif
209
215
#ifdef HAVE_LIBSQLITE3
210
216
  if (gearman_server_queue_libsqlite3_conf(&conf) != GEARMAN_SUCCESS)
211
217
  {
212
 
    fprintf(stderr, "gearmand: gearman_queue_libsqlite3_conf: %s\n",
213
 
            gearman_conf_error(&conf));
 
218
    error::message("gearman_queue_libsqlite3_conf", gearman_conf_error(&conf));
214
219
    return 1;
215
220
  }
216
221
#endif
218
223
#ifdef HAVE_LIBPQ
219
224
  if (gearman_server_queue_libpq_conf(&conf) != GEARMAN_SUCCESS)
220
225
  {
221
 
    fprintf(stderr, "gearmand: gearman_queue_libpq_conf: %s\n",
222
 
            gearman_conf_error(&conf));
 
226
    error::message("gearman_queue_libpq_conf", gearman_conf_error(&conf));
223
227
    return 1;
224
228
  }
225
229
#endif
226
230
 
227
231
  if (gearmand_protocol_http_conf(&conf) != GEARMAN_SUCCESS)
228
232
  {
229
 
    fprintf(stderr, "gearmand: gearman_protocol_http_conf: %s\n",
230
 
            gearman_conf_error(&conf));
 
233
    error::message("gearman_protocol_http_conf", gearman_conf_error(&conf));
231
234
    return 1;
232
235
  }
233
236
 
244
247
  /* Check for option values that were given. */
245
248
  while (gearman_conf_module_value(&module, &name, &value))
246
249
  {
247
 
    if (!strcmp(name, "backlog"))
 
250
    if (not strcmp(name, "backlog"))
 
251
    {
248
252
      backlog= atoi(value);
249
 
    else if (!strcmp(name, "daemon"))
 
253
    }
 
254
    else if (not strcmp(name, "daemon"))
250
255
    {
251
256
      switch (fork())
252
257
      {
253
258
      case -1:
254
 
        fprintf(stderr, "gearmand: fork:%d\n", errno);
 
259
        error::perror("fork");
255
260
        return 1;
256
261
 
257
262
      case 0:
263
268
 
264
269
      if (setsid() == -1)
265
270
      {
266
 
        fprintf(stderr, "gearmand: setsid:%d\n", errno);
 
271
        error::perror("setsid");
267
272
        return 1;
268
273
      }
269
274
 
270
275
      close_stdio= true;
271
276
    }
272
 
    else if (!strcmp(name, "file-descriptors"))
273
 
      fds= (rlim_t)atoi(value);
274
 
    else if (!strcmp(name, "help"))
 
277
    else if (not strcmp(name, "file-descriptors"))
 
278
    {
 
279
      fds= static_cast<rlim_t>(atoi(value));
 
280
    }
 
281
    else if (not strcmp(name, "help"))
275
282
    {
276
283
      printf("\ngearmand %s - %s\n\n", gearman_version(), gearman_bugreport());
277
284
      printf("usage: %s [OPTIONS]\n", argv[0]);
278
285
      gearman_conf_usage(&conf);
279
286
      return 1;
280
287
    }
281
 
    else if (!strcmp(name, "job-retries"))
282
 
      job_retries= (uint8_t)atoi(value);
283
 
    else if (!strcmp(name, "log-file"))
 
288
    else if (not strcmp(name, "job-retries"))
 
289
    {
 
290
      job_retries= static_cast<uint8_t>(atoi(value));
 
291
    }
 
292
    else if (not strcmp(name, "log-file"))
 
293
    {
284
294
      log_info.file= value;
285
 
    else if (!strcmp(name, "listen"))
 
295
    }
 
296
    else if (not strcmp(name, "listen"))
 
297
    {
286
298
      host= value;
287
 
    else if (!strcmp(name, "port"))
288
 
      port= (in_port_t)atoi(value);
289
 
    else if (!strcmp(name, "pid-file"))
 
299
    }
 
300
    else if (not strcmp(name, "port"))
 
301
    {
 
302
      port= static_cast<in_port_t>(atoi(value));
 
303
    }
 
304
    else if (not strcmp(name, "pid-file"))
 
305
    {
290
306
      pid_file= value;
291
 
    else if (!strcmp(name, "protocol"))
 
307
    }
 
308
    else if (not strcmp(name, "protocol"))
 
309
    {
292
310
      continue;
293
 
    else if (!strcmp(name, "queue-type"))
 
311
    }
 
312
    else if (not strcmp(name, "queue-type"))
 
313
    {
294
314
      queue_type= value;
295
 
    else if (!strcmp(name, "threads"))
296
 
      threads= (uint32_t)atoi(value);
297
 
    else if (!strcmp(name, "user"))
 
315
    }
 
316
    else if (not strcmp(name, "threads"))
 
317
    {
 
318
      threads= static_cast<uint32_t>(atoi(value));
 
319
    }
 
320
    else if (not strcmp(name, "user"))
 
321
    {
298
322
      user= value;
299
 
    else if (!strcmp(name, "verbose"))
 
323
    }
 
324
    else if (not strcmp(name, "verbose"))
 
325
    {
300
326
      verbose++;
301
 
    else if (!strcmp(name, "round-robin"))
 
327
    }
 
328
    else if (not strcmp(name, "round-robin"))
 
329
    {
302
330
      round_robin++;
303
 
    else if (!strcmp(name, "version"))
 
331
    }
 
332
    else if (not strcmp(name, "version"))
 
333
    {
304
334
      printf("\ngearmand %s - %s\n", gearman_version(), gearman_bugreport());
305
 
    else if (!strcmp(name, "worker-wakeup"))
306
 
      worker_wakeup= (uint8_t)atoi(value);
 
335
    }
 
336
    else if (not strcmp(name, "worker-wakeup"))
 
337
    {
 
338
      worker_wakeup= static_cast<uint8_t>(atoi(value));
 
339
    }
307
340
    else
308
341
    {
309
 
      fprintf(stderr, "gearmand: Unknown option:%s\n", name);
 
342
      error::message("Unknown option", name);
310
343
      return 1;
311
344
    }
312
345
  }
319
352
    {
320
353
      if (dup2(fd, STDIN_FILENO) == -1)
321
354
      {
322
 
        fprintf(stderr, "gearmand: dup2:%d\n", errno);
 
355
        error::perror("dup2");
323
356
        return 1;
324
357
      }
325
358
 
326
359
      if (dup2(fd, STDOUT_FILENO) == -1)
327
360
      {
328
 
        fprintf(stderr, "gearmand: dup2:%d\n", errno);
 
361
        error::perror("dup2");
329
362
        return 1;
330
363
      }
331
364
 
332
365
      if (dup2(fd, STDERR_FILENO) == -1)
333
366
      {
334
 
        fprintf(stderr, "gearmand: dup2:%d\n", errno);
 
367
        error::perror("dup2");
335
368
        return 1;
336
369
      }
337
370
 
342
375
  if ((fds > 0 && _set_fdlimit(fds)) || _switch_user(user) || _set_signals())
343
376
    return 1;
344
377
 
345
 
  if (pid_file != NULL && _pid_write(pid_file))
346
 
    return 1;
 
378
  Pidfile _pid_file(pid_file);
347
379
 
348
380
  _gearmand= gearmand_create(host, port);
349
381
  if (_gearmand == NULL)
350
382
  {
351
 
    fprintf(stderr, "gearmand: Could not create gearmand library instance\n");
 
383
    error::message("Could not create gearmand library instance.");
352
384
    return 1;
353
385
  }
354
386
 
356
388
  gearmand_set_threads(_gearmand, threads);
357
389
  gearmand_set_job_retries(_gearmand, job_retries);
358
390
  gearmand_set_worker_wakeup(_gearmand, worker_wakeup);
359
 
  gearmand_set_log_fn(_gearmand, _log, &log_info, verbose);
 
391
  gearmand_set_log_fn(_gearmand, _log, &log_info, static_cast<gearman_verbose_t>(verbose));
360
392
  gearmand_set_round_robin(_gearmand, round_robin);
361
393
 
362
394
  if (queue_type != NULL)
363
395
  {
364
396
#ifdef HAVE_LIBDRIZZLE
365
 
    if (!strcmp(queue_type, "libdrizzle"))
 
397
    if (not strcmp(queue_type, "libdrizzle"))
366
398
    {
367
399
      ret= gearmand_queue_libdrizzle_init(_gearmand, &conf);
368
400
      if (ret != GEARMAN_SUCCESS)
371
403
    else
372
404
#endif
373
405
#ifdef HAVE_LIBMEMCACHED
374
 
    if (!strcmp(queue_type, "libmemcached"))
 
406
    if (not strcmp(queue_type, "libmemcached"))
375
407
    {
376
408
      ret= gearmand_queue_libmemcached_init(_gearmand, &conf);
377
409
      if (ret != GEARMAN_SUCCESS)
380
412
    else
381
413
#endif
382
414
#ifdef HAVE_LIBSQLITE3
383
 
    if (!strcmp(queue_type, "libsqlite3"))
 
415
    if (not strcmp(queue_type, "libsqlite3"))
384
416
    {
385
417
      ret= gearmand_queue_libsqlite3_init(_gearmand, &conf);
386
418
      if (ret != GEARMAN_SUCCESS)
389
421
    else
390
422
#endif
391
423
#ifdef HAVE_LIBPQ
392
 
    if (!strcmp(queue_type, "libpq"))
 
424
    if (not strcmp(queue_type, "libpq"))
393
425
    {
394
426
      ret= gearmand_queue_libpq_init(_gearmand, &conf);
395
427
      if (ret != GEARMAN_SUCCESS)
398
430
    else
399
431
#endif
400
432
#ifdef HAVE_LIBTOKYOCABINET
401
 
    if (!strcmp(queue_type, "libtokyocabinet"))
 
433
    if (not strcmp(queue_type, "libtokyocabinet"))
402
434
    {
403
435
      ret= gearmand_queue_libtokyocabinet_init(_gearmand, &conf);
404
436
      if (ret != GEARMAN_SUCCESS)
407
439
    else
408
440
#endif        
409
441
    {
410
 
      fprintf(stderr, "gearmand: Unknown queue module: %s\n", queue_type);
 
442
      error::message("Unknown queue module", queue_type);
411
443
      return 1;
412
444
    }
413
445
  }
417
449
    if (strcmp(name, "protocol"))
418
450
      continue;
419
451
 
420
 
    if (!strcmp(value, "http"))
 
452
    if (not strcmp(value, "http"))
421
453
    {
422
454
      ret= gearmand_protocol_http_init(_gearmand, &conf);
423
455
      if (ret != GEARMAN_SUCCESS)
425
457
    }
426
458
    else
427
459
    {
428
 
      fprintf(stderr, "gearmand: Unknown protocol module: %s\n", value);
 
460
      error::message("Unknown protocol module", value);
429
461
      return 1;
430
462
    }
431
463
  }
435
467
  if (queue_type != NULL)
436
468
  {
437
469
#ifdef HAVE_LIBDRIZZLE
438
 
    if (!strcmp(queue_type, "libdrizzle"))
 
470
    if (not strcmp(queue_type, "libdrizzle"))
439
471
      gearmand_queue_libdrizzle_deinit(_gearmand);
440
472
#endif
441
473
#ifdef HAVE_LIBMEMCACHED
442
 
    if (!strcmp(queue_type, "libmemcached"))
 
474
    if (not strcmp(queue_type, "libmemcached"))
443
475
      gearmand_queue_libmemcached_deinit(_gearmand);
444
476
#endif
445
477
#ifdef HAVE_LIBSQLITE3
446
 
    if (!strcmp(queue_type, "libsqlite3"))
 
478
    if (not strcmp(queue_type, "libsqlite3"))
447
479
      gearmand_queue_libsqlite3_deinit(_gearmand);
448
480
#endif
449
481
#ifdef HAVE_LIBPQ
450
 
    if (!strcmp(queue_type, "libpq"))
 
482
    if (not strcmp(queue_type, "libpq"))
451
483
      gearmand_queue_libpq_deinit(_gearmand);
452
484
#endif
453
485
#ifdef HAVE_LIBTOKYOCABINET
454
 
    if (!strcmp(queue_type, "libtokyocabinet"))
 
486
    if (not strcmp(queue_type, "libtokyocabinet"))
455
487
      gearmand_queue_libtokyocabinet_deinit(_gearmand);
456
488
#endif
457
489
  }
461
493
    if (strcmp(name, "protocol"))
462
494
      continue;
463
495
 
464
 
    if (!strcmp(value, "http"))
 
496
    if (not strcmp(value, "http"))
465
497
      gearmand_protocol_http_deinit(_gearmand);
466
498
  }
467
499
 
468
500
  gearmand_free(_gearmand);
469
501
 
470
 
  if (pid_file != NULL)
471
 
    _pid_delete(pid_file);
472
 
 
473
502
  if (log_info.fd != -1)
474
503
    (void) close(log_info.fd);
475
504
 
484
513
 
485
514
  if (getrlimit(RLIMIT_NOFILE, &rl) == -1)
486
515
  {
487
 
    fprintf(stderr, "gearmand: Could not get file descriptor limit:%d\n",
488
 
            errno);
 
516
    error::perror("Could not get file descriptor limit");
489
517
    return true;
490
518
  }
491
519
 
495
523
 
496
524
  if (setrlimit(RLIMIT_NOFILE, &rl) == -1)
497
525
  {
498
 
    fprintf(stderr, "gearmand: Failed to set limit for the number of file "
499
 
                    "descriptors (%d). Try running as root or giving a "
500
 
                    "smaller value to -f.\n",
501
 
            errno);
502
 
    return true;
503
 
  }
504
 
 
505
 
  return false;
506
 
}
507
 
 
508
 
static bool _pid_write(const char *pid_file)
509
 
{
510
 
  FILE *f;
511
 
 
512
 
  f= fopen(pid_file, "w");
513
 
  if (f == NULL)
514
 
  {
515
 
    fprintf(stderr, "gearmand: Could not open pid file for writing: %s (%d)\n",
516
 
            pid_file, errno);
517
 
    return true;
518
 
  }
519
 
 
520
 
  fprintf(f, "%" PRId64 "\n", (int64_t)getpid());
521
 
 
522
 
  if (fclose(f) == -1)
523
 
  {
524
 
    fprintf(stderr, "gearmand: Could not close the pid file: %s (%d)\n",
525
 
            pid_file, errno);
526
 
    return true;
527
 
  }
528
 
 
529
 
  return false;
530
 
}
531
 
 
532
 
static void _pid_delete(const char *pid_file)
533
 
{
534
 
  if (unlink(pid_file) == -1)
535
 
  {
536
 
    fprintf(stderr, "gearmand: Could not remove the pid file: %s (%d)\n",
537
 
            pid_file, errno);
538
 
  }
 
526
    error::perror("Failed to set limit for the number of file "
 
527
                  "descriptors.  Try running as root or giving a "
 
528
                  "smaller value to -f.");
 
529
    return true;
 
530
  }
 
531
 
 
532
  return false;
539
533
}
540
534
 
541
535
static bool _switch_user(const char *user)
546
540
  {
547
541
    if (user == NULL || user[0] == 0)
548
542
    {
549
 
      fprintf(stderr,
550
 
              "gearmand: Must specify '-u root' if you want to run as root\n");
 
543
      error::message("Must specify '-u root' if you want to run as root");
551
544
      return true;
552
545
    }
553
546
 
554
547
    pw= getpwnam(user);
555
548
    if (pw == NULL)
556
549
    {
557
 
      fprintf(stderr, "gearmand: Could not find user '%s'\n", user);
 
550
      error::message("Could not find user", user);
558
551
      return 1;
559
552
    }
560
553
 
561
554
    if (setgid(pw->pw_gid) == -1 || setuid(pw->pw_uid) == -1)
562
555
    {
563
 
      fprintf(stderr, "gearmand: Could not switch to user '%s'\n", user);
 
556
      error::message("Could not switch to user", user);
564
557
      return 1;
565
558
    }
566
559
  }
567
560
  else if (user != NULL)
568
561
  {
569
 
    fprintf(stderr, "gearmand: Must be root to switch users\n");
 
562
    error::message("Must be root to switch users.");
570
563
    return true;
571
564
  }
572
565
 
573
566
  return false;
574
567
}
575
568
 
 
569
extern "C" {
576
570
static bool _set_signals(void)
577
571
{
578
572
  struct sigaction sa;
583
577
  if (sigemptyset(&sa.sa_mask) == -1 ||
584
578
      sigaction(SIGPIPE, &sa, 0) == -1)
585
579
  {
586
 
    fprintf(stderr, "gearmand: Could not set SIGPIPE handler (%d)\n", errno);
 
580
    error::perror("Could not set SIGPIPE handler.");
587
581
    return true;
588
582
  }
589
583
 
590
584
  sa.sa_handler= _shutdown_handler;
591
585
  if (sigaction(SIGTERM, &sa, 0) == -1)
592
586
  {
593
 
    fprintf(stderr, "gearmand: Could not set SIGTERM handler (%d)\n", errno);
 
587
    error::perror("Could not set SIGTERM handler.");
594
588
    return true;
595
589
  }
596
590
 
597
591
  if (sigaction(SIGINT, &sa, 0) == -1)
598
592
  {
599
 
    fprintf(stderr, "gearmand: Could not set SIGINT handler (%d)\n", errno);
 
593
    error::perror("Could not set SIGINT handler.");
600
594
    return true;
601
595
  }
602
596
 
603
597
  if (sigaction(SIGUSR1, &sa, 0) == -1)
604
598
  {
605
 
    fprintf(stderr, "gearmand: Could not set SIGUSR1 handler (%d)\n", errno);
 
599
    error::perror("Could not set SIGUSR1 handler.");
606
600
    return true;
607
601
  }
608
602
 
609
603
  return false;
610
604
}
 
605
}
611
606
 
612
607
static void _shutdown_handler(int signal_arg)
613
608
{
619
614
 
620
615
static void _log(const char *line, gearman_verbose_t verbose, void *context)
621
616
{
622
 
  gearmand_log_info_st *log_info= (gearmand_log_info_st *)context;
 
617
  gearmand_log_info_st *log_info= static_cast<gearmand_log_info_st *>(context);
623
618
  int fd;
624
619
  time_t t;
625
620
  char buffer[GEARMAN_MAX_ERROR_SIZE];
626
621
 
627
622
  if (log_info->file == NULL)
 
623
  {
628
624
    fd= 1;
 
625
  }
629
626
  else
630
627
  {
631
628
    t= time(NULL);
641
638
      log_info->fd= open(log_info->file, O_CREAT | O_WRONLY | O_APPEND, 0644);
642
639
      if (log_info->fd == -1)
643
640
      {
644
 
        fprintf(stderr, "gearmand: Could not open log file for writing (%d)\n",
645
 
                errno);
 
641
        error::perror("Could not open log file for writing.");
646
642
        return;
647
643
      }
648
644
 
655
651
  snprintf(buffer, GEARMAN_MAX_ERROR_SIZE, "%5s %s\n",
656
652
           gearman_verbose_name(verbose), line);
657
653
  if (write(fd, buffer, strlen(buffer)) == -1)
658
 
    fprintf(stderr, "gearmand: Could not write to log file: %d\n", errno);
 
654
  {
 
655
    error::perror("Could not write to log file.");
 
656
  }
659
657
}