common_defs.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892
  1. /*
  2. * Copyright (c) 2019 Clementine Computing LLC.
  3. *
  4. * This file is part of PopuFare.
  5. *
  6. * PopuFare is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * PopuFare is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with PopuFare. If not, see <https:// www.gnu.org/licenses/>.
  18. *
  19. */
  20. #include <sys/termios.h>
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23. #include <sys/ioctl.h>
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <fcntl.h>
  27. #include <unistd.h>
  28. #include <signal.h>
  29. #include <string.h>
  30. #include <poll.h>
  31. #include <syslog.h>
  32. #include <sysexits.h>
  33. #include <stdarg.h>
  34. #include <dirent.h>
  35. #include <fnmatch.h>
  36. #include "common_defs.h"
  37. #ifndef DEFAULT_BAUD
  38. #define DEFAULT_BAUD (B115200)
  39. #endif
  40. // ------------------------------------------- This horrible blob of code goes and hunts for package install records and gathers
  41. // ------------------------------------------- them into a sane data structure for display to the user in status/diagnostic screens.
  42. #define PKG_SEARCH_DIR CONFIG_FILE_PATH
  43. #define PATTERN_SUFFIX ".tgz.version"
  44. #define CHECKSUM_SUFFIX ".tgz.checksum"
  45. #define PATTTERN ("*" PATTERN_SUFFIX)
  46. static int package_filter(const struct dirent *file) {
  47. int match = fnmatch(PATTTERN, file->d_name, 0);
  48. return !match;
  49. }
  50. int find_packages(package_signature *pkgs, int n) {
  51. int i = 0;
  52. int scandir_ret;
  53. struct dirent **matchlist;
  54. int j;
  55. int match_len;
  56. int suffix_len = strlen(PATTERN_SUFFIX);
  57. FILE *f;
  58. struct stat st;
  59. char pathbuffer[1024];
  60. // Look for any file that matches the pattern PATTERN (see package_filter above) and return into matchlist a pointer
  61. // to and array of pointers to dirent structures for each directory entry that made the cut, sorted alphabetically
  62. //
  63. scandir_ret = scandir(PKG_SEARCH_DIR, &matchlist, package_filter, alphasort);
  64. // If that seemed to work....
  65. //
  66. if( (scandir_ret >= 0) && (matchlist != NULL) ) {
  67. // Walk the resultant list
  68. //
  69. for(i=0; i < scandir_ret; i++) {
  70. // if we've filled our caller's buffer, break out now
  71. //
  72. if(i >= n) {
  73. break;
  74. }
  75. // Go figure out how long the module name part is (it'll be the length of the filename minus the length of the suffix)
  76. //
  77. match_len = strlen(matchlist[i]->d_name) - suffix_len;
  78. // If that would cause an overflow, truncate it...
  79. //
  80. if (match_len > (PKG_STRING_SIZE - 1)) {
  81. match_len = PKG_STRING_SIZE - 1;
  82. }
  83. // Copy our package name
  84. //
  85. strncpy(pkgs[i].pkgname, matchlist[i]->d_name, match_len);
  86. pkgs[i].pkgname[match_len] = '\0';
  87. // (if fscanf fails, we want an empty string rather than random crap from memory...)
  88. //
  89. pkgs[i].pkgver[0] = '\0';
  90. // generate the file name of the package version string...
  91. //
  92. snprintf(pathbuffer, sizeof(pathbuffer), "%s%s%s", PKG_SEARCH_DIR, pkgs[i].pkgname, PATTERN_SUFFIX);
  93. // Go and read the contents of that into the pkgver part of our structure...
  94. //
  95. f = fopen(pathbuffer, "rb");
  96. if (f) {
  97. fscanf(f, PKG_STRING_FORMAT, pkgs[i].pkgver);
  98. fclose(f);
  99. }
  100. pkgs[i].checksum[0] = '\0';
  101. // generate the file name of the file containing the package checksum
  102. //
  103. snprintf(pathbuffer, sizeof(pathbuffer), "%s%s%s", PKG_SEARCH_DIR, pkgs[i].pkgname, CHECKSUM_SUFFIX);
  104. // Go and read the contents of that into the checkdum part of our structure...
  105. //
  106. f = fopen(pathbuffer, "rb");
  107. if (f) {
  108. fscanf(f, PKG_STRING_FORMAT, pkgs[i].checksum);
  109. fclose(f);
  110. }
  111. pkgs[i].installed = 0;
  112. // Go and grab the mtime of the package install file
  113. //
  114. if (!stat(pathbuffer, &st)) {
  115. pkgs[i].installed = st.st_mtime;
  116. }
  117. // Free this dirent
  118. //
  119. free(matchlist[i]);
  120. }
  121. // Clean up any leftovers
  122. //
  123. for (j = i; j < scandir_ret; j++) {
  124. free(matchlist[i]);
  125. }
  126. // free the array of pointers
  127. //
  128. free(matchlist);
  129. }
  130. // return the number actually filled
  131. //
  132. return i;
  133. }
  134. // --------------------------------------------------------------------------------------------------
  135. // This function checks the dropfile to see if the tunnel is up...
  136. //
  137. int tunnel_is_up() {
  138. struct stat st;
  139. int retval;
  140. retval = stat(TUNNEL_DROPFILE, &st);
  141. if (retval) {
  142. return 0;
  143. }
  144. else {
  145. return 1;
  146. }
  147. }
  148. // This function checks the dropfile to see if the GPRS modem is up...
  149. //
  150. int gprs_is_up() {
  151. struct stat st;
  152. int retval;
  153. retval = stat(GPRS_DROPFILE, &st);
  154. if(retval) {
  155. return 0;
  156. }
  157. else {
  158. return 1;
  159. }
  160. }
  161. // This function gets the equipment number from the appropriate config file
  162. // If it cannot be gotten, it returns -1
  163. //
  164. int get_equip_num() {
  165. FILE *f;
  166. int num = -1;
  167. f = fopen(EQUIPNUM_FILE, "rb");
  168. if (f) {
  169. fscanf(f,"%d",&num);
  170. fclose(f);
  171. }
  172. else {
  173. num = -1;
  174. }
  175. return num;
  176. }
  177. // This function sets the euipment number in the config file.
  178. // if this operation fails, -1 is returned.
  179. //
  180. int set_equip_num(int num) {
  181. FILE *f;
  182. if ( (num < 1) || (num > MAX_EQUIPNUM) ) {
  183. return -1;
  184. }
  185. f = fopen(EQUIPNUM_TEMPFILE, "wb");
  186. if (f) {
  187. fprintf(f,"%d\n", num);
  188. fclose(f);
  189. rename(EQUIPNUM_TEMPFILE, EQUIPNUM_FILE);
  190. sync();
  191. return 0;
  192. }
  193. return -1;
  194. }
  195. //
  196. int get_server_desc(char *desc, int len) {
  197. char svrname[LINE_BUFFER_SIZE];
  198. FILE *f;
  199. if (!desc) {
  200. return -1;
  201. }
  202. if (len <= 0) {
  203. return -1;
  204. }
  205. f = fopen(SERVER_DESC_FILE, "rb");
  206. if (f) {
  207. fgets(svrname, LINE_BUFFER_SIZE, f);
  208. svrname[LINE_BUFFER_SIZE - 1] = '\0';
  209. strip_crlf(svrname);
  210. strncpy(desc, svrname, len);
  211. desc[len - 1] = '\0';
  212. return 0;
  213. }
  214. return -1;
  215. }
  216. int get_field(char *dest, char *src, int dest_len, int *eol_flag) {
  217. int i,j;
  218. int done = 0;
  219. int eol = 0;
  220. i = j = 0;
  221. while ( ! done ) {
  222. switch(src[i]) {
  223. case '\0': // If we've hit the end of the input line
  224. case '\n':
  225. case '\r':
  226. // cap off our destination string if there is room
  227. //
  228. if (j < dest_len) {
  229. dest[j++] = '\0';
  230. }
  231. // set our internal End Of Line flag
  232. //
  233. eol = 1;
  234. // set the done flag so we break out of the while
  235. //
  236. done = 1;
  237. break;
  238. // If we have hit a record boundary
  239. //
  240. case '\t':
  241. // cap off our input line
  242. //
  243. if (j < dest_len) {
  244. dest[j++] = '\0';
  245. }
  246. // Advance past this input character
  247. //
  248. i++;
  249. // flag us as done
  250. //
  251. done = 1;
  252. break;
  253. // otherwise (for normal characters) just copy them if there is space
  254. //
  255. default:
  256. if (j < dest_len) {
  257. dest[j++] = src[i];
  258. }
  259. // and advance past them
  260. //
  261. i++;
  262. break;
  263. }
  264. }
  265. // If we have filled our line to capacity
  266. //
  267. if ( j == dest_len ) {
  268. // Truncate it by 1 character to fit the terminating NUL
  269. //
  270. dest[dest_len - 1] = '\0';
  271. }
  272. // If the user has passed us a place to store our EOL flag,
  273. //
  274. if( eol_flag != NULL ) {
  275. // store it there
  276. //
  277. *eol_flag = eol;
  278. }
  279. // Return the index of the next character to be consumed.
  280. //
  281. return i;
  282. }
  283. // magic hash function hashes english strings well enough for our needs
  284. //
  285. unsigned long long stringhash(char *string) {
  286. unsigned long long hash = 5381;
  287. int c;
  288. while ((c = *string++)) {
  289. /* hash * 33 + c */
  290. hash = ((hash << 5) + hash) + c;
  291. }
  292. return hash;
  293. }
  294. int strip_crlf(char *buffer) {
  295. char *src,*dst;
  296. int count=0;
  297. // Set both our source and destination pointers to the buffer in question
  298. //
  299. src=dst=buffer;
  300. // While we still have unprocessed buffer bytes
  301. //
  302. while(*src) {
  303. // If we encounter a CR or LF character
  304. //
  305. if((*src == '\r') || (*src == '\n')) {
  306. // If the NEXT character is not another EOL character or a terminating nul
  307. //
  308. if( (src[1] != '\0') && (src[1] != '\r') && (src[1] != '\n') ) {
  309. src++;
  310. // replace the CR or LF with a space.
  311. //
  312. *dst++ = ' ';
  313. count++;
  314. continue;
  315. }
  316. // On the other hand, if what comes next is EOL or end of string,
  317. //
  318. else {
  319. // just trim this character
  320. //
  321. src++;
  322. continue;
  323. }
  324. }
  325. // If this character isn't one of the special ones, just copy it.
  326. //
  327. *dst++ = *src++;
  328. count++;
  329. }
  330. // Copy the terminating NUL
  331. //
  332. *dst++ = *src++;
  333. return count;
  334. }
  335. int open_rs232_device(char *devname, int custom_baud, int linemode) {
  336. struct termios tty={0};
  337. int retval;
  338. int fd;
  339. // Open the specified character device READ/WRITE and not as a Controlling TTY
  340. //
  341. fd = open(devname, O_RDWR | O_NOCTTY);
  342. if (fd < 0) {
  343. #ifdef COMMON_PRINT_WARNING
  344. fprintf(stderr, "Warning: Cannot open TTY %s\n", devname);
  345. #endif
  346. return -1;
  347. }
  348. // Try and fetch the TTY properties of the device
  349. //
  350. retval = ioctl(fd, TCGETS, &tty);
  351. if (retval) {
  352. #ifdef COMMON_PRINT_WARNING
  353. fprintf(stderr, "Warning: Cannot get TTY attributes on %s. Not a TTY?\n", devname);
  354. #endif
  355. close(fd);
  356. return -1;
  357. }
  358. if (custom_baud > 0) {
  359. tty.c_cflag = custom_baud | CS8 | CREAD | CLOCAL;
  360. }
  361. else {
  362. tty.c_cflag = DEFAULT_BAUD | CS8 | CREAD | CLOCAL;
  363. }
  364. if (linemode) {
  365. tty.c_iflag = IGNBRK;
  366. tty.c_oflag = 0;
  367. tty.c_lflag = ICANON;
  368. tty.c_line = 0;
  369. tty.c_cc[VMIN] = 1; // minimum one character read
  370. tty.c_cc[VTIME] = ACCUM_SECONDS * 10; // wait ACCUM_SECONDS without any further chars
  371. // before giving up on the arrival of a newline.
  372. // (VTIME is specified in deciseconds (who knows why...))
  373. tty.c_cc[VEOL] = '\n'; // allow a newline to release the buffer
  374. }
  375. else {
  376. tty.c_iflag = IGNBRK;
  377. tty.c_oflag = 0;
  378. tty.c_lflag = 0;
  379. tty.c_line = 0;
  380. tty.c_cc[VMIN] = 1;
  381. tty.c_cc[VTIME] = 5;
  382. }
  383. // try and plunk our desired settings down on the device
  384. //
  385. retval = ioctl(fd, TCSETS, &tty);
  386. if (retval) {
  387. #ifdef COMMON_PRINT_WARNING
  388. fprintf(stderr, "Warning: Cannot set TTY attributes on %s. Unsupported mode?\n", devname);
  389. #endif
  390. close(fd);
  391. return -1;
  392. }
  393. // flush the serial port buffers to clean up any detritus that has accumulated before we got here
  394. //
  395. tcflush(fd, TCIOFLUSH);
  396. return fd;
  397. }
  398. static int read_with_timeout(int fd, void *buffer, int n, int timeout) {
  399. int retval;
  400. struct pollfd fds[1];
  401. fds[0].fd = fd;
  402. fds[0].events = POLLIN;
  403. retval = poll(fds, 1, timeout);
  404. if (retval > 0) {
  405. return read(fd, buffer, n);
  406. }
  407. else {
  408. return retval;
  409. }
  410. }
  411. static int init_device(int fd, device_test_vector *vec, char *diag) {
  412. char buffer[1024] = {0};
  413. int i;
  414. int retval;
  415. int len;
  416. char *trav;
  417. int timeout = DEVICE_TEST_TIMEOUT;
  418. if (vec->init_timeout > 0) {
  419. timeout = vec->init_timeout;
  420. }
  421. // If we were given an init string
  422. //
  423. if (vec->init_string != NULL) {
  424. // calculate how long it is
  425. //
  426. len = strlen(vec->init_string);
  427. // send it on its way
  428. //
  429. retval = write(fd, vec->init_string, len);
  430. // if that didn't work
  431. //
  432. if (retval != len) {
  433. // complain and fail
  434. //
  435. if (diag) {
  436. snprintf(diag, DIAG_BUFFER_SIZE, "Cannot write init string to device.");
  437. }
  438. return -1;
  439. }
  440. }
  441. i = 0;
  442. while (i < vec->n_reply_lines) {
  443. // Ask the kernel for a line from the TTY
  444. //
  445. retval = read_with_timeout(fd, buffer, sizeof(buffer), timeout);
  446. // If we DID read something from the device, make sure it is correct
  447. //
  448. if(retval > 0) {
  449. buffer[retval] = '\0';
  450. strip_crlf(buffer);
  451. trav = buffer;
  452. // Skip any garbage before the start character
  453. //
  454. while (*trav && (*trav != '/')) {
  455. trav++;
  456. }
  457. if (*trav == '\0') {
  458. continue; // ignore blank lines
  459. }
  460. if ( (trav[0] == '/') && (trav[1] == '?') && (trav[2] == ':') ) {
  461. // ignore device ID lines
  462. //
  463. continue;
  464. }
  465. // The order of these tests in importand. Short circuit keeps us from
  466. // dereferencing expected_reply_lines if the first test fails
  467. //
  468. // If we have a pattern to test against
  469. //
  470. if ( (vec->reply_strings != NULL) && (vec->reply_strings[i] != NULL) ) {
  471. if (strcmp(trav, vec->reply_strings[i])) {
  472. if (diag) {
  473. snprintf(diag, DIAG_BUFFER_SIZE, "Read init reply line %d from device, expected \"%s\" but got \"%s\"", i, vec->reply_strings[i], trav);
  474. }
  475. return -1;
  476. }
  477. }
  478. }
  479. // If we DIDN'T read anything from the device...
  480. //
  481. else {
  482. // Complain
  483. //
  484. if (diag) {
  485. snprintf(diag, DIAG_BUFFER_SIZE, "Reading init reply from device timed out waiting for line %d", i);
  486. }
  487. // And fail
  488. //
  489. return -1;
  490. }
  491. i++;
  492. }
  493. return 0;
  494. }
  495. int test_and_init_device(int fd, device_test_vector *vec, char *diag) {
  496. char buffer[DEV_INIT_BUFFER_SIZE] = {0};
  497. char module_id[DEV_INIT_BUFFER_SIZE] = {0};
  498. int tries = DEVICE_TEST_TRIES;
  499. int timeout = DEVICE_TEST_TIMEOUT;
  500. int retval;
  501. char *trav;
  502. if (vec == NULL) {
  503. return -1;
  504. }
  505. if (vec->dev_id == NULL) {
  506. return -1;
  507. }
  508. if (vec->init_tries > 0) {
  509. tries = vec->init_tries;
  510. }
  511. if (vec->init_timeout > 0) {
  512. timeout = vec->init_timeout;
  513. }
  514. // We want to iterate through DEVICE_TEST_TRIES tries at getting a valid line from the device
  515. //
  516. do {
  517. // Send a CR to stimulate the device to spit out its help message
  518. //
  519. write(fd,"\r", 1);
  520. // Ask the kernel for a line from the TTY
  521. //
  522. retval = read_with_timeout(fd, buffer, sizeof(buffer), timeout);
  523. // If we actually got a line of data
  524. //
  525. if (retval > 0) {
  526. buffer[retval] = '\0';
  527. strip_crlf(buffer);
  528. // Start examining our buffer
  529. //
  530. trav = buffer;
  531. // Skip any garbage before the start character
  532. //
  533. while (*trav && (*trav != '/')) {
  534. trav++;
  535. }
  536. // See if it is our Device ID / help line...
  537. //
  538. if ( (trav[0] == '/') && (trav[1] == '?') && (trav[2] == ':') ) {
  539. // Skip the header and go to the body
  540. //
  541. trav += 3;
  542. // Look for our module ID string
  543. //
  544. retval = sscanf(trav, " ?=%s", module_id);
  545. if (retval < 1) {
  546. // Look for our module ID string without leading space
  547. //
  548. retval = sscanf(trav, "?=%s", module_id);
  549. }
  550. // If we have found id
  551. //
  552. if (retval == 1) {
  553. // See if it is the correct one
  554. //
  555. if (!strcmp(module_id, vec->dev_id)) {
  556. // If so, pass on our diagnostic message if we have a place to
  557. //
  558. if (diag) {
  559. snprintf(diag, DIAG_BUFFER_SIZE, "Device connected OK");
  560. }
  561. return init_device(fd, vec, diag); // Perform initialization and return the status of that operation
  562. }
  563. // Otherwise, if it is NOT the one we are expecting
  564. //
  565. else {
  566. // Complain if we have a place to
  567. //
  568. if (diag) {
  569. snprintf(diag, DIAG_BUFFER_SIZE, "Device present: Expecting: \"%s\" Got: \"%s\"", vec->dev_id, module_id);
  570. }
  571. return -2; // Return a distinct failure code
  572. }
  573. }
  574. }
  575. // If we DIDN'T get the line we were looking for, pretend it was blank so we'll try again...
  576. //
  577. else {
  578. // This pretends the received line was black.
  579. //
  580. retval = 0;
  581. }
  582. // if we got 0 bytes or EINTR from the alarm firing
  583. //
  584. }
  585. // While we still have tries and a previous try didn't work
  586. //
  587. } while ( (retval <= 0) && ( --tries > 0) );
  588. if (diag) {
  589. snprintf(diag, DIAG_BUFFER_SIZE, "Could not get reply from device");
  590. }
  591. return -1;
  592. }
  593. // ========================================================================================================
  594. // ------------------------------- WATCHDOG TIMER and other SIGNAL HANDLERS -------------------------------
  595. // ========================================================================================================
  596. // volatile int hup_request_status = 0;
  597. //
  598. volatile sig_atomic_t hup_request_status = 0;
  599. void request_hup(char *fmt, ...) {
  600. va_list ap;
  601. hup_request_status = 1;
  602. va_start(ap, fmt);
  603. vprintf(fmt, ap);
  604. va_end(ap);
  605. }
  606. // Our signal handlers and standard message handlers will OR these bits into exit_request_status
  607. //
  608. volatile int exit_request_status = 0;
  609. static int exit_signal_counter = 0;
  610. void request_polite_exit(int reason, char *fmt, ...) {
  611. va_list ap;
  612. exit_request_status |= reason;
  613. if (reason) {
  614. exit_signal_counter++;
  615. }
  616. if (exit_request_status & EXIT_REQUEST_CRASH) {
  617. va_start(ap, fmt);
  618. vsyslog(LOG_ERR, fmt, ap);
  619. va_end(ap);
  620. exit(EX_SOFTWARE);
  621. }
  622. if (exit_signal_counter >= MAX_POLITE_EXIT_REQUESTS) {
  623. va_start(ap, fmt);
  624. vsyslog(LOG_NOTICE, fmt, ap);
  625. va_end(ap);
  626. exit(SIGTERM);
  627. }
  628. }
  629. static void watchdog_handler(int signum, siginfo_t *info, void *data) {
  630. request_polite_exit(EXIT_REQUEST_CRASH, "Watchdog timer has expired!");
  631. }
  632. static void term_int_handler(int signum, siginfo_t *info, void *data) {
  633. request_polite_exit(EXIT_REQUEST_INT_TERM, "Received signal %d", signum);
  634. }
  635. static void hard_crash_handler(int signum, siginfo_t *info, void *data) {
  636. switch(signum) {
  637. case SIGSEGV:
  638. request_polite_exit(EXIT_REQUEST_CRASH, "Segmentation fault at virtual address %p", info->si_addr);
  639. break;
  640. case SIGILL:
  641. request_polite_exit(EXIT_REQUEST_CRASH, "Illegal instruction at virtual address %p", info->si_addr);
  642. break;
  643. case SIGFPE:
  644. request_polite_exit(EXIT_REQUEST_CRASH, "Floating point exception at virtual address %p", info->si_addr);
  645. break;
  646. case SIGBUS:
  647. request_polite_exit(EXIT_REQUEST_CRASH, "SIGBUS (hardware error!) at address %p", info->si_addr);
  648. break;
  649. default:
  650. request_polite_exit(EXIT_REQUEST_CRASH, "Caught Signal %d", signum);
  651. break;
  652. }
  653. }
  654. void configure_signal_handlers(char *procname) {
  655. struct sigaction sa = {{0}};
  656. openlog(procname, LOG_CONS | LOG_PERROR, LOG_USER);
  657. #ifdef USE_WATCHDOG_ALARM
  658. sa.sa_sigaction = watchdog_handler;
  659. sa.sa_flags = SA_SIGINFO;
  660. sigfillset(&sa.sa_mask);
  661. sigaction(SIGALRM, &sa, NULL);
  662. RESET_WATCHDOG();
  663. #endif
  664. // Install our "boy did we ever fuck up this time" signal handler
  665. // to trap segmentation faults, illegal instructions, divides by zero,
  666. // and things like RAM chips popping off a running board (SIGBUS).
  667. //
  668. sa.sa_sigaction = hard_crash_handler;
  669. sa.sa_flags = SA_SIGINFO;
  670. sigaction(SIGSEGV, &sa, NULL);
  671. sigaction(SIGILL, &sa, NULL);
  672. sigaction(SIGFPE, &sa, NULL);
  673. sigaction(SIGBUS, &sa, NULL);
  674. // Install our polite exit handler...
  675. //
  676. sa.sa_sigaction = term_int_handler;
  677. sa.sa_flags = SA_SIGINFO | SA_RESTART; // Allow interrupted I/O calls to finish to facilitate clean exit
  678. sigaction(SIGTERM, &sa, NULL);
  679. sigaction(SIGINT, &sa, NULL);
  680. }
  681. // ------------------