main.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  1. /*
  2. * Copyright (C) 2010 Michael Buesch <m@bues.ch>
  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. * as published by the Free Software Foundation; either version 2
  7. * of the License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. */
  14. #include "main.h"
  15. #include "timer.h"
  16. #include "args.h"
  17. #include "api.h"
  18. #include "log.h"
  19. #include "conf.h"
  20. #include "util.h"
  21. #include "list.h"
  22. #include "battery.h"
  23. #include "backlight.h"
  24. #include "devicelock.h"
  25. #include "autodim.h"
  26. #include <assert.h>
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include <unistd.h>
  31. #include <errno.h>
  32. #include <fcntl.h>
  33. #include <signal.h>
  34. #include <sys/ioctl.h>
  35. #include <sys/socket.h>
  36. #include <sys/un.h>
  37. #include <sys/stat.h>
  38. #include <sys/resource.h>
  39. struct client {
  40. int fd;
  41. int notifications_enabled;
  42. struct list_head list;
  43. };
  44. static int socket_fd = -1;
  45. static sig_atomic_t in_signal;
  46. static int sig_block_count;
  47. static LIST_HEAD(client_list);
  48. struct backend backend;
  49. static int send_message(struct client *c, struct pt_message *msg, uint16_t flags)
  50. {
  51. ssize_t ret;
  52. size_t count, pos = 0;
  53. msg->flags |= htons(flags);
  54. count = sizeof(*msg);
  55. while (count) {
  56. ret = send(c->fd, ((uint8_t *)msg) + pos, count, 0);
  57. if (ret < 0) {
  58. logerr("Failed to send message to client, fd=%d\n",
  59. c->fd);
  60. return -1;
  61. }
  62. count -= ret;
  63. pos += ret;
  64. }
  65. return 0;
  66. }
  67. static int enable_autodim(int max_percent, int enable_on_ac)
  68. {
  69. int err = 0;
  70. if (!backend.backlight)
  71. return -ENODEV;
  72. backend.backlight->autodim_enabled_on_ac = enable_on_ac;
  73. if (!backend.autodim) {
  74. err = -ENOMEM;
  75. backend.autodim = autodim_alloc();
  76. if (backend.autodim)
  77. err = autodim_init(backend.autodim, backend.backlight, backend.config);
  78. if (err) {
  79. autodim_free(backend.autodim);
  80. backend.autodim = NULL;
  81. return err;
  82. }
  83. }
  84. autodim_set_max_percent(backend.autodim, max_percent);
  85. return err;
  86. }
  87. static void disable_autodim(void)
  88. {
  89. autodim_destroy(backend.autodim);
  90. autodim_free(backend.autodim);
  91. backend.autodim = NULL;
  92. if (backend.backlight)
  93. backend.backlight->autodim_enabled_on_ac = 0;
  94. }
  95. static void received_message(struct client *c, struct pt_message *msg)
  96. {
  97. struct pt_message reply = {
  98. .id = msg->id,
  99. .flags = (msg->flags & ~htons(PT_FLG_OK)) | htons(PT_FLG_REPLY),
  100. };
  101. int err;
  102. switch (ntohs(msg->id)) {
  103. case PTREQ_PING:
  104. send_message(c, &reply, PT_FLG_OK);
  105. break;
  106. case PTREQ_WANT_NOTIFY:
  107. if (msg->flags & htons(PT_FLG_ENABLE))
  108. c->notifications_enabled = 1;
  109. else
  110. c->notifications_enabled = 0;
  111. send_message(c, &reply, PT_FLG_OK);
  112. break;
  113. case PTREQ_XEVREP:
  114. err = 0;
  115. if (msg->flags & htons(PT_FLG_ENABLE))
  116. err = xevrep_enable(&backend.xevrep);
  117. else
  118. xevrep_disable(&backend.xevrep);
  119. send_message(c, &reply, err ? 0 : PT_FLG_OK);
  120. break;
  121. case PTREQ_BL_GETSTATE:
  122. err = backlight_fill_pt_message_stat(backend.backlight,
  123. &reply);
  124. send_message(c, &reply, err ? 0 : PT_FLG_OK);
  125. break;
  126. case PTREQ_BL_SETBRIGHTNESS:
  127. err = backend.backlight->set_brightness(backend.backlight,
  128. msg->bl_set.brightness);
  129. reply.error.code = htonl(err);
  130. send_message(c, &reply, err ? 0 : PT_FLG_OK);
  131. break;
  132. case PTREQ_BL_AUTODIM:
  133. err = 0;
  134. if (msg->bl_autodim.flags & htonl(PT_AUTODIM_FLG_ENABLE)) {
  135. err = enable_autodim(htonl(msg->bl_autodim.max_percent),
  136. !!(msg->bl_autodim.flags & htonl(PT_AUTODIM_FLG_ENABLE_AC)));
  137. } else {
  138. disable_autodim();
  139. }
  140. reply.error.code = htonl(err);
  141. send_message(c, &reply, err ? 0 : PT_FLG_OK);
  142. break;
  143. case PTREQ_BAT_GETSTATE:
  144. err = battery_fill_pt_message_stat(backend.battery, &reply);
  145. send_message(c, &reply, err ? 0 : PT_FLG_OK);
  146. break;
  147. default:
  148. logerr("Received unknown message %u\n", ntohs(msg->id));
  149. }
  150. }
  151. static void notify_client(struct client *c, struct pt_message *msg, uint16_t flags)
  152. {
  153. if (c->notifications_enabled)
  154. send_message(c, msg, flags);
  155. }
  156. void notify_clients(struct pt_message *msg, uint16_t flags)
  157. {
  158. struct client *c;
  159. list_for_each_entry(c, &client_list, list)
  160. notify_client(c, msg, flags);
  161. }
  162. static struct client * new_client(int fd)
  163. {
  164. struct client *c;
  165. c = zalloc(sizeof(*c));
  166. if (!c)
  167. return NULL;
  168. c->fd = fd;
  169. INIT_LIST_HEAD(&c->list);
  170. return c;
  171. }
  172. static void remove_client(struct client *c)
  173. {
  174. list_del(&c->list);
  175. logdebug("Client disconnected, fd=%d\n", c->fd);
  176. free(c);
  177. }
  178. static void disconnect_client(struct client *c)
  179. {
  180. struct pt_message msg = {
  181. .id = htons(PTNOTI_SRVDOWN),
  182. };
  183. notify_client(c, &msg, PT_FLG_OK);
  184. }
  185. static void force_disconnect_clients(void)
  186. {
  187. struct client *c, *c_tmp;
  188. list_for_each_entry_safe(c, c_tmp, &client_list, list) {
  189. disconnect_client(c);
  190. remove_client(c);
  191. }
  192. }
  193. static void recv_clients(void)
  194. {
  195. struct client *c, *c_tmp;
  196. ssize_t count;
  197. size_t pos;
  198. struct pt_message msg;
  199. list_for_each_entry_safe(c, c_tmp, &client_list, list) {
  200. pos = 0;
  201. do {
  202. count = recv(c->fd, &msg, sizeof(msg), 0);
  203. if (count < 0)
  204. goto next_client;
  205. if (count == 0) {
  206. remove_client(c);
  207. goto next_client;
  208. }
  209. pos += count;
  210. } while (pos != sizeof(msg));
  211. received_message(c, &msg);
  212. next_client:
  213. continue;
  214. }
  215. }
  216. static void socket_accept(int fd)
  217. {
  218. socklen_t socklen;
  219. struct sockaddr_un remoteaddr;
  220. int err, cfd;
  221. pid_t pid;
  222. struct client *c;
  223. socklen = sizeof(remoteaddr);
  224. cfd = accept(fd, (struct sockaddr *)&remoteaddr, &socklen);
  225. if (cfd == -1)
  226. return;
  227. /* connected */
  228. pid = getpid();
  229. err = ioctl(cfd, SIOCSPGRP, &pid);
  230. if (err) {
  231. logerr("Failed to set SIOCSPGRP: %s\n",
  232. strerror(errno));
  233. goto error_close;
  234. }
  235. err = fcntl(cfd, F_SETFL, O_NONBLOCK | O_ASYNC);
  236. if (err) {
  237. logerr("Failed to set flags on client: %s\n",
  238. strerror(errno));
  239. goto error_close;
  240. }
  241. c = new_client(cfd);
  242. if (!c)
  243. goto error_close;
  244. list_add_tail(&c->list, &client_list);
  245. logdebug("Client connected, fd=%d\n", cfd);
  246. return;
  247. error_close:
  248. close(cfd);
  249. }
  250. static int new_socket(const char *path, unsigned int perm,
  251. unsigned int nrlisten)
  252. {
  253. struct sockaddr_un sockaddr;
  254. int err, fd;
  255. pid_t pid;
  256. fd = socket(AF_UNIX, SOCK_STREAM, 0);
  257. if (fd == -1) {
  258. logerr("Failed to create socket %s: %s\n",
  259. path, strerror(errno));
  260. goto error;
  261. }
  262. pid = getpid();
  263. err = ioctl(fd, SIOCSPGRP, &pid);
  264. if (err) {
  265. logerr("Failed to set SIOCSPGRP: %s\n",
  266. strerror(errno));
  267. goto error_close_sock;
  268. }
  269. err = fcntl(fd, F_SETFL, O_NONBLOCK | O_ASYNC);
  270. if (err) {
  271. logerr("Failed to set flags on socket %s: %s\n",
  272. path, strerror(errno));
  273. goto error_close_sock;
  274. }
  275. if (cmdargs.force)
  276. unlink(path);
  277. sockaddr.sun_family = AF_UNIX;
  278. strncpy(sockaddr.sun_path, path, sizeof(sockaddr.sun_path) - 1);
  279. err = bind(fd, (struct sockaddr *)&sockaddr, SUN_LEN(&sockaddr));
  280. if (err) {
  281. logerr("Failed to bind socket to %s: %s\n",
  282. path, strerror(errno));
  283. goto error_close_sock;
  284. }
  285. err = chmod(path, perm);
  286. if (err) {
  287. logerr("Failed to set %s socket permissions: %s\n",
  288. path, strerror(errno));
  289. goto error_unlink_sock;
  290. }
  291. err = listen(fd, nrlisten);
  292. if (err) {
  293. logerr("Failed to listen on socket %s: %s\n",
  294. path, strerror(errno));
  295. goto error_unlink_sock;
  296. }
  297. return fd;
  298. error_unlink_sock:
  299. unlink(path);
  300. error_close_sock:
  301. close(fd);
  302. error:
  303. return -1;
  304. }
  305. static int create_socket(void)
  306. {
  307. int err;
  308. err = mkdir(PT_SOCK_DIR, 0755);
  309. if (err && errno != EEXIST) {
  310. logerr("Failed to create directory %s: %s\n",
  311. PT_SOCK_DIR, strerror(errno));
  312. return err;
  313. }
  314. socket_fd = new_socket(PT_SOCKET, 0666, 10);
  315. if (socket_fd == -1)
  316. goto err_rmdir;
  317. return 0;
  318. err_rmdir:
  319. rmdir(PT_SOCK_DIR);
  320. return -1;
  321. }
  322. static void remove_socket(void)
  323. {
  324. if (socket_fd != -1) {
  325. close(socket_fd);
  326. socket_fd = -1;
  327. unlink(PT_SOCKET);
  328. rmdir(PT_SOCK_DIR);
  329. }
  330. }
  331. static int create_pidfile(void)
  332. {
  333. char buf[32] = { 0, };
  334. const char *write_ptr;
  335. pid_t pid = getpid();
  336. int fd;
  337. size_t count;
  338. ssize_t res;
  339. if (!cmdargs.pidfile)
  340. return 0;
  341. fd = open(cmdargs.pidfile, O_RDWR | O_CREAT | O_TRUNC, 0444);
  342. if (fd < 0) {
  343. logerr("Failed to create PID-file %s: %s\n",
  344. cmdargs.pidfile, strerror(errno));
  345. return -1;
  346. }
  347. snprintf(buf, sizeof(buf), "%lu",
  348. (unsigned long)pid);
  349. count = strlen(buf);
  350. write_ptr = buf;
  351. while (count) {
  352. res = write(fd, write_ptr, count);
  353. if (res < 0) {
  354. logerr("Failed to write PID-file %s: %s\n",
  355. cmdargs.pidfile, strerror(errno));
  356. return -1;
  357. }
  358. count -= (size_t)res;
  359. write_ptr += (size_t)res;
  360. }
  361. return 0;
  362. }
  363. static void remove_pidfile(void)
  364. {
  365. if (cmdargs.pidfile) {
  366. unlink(cmdargs.pidfile);
  367. cmdargs.pidfile = NULL;
  368. }
  369. }
  370. static void shutdown_cleanup(void)
  371. {
  372. block_signals();
  373. force_disconnect_clients();
  374. xevrep_disable(&backend.xevrep);
  375. xevrep_sigchld(&backend.xevrep, 1);
  376. unblock_x11_input(&backend.x11lock);
  377. x11lock_sigchld(&backend.x11lock, 1);
  378. autodim_destroy(backend.autodim);
  379. autodim_free(backend.autodim);
  380. backend.autodim = NULL;
  381. devicelock_destroy(backend.devicelock);
  382. backend.devicelock = NULL;
  383. backlight_destroy(backend.backlight);
  384. backend.backlight = NULL;
  385. battery_destroy(backend.battery);
  386. backend.battery = NULL;
  387. remove_pidfile();
  388. remove_socket();
  389. config_file_free(backend.config);
  390. backend.config = NULL;
  391. unblock_signals();
  392. }
  393. static inline void enter_signal(void)
  394. {
  395. in_signal = 1;
  396. compiler_barrier();
  397. }
  398. static inline void leave_signal(void)
  399. {
  400. compiler_barrier();
  401. in_signal = 0;
  402. }
  403. static void signal_terminate(int signal)
  404. {
  405. enter_signal();
  406. loginfo("Terminating signal received.\n");
  407. shutdown_cleanup();
  408. leave_signal();
  409. exit(1);
  410. }
  411. static void signal_pipe(int signal)
  412. {
  413. enter_signal();
  414. logerr("Broken pipe.\n");
  415. leave_signal();
  416. }
  417. static void signal_async_io(int signal)
  418. {
  419. enter_signal();
  420. socket_accept(socket_fd);
  421. recv_clients();
  422. leave_signal();
  423. }
  424. static void signal_input_event_1(int signal)
  425. {
  426. enter_signal();
  427. if (backend.autodim)
  428. autodim_handle_input_event(backend.autodim);
  429. leave_signal();
  430. }
  431. static void signal_input_event_2(int signal)
  432. {
  433. enter_signal();
  434. backend.devicelock->event(backend.devicelock);
  435. leave_signal();
  436. }
  437. static void signal_child(int signal)
  438. {
  439. enter_signal();
  440. x11lock_sigchld(&backend.x11lock, 0);
  441. xevrep_sigchld(&backend.xevrep, 0);
  442. leave_signal();
  443. }
  444. #define sigset_set_blocked_sigs(setp) do { \
  445. sigemptyset((setp)); \
  446. sigaddset((setp), SIGCHLD); \
  447. sigaddset((setp), SIGUSR1); \
  448. sigaddset((setp), SIGUSR2); \
  449. sigaddset((setp), SIGIO); \
  450. sigaddset((setp), SIGPIPE); \
  451. sigaddset((setp), SIGINT); \
  452. sigaddset((setp), SIGTERM); \
  453. } while (0)
  454. void block_signals(void)
  455. {
  456. sigset_t set;
  457. if (!in_signal) {
  458. assert(sig_block_count >= 0);
  459. if (sig_block_count++ == 0) {
  460. sigset_set_blocked_sigs(&set);
  461. if (sigprocmask(SIG_BLOCK, &set, NULL)) {
  462. logerr("Failed to block signals: %s\n",
  463. strerror(errno));
  464. }
  465. }
  466. }
  467. compiler_barrier();
  468. }
  469. void unblock_signals(void)
  470. {
  471. sigset_t set;
  472. compiler_barrier();
  473. if (!in_signal) {
  474. if (--sig_block_count == 0) {
  475. sigset_set_blocked_sigs(&set);
  476. if (sigprocmask(SIG_UNBLOCK, &set, NULL)) {
  477. logerr("Failed to unblock signals: %s\n",
  478. strerror(errno));
  479. }
  480. }
  481. assert(sig_block_count >= 0);
  482. }
  483. }
  484. static int install_sighandler(int signal, int ignore, void (*handler)(int))
  485. {
  486. struct sigaction act;
  487. memset(&act, 0, sizeof(act));
  488. sigset_set_blocked_sigs(&act.sa_mask);
  489. act.sa_flags = 0;
  490. act.sa_handler = ignore ? SIG_IGN : handler;
  491. return sigaction(signal, &act, NULL);
  492. }
  493. static int setup_signal_handlers(int ignore_signals)
  494. {
  495. int err = 0;
  496. err |= install_sighandler(SIGINT, ignore_signals, signal_terminate);
  497. err |= install_sighandler(SIGTERM, ignore_signals, signal_terminate);
  498. err |= install_sighandler(SIGPIPE, ignore_signals, signal_pipe);
  499. err |= install_sighandler(SIGIO, ignore_signals, signal_async_io);
  500. err |= install_sighandler(SIGUSR1, ignore_signals, signal_input_event_1);
  501. err |= install_sighandler(SIGUSR2, ignore_signals, signal_input_event_2);
  502. err |= install_sighandler(SIGCHLD, ignore_signals, signal_child);
  503. return err ? -1 : 0;
  504. }
  505. static int set_niceness(void)
  506. {
  507. int err, nice_level;
  508. nice_level = config_get_int(backend.config, "SYSTEM", "nice", 5);
  509. nice_level = clamp(nice_level, -20, 19);
  510. err = setpriority(PRIO_PROCESS, 0, nice_level);
  511. if (err) {
  512. logerr("Failed to set niceness to %d: %s\n",
  513. nice_level, strerror(errno));
  514. return -errno;
  515. }
  516. return 0;
  517. }
  518. static int mainloop(void)
  519. {
  520. int err, value, on_ac;
  521. unsigned int timer_errors = 0;
  522. log_initialize();
  523. err = setup_signal_handlers(1);
  524. if (err)
  525. goto error;
  526. err = -ENOMEM;
  527. backend.config = config_file_parse("/etc/pwrtray-backendrc");
  528. if (!backend.config)
  529. goto error;
  530. err = sleeptimer_system_init();
  531. if (err)
  532. goto error;
  533. err = -ENOMEM;
  534. backend.battery = battery_probe();
  535. if (!backend.battery)
  536. goto error;
  537. backend.backlight = backlight_probe();
  538. if (!backend.backlight)
  539. goto error;
  540. if (config_get_bool(backend.config, "BACKLIGHT", "autodim_default_on", 0)) {
  541. value = backlight_get_percentage(backend.backlight);
  542. if (value < 0)
  543. value = 100;
  544. on_ac = config_get_bool(backend.config, "BACKLIGHT",
  545. "autodim_default_on_ac", 0);
  546. if (enable_autodim(value, on_ac))
  547. logerr("Failed to initially enable autodimming\n");
  548. }
  549. backend.devicelock = devicelock_probe();
  550. if (!backend.devicelock)
  551. goto error;
  552. err = create_socket();
  553. if (err)
  554. goto error;
  555. err = create_pidfile();
  556. if (err)
  557. goto error;
  558. err = setup_signal_handlers(0);
  559. if (err)
  560. goto error;
  561. err = set_niceness();
  562. if (err)
  563. goto error;
  564. loginfo("pwrtray-backend started\n");
  565. while (1) {
  566. err = sleeptimer_wait_next();
  567. if (!err)
  568. continue;
  569. if (timer_errors < 10) {
  570. timer_errors++;
  571. logdebug("Mainloop: sleeptimer_wait_next() failed with %d (%s)\n",
  572. err, strerror(-err));
  573. }
  574. msleep(1000);
  575. }
  576. error:
  577. shutdown_cleanup();
  578. log_exit();
  579. return err ? 1 : 0;
  580. }
  581. int main(int argc, char **argv)
  582. {
  583. int err;
  584. err = parse_commandline(argc, argv);
  585. if (err)
  586. return (err < 0) ? 1 : 0;
  587. if (cmdargs.background) {
  588. err = daemon(0, 0);
  589. if (err) {
  590. logerr("Failed to fork into background: %s\n",
  591. strerror(errno));
  592. return 1;
  593. }
  594. /* We are in the child process. */
  595. return mainloop();
  596. }
  597. return mainloop();
  598. }