gearmand.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. /* Gearman server and library
  2. * Copyright (C) 2008 Brian Aker, Eric Day
  3. * All rights reserved.
  4. *
  5. * Use and distribution licensed under the BSD license. See
  6. * the COPYING file in the parent directory for full text.
  7. */
  8. #include <config.h>
  9. #include <errno.h>
  10. #include <fcntl.h>
  11. #include <pwd.h>
  12. #include <signal.h>
  13. #include <stdint.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <sys/resource.h>
  18. #include <sys/stat.h>
  19. #include <sys/types.h>
  20. #include <unistd.h>
  21. #ifdef TIME_WITH_SYS_TIME
  22. # include <sys/time.h>
  23. # include <time.h>
  24. #else
  25. # ifdef HAVE_SYS_TIME_H
  26. # include <sys/time.h>
  27. # else
  28. # include <time.h>
  29. # endif
  30. #endif
  31. #include <libgearman-server/gearmand.h>
  32. #include <libgearman-server/plugins.h>
  33. #include <libgearman-server/queue.h>
  34. #define GEARMAND_LOG_REOPEN_TIME 60
  35. #include "util/daemon.h"
  36. #include "util/pidfile.h"
  37. #include <boost/program_options.hpp>
  38. #include <iostream>
  39. using namespace gearman_util;
  40. namespace error {
  41. inline void perror(const char *message)
  42. {
  43. char *errmsg_ptr;
  44. char errmsg[BUFSIZ];
  45. errmsg[0]= 0;
  46. #ifdef STRERROR_R_CHAR_P
  47. errmsg_ptr= strerror_r(errno, errmsg, sizeof(errmsg));
  48. #else
  49. strerror_r(errno, errmsg, sizeof(errmsg));
  50. errmsg_ptr= errmsg;
  51. #endif
  52. std::cerr << "gearman: " << message << " (" << errmsg_ptr << ")" << std::endl;
  53. }
  54. inline void message(const char *arg)
  55. {
  56. std::cerr << "gearmand: " << arg << std::endl;
  57. }
  58. inline void message(const char *arg, const char *arg2)
  59. {
  60. std::cerr << "gearmand: " << arg << " : " << arg2 << std::endl;
  61. }
  62. inline void message(const std::string &arg, gearmand_error_t rc)
  63. {
  64. std::cerr << "gearmand: " << arg << " : " << gearmand_strerror(rc) << std::endl;
  65. }
  66. } // namespace error
  67. struct gearmand_log_info_st
  68. {
  69. std::string filename;
  70. int fd;
  71. time_t reopen;
  72. gearmand_log_info_st(const std::string &filename_arg) :
  73. filename(filename_arg),
  74. fd(-1),
  75. reopen(0)
  76. {
  77. }
  78. };
  79. static bool _set_fdlimit(rlim_t fds);
  80. static bool _switch_user(const char *user);
  81. extern "C" {
  82. static bool _set_signals(void);
  83. }
  84. static void _shutdown_handler(int signal_arg);
  85. static void _log(const char *line, gearmand_verbose_t verbose, void *context);
  86. int main(int argc, char *argv[])
  87. {
  88. int backlog;
  89. rlim_t fds= 0;
  90. uint32_t job_retries;
  91. uint32_t worker_wakeup;
  92. std::string host;
  93. std::string user;
  94. std::string log_file;
  95. std::string pid_file;
  96. std::string port;
  97. std::string protocol;
  98. std::string queue_type;
  99. std::string verbose_string;
  100. uint32_t threads;
  101. bool opt_round_robin;
  102. bool opt_daemon;
  103. bool opt_check_args;
  104. boost::program_options::options_description general("General options");
  105. general.add_options()
  106. ("backlog,b", boost::program_options::value(&backlog)->default_value(32),
  107. "Number of backlog connections for listen.")
  108. ("check-args", boost::program_options::bool_switch(&opt_check_args)->default_value(false),
  109. "Check command line and configuration file argments and then exit.")
  110. ("daemon,d", boost::program_options::bool_switch(&opt_daemon)->default_value(false),
  111. "Daemon, detach and run in the background.")
  112. ("file-descriptors,f", boost::program_options::value(&fds),
  113. "Number of file descriptors to allow for the process (total connections will be slightly less). Default is max allowed for user.")
  114. ("help,h", "Print this help menu.")
  115. ("job-retries,j", boost::program_options::value(&job_retries)->default_value(0),
  116. "Number of attempts to run the job before the job server removes it. This is helpful to ensure a bad job does not crash all available workers. Default is no limit.")
  117. ("log-file,l", boost::program_options::value(&log_file),
  118. "Log file to write errors and information to. Turning this option on also forces the first verbose level to be enabled.")
  119. ("listen,L", boost::program_options::value(&host),
  120. "Address the server should listen on. Default is INADDR_ANY.")
  121. ("port,p", boost::program_options::value(&port)->default_value(GEARMAN_DEFAULT_TCP_PORT_STRING),
  122. "Port the server should listen on.")
  123. ("pid-file,P", boost::program_options::value(&pid_file),
  124. "File to write process ID out to.")
  125. ("protocol,r", boost::program_options::value(&protocol),
  126. "Load protocol module.")
  127. ("round-robin,R", boost::program_options::bool_switch(&opt_round_robin)->default_value(false),
  128. "Assign work in round-robin order per worker connection. The default is to assign work in the order of functions added by the worker.")
  129. ("queue-type,q", boost::program_options::value(&queue_type),
  130. "Persistent queue type to use.")
  131. ("threads,t", boost::program_options::value(&threads)->default_value(4),
  132. "Number of I/O threads to use. Default=4.")
  133. ("user,u", boost::program_options::value(&user),
  134. "Switch to given user after startup.")
  135. ("verbose,v", boost::program_options::value(&verbose_string)->default_value("v"),
  136. "Increase verbosity level by one.")
  137. ("version,V", "Display the version of gearmand and exit.")
  138. ("worker-wakeup,w", boost::program_options::value(&worker_wakeup)->default_value(0),
  139. "Number of workers to wakeup for each job received. The default is to wakeup all available workers.")
  140. ;
  141. boost::program_options::options_description all("Allowed options");
  142. all.add(general);
  143. gearmand::protocol::HTTP http;
  144. all.add(http.command_line_options());
  145. gearmand::plugins::initialize(all);
  146. boost::program_options::variables_map vm;
  147. try {
  148. store(parse_command_line(argc, argv, all), vm);
  149. notify(vm);
  150. }
  151. catch(std::exception &e)
  152. {
  153. std::cout << e.what() << std::endl;
  154. return EXIT_FAILURE;
  155. }
  156. uint8_t verbose_count;
  157. verbose_count= static_cast<gearmand_verbose_t>(verbose_string.length());
  158. if (opt_check_args)
  159. {
  160. return EXIT_SUCCESS;
  161. }
  162. if (vm.count("help"))
  163. {
  164. std::cout << all << std::endl;
  165. return EXIT_FAILURE;
  166. }
  167. if (vm.count("version"))
  168. {
  169. std::cout << std::endl << "gearmand " << gearmand_version() << " - " << gearmand_bugreport() << std::endl;
  170. return EXIT_FAILURE;
  171. }
  172. if (fds > 0 && _set_fdlimit(fds))
  173. {
  174. return EXIT_FAILURE;
  175. }
  176. if (not user.empty() and _switch_user(user.c_str()))
  177. {
  178. return EXIT_FAILURE;
  179. }
  180. if (_set_signals())
  181. {
  182. return EXIT_FAILURE;
  183. }
  184. if (opt_daemon)
  185. {
  186. gearmand::daemonize(false, true);
  187. }
  188. if (opt_daemon)
  189. gearmand::daemon_is_ready(verbose_count == 0);
  190. gearmand_verbose_t verbose= verbose_count > static_cast<int>(GEARMAND_VERBOSE_CRAZY) ? GEARMAND_VERBOSE_CRAZY : static_cast<gearmand_verbose_t>(verbose_count);
  191. Pidfile _pid_file(pid_file);
  192. if (not _pid_file.create())
  193. {
  194. error::perror(_pid_file.error_message().c_str());
  195. return EXIT_FAILURE;
  196. }
  197. gearmand_log_info_st log_info(log_file);
  198. gearmand_st *_gearmand;
  199. _gearmand= gearmand_create(host.empty() ? NULL : host.c_str(),
  200. port.c_str(), threads, backlog,
  201. static_cast<uint8_t>(job_retries),
  202. static_cast<uint8_t>(worker_wakeup),
  203. _log, &log_info, verbose,
  204. opt_round_robin);
  205. if (not _gearmand)
  206. {
  207. error::message("Could not create gearmand library instance.");
  208. return EXIT_FAILURE;
  209. }
  210. if (not queue_type.empty())
  211. {
  212. gearmand_error_t rc;
  213. if ((rc= gearmand::queue::initialize(_gearmand, queue_type.c_str())) != GEARMAN_SUCCESS)
  214. {
  215. gearmand_free(_gearmand);
  216. return EXIT_FAILURE;
  217. }
  218. }
  219. if (not protocol.compare("http"))
  220. {
  221. if (http.start(_gearmand) != GEARMAN_SUCCESS)
  222. {
  223. error::message("Error while enabling protocol module", protocol.c_str());
  224. return EXIT_FAILURE;
  225. }
  226. }
  227. else if (not protocol.empty())
  228. {
  229. error::message("Unknown protocol module", protocol.c_str());
  230. return EXIT_FAILURE;
  231. }
  232. gearmand_error_t ret;
  233. ret= gearmand_run(_gearmand);
  234. gearmand_free(_gearmand);
  235. if (log_info.fd != -1)
  236. (void) close(log_info.fd);
  237. return (ret == GEARMAN_SUCCESS || ret == GEARMAN_SHUTDOWN) ? 0 : 1;
  238. }
  239. static bool _set_fdlimit(rlim_t fds)
  240. {
  241. struct rlimit rl;
  242. if (getrlimit(RLIMIT_NOFILE, &rl) == -1)
  243. {
  244. error::perror("Could not get file descriptor limit");
  245. return true;
  246. }
  247. rl.rlim_cur= fds;
  248. if (rl.rlim_max < rl.rlim_cur)
  249. rl.rlim_max= rl.rlim_cur;
  250. if (setrlimit(RLIMIT_NOFILE, &rl) == -1)
  251. {
  252. error::perror("Failed to set limit for the number of file "
  253. "descriptors. Try running as root or giving a "
  254. "smaller value to -f.");
  255. return true;
  256. }
  257. return false;
  258. }
  259. static bool _switch_user(const char *user)
  260. {
  261. if (getuid() == 0 || geteuid() == 0)
  262. {
  263. struct passwd *pw= getpwnam(user);
  264. if (not pw)
  265. {
  266. error::message("Could not find user", user);
  267. return EXIT_FAILURE;
  268. }
  269. if (setgid(pw->pw_gid) == -1 || setuid(pw->pw_uid) == -1)
  270. {
  271. error::message("Could not switch to user", user);
  272. return EXIT_FAILURE;
  273. }
  274. }
  275. else
  276. {
  277. error::message("Must be root to switch users.");
  278. return true;
  279. }
  280. return false;
  281. }
  282. extern "C" {
  283. static bool _set_signals(void)
  284. {
  285. struct sigaction sa;
  286. memset(&sa, 0, sizeof(struct sigaction));
  287. sa.sa_handler= SIG_IGN;
  288. if (sigemptyset(&sa.sa_mask) == -1 ||
  289. sigaction(SIGPIPE, &sa, 0) == -1)
  290. {
  291. error::perror("Could not set SIGPIPE handler.");
  292. return true;
  293. }
  294. sa.sa_handler= _shutdown_handler;
  295. if (sigaction(SIGTERM, &sa, 0) == -1)
  296. {
  297. error::perror("Could not set SIGTERM handler.");
  298. return true;
  299. }
  300. if (sigaction(SIGINT, &sa, 0) == -1)
  301. {
  302. error::perror("Could not set SIGINT handler.");
  303. return true;
  304. }
  305. if (sigaction(SIGUSR1, &sa, 0) == -1)
  306. {
  307. error::perror("Could not set SIGUSR1 handler.");
  308. return true;
  309. }
  310. return false;
  311. }
  312. }
  313. static void _shutdown_handler(int signal_arg)
  314. {
  315. if (signal_arg == SIGUSR1)
  316. gearmand_wakeup(Gearmand(), GEARMAND_WAKEUP_SHUTDOWN_GRACEFUL);
  317. else
  318. gearmand_wakeup(Gearmand(), GEARMAND_WAKEUP_SHUTDOWN);
  319. }
  320. static void _log(const char *line, gearmand_verbose_t verbose, void *context)
  321. {
  322. gearmand_log_info_st *log_info= static_cast<gearmand_log_info_st *>(context);
  323. int fd;
  324. if (log_info->filename.empty())
  325. {
  326. fd= 1;
  327. }
  328. else
  329. {
  330. time_t t= time(NULL);
  331. if (log_info->fd != -1 && log_info->reopen < t)
  332. {
  333. (void) close(log_info->fd);
  334. log_info->fd= -1;
  335. }
  336. if (log_info->fd == -1)
  337. {
  338. log_info->fd= open(log_info->filename.c_str(), O_CREAT | O_WRONLY | O_APPEND, 0644);
  339. if (log_info->fd == -1)
  340. {
  341. error::perror("Could not open log file for writing.");
  342. return;
  343. }
  344. log_info->reopen= t + GEARMAND_LOG_REOPEN_TIME;
  345. }
  346. fd= log_info->fd;
  347. }
  348. char buffer[GEARMAN_MAX_ERROR_SIZE];
  349. snprintf(buffer, GEARMAN_MAX_ERROR_SIZE, "%5s %s\n",
  350. gearmand_verbose_name(verbose), line);
  351. if (write(fd, buffer, strlen(buffer)) == -1)
  352. {
  353. error::perror("Could not write to log file.");
  354. }
  355. }