diff options
author | Ron Yorston <rmy@pobox.com> | 2017-07-18 15:58:52 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2017-07-18 15:58:52 +0100 |
commit | b680f05ad449505e3d914bebd4c8d83bf768c094 (patch) | |
tree | c08ded13d430b0e7e0104f2eb594fad190ce98a3 /miscutils | |
parent | 258200ff81d5a9da54dab35acf36213eff1e399b (diff) | |
parent | 513a2457b65894b10b9fd6aa8753fca59eced08c (diff) | |
download | busybox-w32-b680f05ad449505e3d914bebd4c8d83bf768c094.tar.gz busybox-w32-b680f05ad449505e3d914bebd4c8d83bf768c094.tar.bz2 busybox-w32-b680f05ad449505e3d914bebd4c8d83bf768c094.zip |
Merge branch 'busybox' into merge
Diffstat (limited to 'miscutils')
-rw-r--r-- | miscutils/beep.c | 2 | ||||
-rw-r--r-- | miscutils/crond.c | 140 | ||||
-rw-r--r-- | miscutils/makedevs.c | 41 | ||||
-rw-r--r-- | miscutils/ttysize.c | 7 | ||||
-rw-r--r-- | miscutils/watchdog.c | 66 |
5 files changed, 194 insertions, 62 deletions
diff --git a/miscutils/beep.c b/miscutils/beep.c index 14802b543..216f69400 100644 --- a/miscutils/beep.c +++ b/miscutils/beep.c | |||
@@ -16,7 +16,7 @@ | |||
16 | //config: | 16 | //config: |
17 | //config:config FEATURE_BEEP_FREQ | 17 | //config:config FEATURE_BEEP_FREQ |
18 | //config: int "default frequency" | 18 | //config: int "default frequency" |
19 | //config: range 0 2147483647 | 19 | //config: range 20 50000 # allowing 0 here breaks the build |
20 | //config: default 4000 | 20 | //config: default 4000 |
21 | //config: depends on BEEP | 21 | //config: depends on BEEP |
22 | //config: help | 22 | //config: help |
diff --git a/miscutils/crond.c b/miscutils/crond.c index 88e7b47b3..c0c8bef11 100644 --- a/miscutils/crond.c +++ b/miscutils/crond.c | |||
@@ -35,6 +35,22 @@ | |||
35 | //config: help | 35 | //config: help |
36 | //config: Command output will be sent to corresponding user via email. | 36 | //config: Command output will be sent to corresponding user via email. |
37 | //config: | 37 | //config: |
38 | //config:config FEATURE_CROND_SPECIAL_TIMES | ||
39 | //config: bool "Support special times (@reboot, @daily, etc) in crontabs" | ||
40 | //config: default y | ||
41 | //config: depends on CROND | ||
42 | //config: help | ||
43 | //config: string meaning | ||
44 | //config: ------ ------- | ||
45 | //config: @reboot Run once, at startup | ||
46 | //config: @yearly Run once a year: "0 0 1 1 *" | ||
47 | //config: @annually Same as @yearly: "0 0 1 1 *" | ||
48 | //config: @monthly Run once a month: "0 0 1 * *" | ||
49 | //config: @weekly Run once a week: "0 0 * * 0" | ||
50 | //config: @daily Run once a day: "0 0 * * *" | ||
51 | //config: @midnight Same as @daily: "0 0 * * *" | ||
52 | //config: @hourly Run once an hour: "0 * * * *" | ||
53 | //config: | ||
38 | //config:config FEATURE_CROND_DIR | 54 | //config:config FEATURE_CROND_DIR |
39 | //config: string "crond spool directory" | 55 | //config: string "crond spool directory" |
40 | //config: default "/var/spool/cron" | 56 | //config: default "/var/spool/cron" |
@@ -74,6 +90,7 @@ | |||
74 | 90 | ||
75 | #define CRON_DIR CONFIG_FEATURE_CROND_DIR | 91 | #define CRON_DIR CONFIG_FEATURE_CROND_DIR |
76 | #define CRONTABS CONFIG_FEATURE_CROND_DIR "/crontabs" | 92 | #define CRONTABS CONFIG_FEATURE_CROND_DIR "/crontabs" |
93 | #define CRON_REBOOT CONFIG_PID_FILE_PATH "/crond.reboot" | ||
77 | #ifndef SENDMAIL | 94 | #ifndef SENDMAIL |
78 | # define SENDMAIL "sendmail" | 95 | # define SENDMAIL "sendmail" |
79 | #endif | 96 | #endif |
@@ -101,6 +118,8 @@ typedef struct CronLine { | |||
101 | struct CronLine *cl_next; | 118 | struct CronLine *cl_next; |
102 | char *cl_cmd; /* shell command */ | 119 | char *cl_cmd; /* shell command */ |
103 | pid_t cl_pid; /* >0:running, <0:needs to be started in this minute, 0:dormant */ | 120 | pid_t cl_pid; /* >0:running, <0:needs to be started in this minute, 0:dormant */ |
121 | #define START_ME_REBOOT -2 | ||
122 | #define START_ME_NORMAL -1 | ||
104 | #if ENABLE_FEATURE_CROND_CALL_SENDMAIL | 123 | #if ENABLE_FEATURE_CROND_CALL_SENDMAIL |
105 | int cl_empty_mail_size; /* size of mail header only, 0 if no mailfile */ | 124 | int cl_empty_mail_size; /* size of mail header only, 0 if no mailfile */ |
106 | char *cl_mailto; /* whom to mail results, may be NULL */ | 125 | char *cl_mailto; /* whom to mail results, may be NULL */ |
@@ -465,21 +484,85 @@ static void load_crontab(const char *fileName) | |||
465 | //line of the crontab's owner. HOME and SHELL may be overridden by settings | 484 | //line of the crontab's owner. HOME and SHELL may be overridden by settings |
466 | //in the crontab; LOGNAME may not. | 485 | //in the crontab; LOGNAME may not. |
467 | 486 | ||
487 | #if ENABLE_FEATURE_CROND_SPECIAL_TIMES | ||
488 | if (tokens[0][0] == '@') { | ||
489 | /* | ||
490 | * "@daily /a/script/to/run PARAM1 PARAM2..." | ||
491 | */ | ||
492 | typedef struct SpecialEntry { | ||
493 | const char *name; | ||
494 | const char tokens[8]; | ||
495 | } SpecialEntry; | ||
496 | static const SpecialEntry SpecAry[] = { | ||
497 | /* hour day month weekday */ | ||
498 | { "yearly", "0\0" "1\0" "1\0" "*" }, | ||
499 | { "annually", "0\0" "1\0" "1\0" "*" }, | ||
500 | { "monthly", "0\0" "1\0" "*\0" "*" }, | ||
501 | { "weekly", "0\0" "*\0" "*\0" "0" }, | ||
502 | { "daily", "0\0" "*\0" "*\0" "*" }, | ||
503 | { "midnight", "0\0" "*\0" "*\0" "*" }, | ||
504 | { "hourly", "*\0" "*\0" "*\0" "*" }, | ||
505 | { "reboot", "" }, | ||
506 | }; | ||
507 | const SpecialEntry *e = SpecAry; | ||
508 | |||
509 | if (n < 2) | ||
510 | continue; | ||
511 | for (;;) { | ||
512 | if (strcmp(e->name, tokens[0] + 1) == 0) { | ||
513 | /* | ||
514 | * tokens[1] is only the first word of command, | ||
515 | * can'r use it. | ||
516 | * find the entire command in unmodified string: | ||
517 | */ | ||
518 | tokens[5] = skip_whitespace( | ||
519 | skip_non_whitespace( | ||
520 | skip_whitespace(parser->data))); | ||
521 | if (e->tokens[0]) { | ||
522 | char *et = (char*)e->tokens; | ||
523 | /* minute is "0" for all specials */ | ||
524 | tokens[0] = (char*)"0"; | ||
525 | tokens[1] = et; | ||
526 | tokens[2] = et + 2; | ||
527 | tokens[3] = et + 4; | ||
528 | tokens[4] = et + 6; | ||
529 | } | ||
530 | goto got_it; | ||
531 | } | ||
532 | if (!e->tokens[0]) | ||
533 | break; | ||
534 | e++; | ||
535 | } | ||
536 | continue; /* bad line (unrecognized '@foo') */ | ||
537 | } | ||
538 | #endif | ||
468 | /* check if a minimum of tokens is specified */ | 539 | /* check if a minimum of tokens is specified */ |
469 | if (n < 6) | 540 | if (n < 6) |
470 | continue; | 541 | continue; |
542 | IF_FEATURE_CROND_SPECIAL_TIMES( | ||
543 | got_it: | ||
544 | ) | ||
471 | *pline = line = xzalloc(sizeof(*line)); | 545 | *pline = line = xzalloc(sizeof(*line)); |
472 | /* parse date ranges */ | 546 | #if ENABLE_FEATURE_CROND_SPECIAL_TIMES |
473 | ParseField(file->cf_username, line->cl_Mins, 60, 0, NULL, tokens[0]); | 547 | if (tokens[0][0] == '@') { /* "@reboot" line */ |
474 | ParseField(file->cf_username, line->cl_Hrs, 24, 0, NULL, tokens[1]); | 548 | file->cf_wants_starting = 1; |
475 | ParseField(file->cf_username, line->cl_Days, 32, 0, NULL, tokens[2]); | 549 | line->cl_pid = START_ME_REBOOT; /* wants to start */ |
476 | ParseField(file->cf_username, line->cl_Mons, 12, -1, MonAry, tokens[3]); | 550 | /* line->cl_Mins/Hrs/etc stay zero: never match any time */ |
477 | ParseField(file->cf_username, line->cl_Dow, 7, 0, DowAry, tokens[4]); | 551 | } else |
478 | /* | 552 | #endif |
479 | * fix days and dow - if one is not "*" and the other | 553 | { |
480 | * is "*", the other is set to 0, and vise-versa | 554 | /* parse date ranges */ |
481 | */ | 555 | ParseField(file->cf_username, line->cl_Mins, 60, 0, NULL, tokens[0]); |
482 | FixDayDow(line); | 556 | ParseField(file->cf_username, line->cl_Hrs, 24, 0, NULL, tokens[1]); |
557 | ParseField(file->cf_username, line->cl_Days, 32, 0, NULL, tokens[2]); | ||
558 | ParseField(file->cf_username, line->cl_Mons, 12, -1, MonAry, tokens[3]); | ||
559 | ParseField(file->cf_username, line->cl_Dow, 7, 0, DowAry, tokens[4]); | ||
560 | /* | ||
561 | * fix days and dow - if one is not "*" and the other | ||
562 | * is "*", the other is set to 0, and vise-versa | ||
563 | */ | ||
564 | FixDayDow(line); | ||
565 | } | ||
483 | #if ENABLE_FEATURE_CROND_CALL_SENDMAIL | 566 | #if ENABLE_FEATURE_CROND_CALL_SENDMAIL |
484 | /* copy mailto (can be NULL) */ | 567 | /* copy mailto (can be NULL) */ |
485 | line->cl_mailto = xstrdup(mailTo); | 568 | line->cl_mailto = xstrdup(mailTo); |
@@ -664,7 +747,7 @@ fork_job(const char *user, int mailFd, CronLine *line, bool run_sendmail) | |||
664 | return pid; | 747 | return pid; |
665 | } | 748 | } |
666 | 749 | ||
667 | static void start_one_job(const char *user, CronLine *line) | 750 | static pid_t start_one_job(const char *user, CronLine *line) |
668 | { | 751 | { |
669 | char mailFile[128]; | 752 | char mailFile[128]; |
670 | int mailFd = -1; | 753 | int mailFd = -1; |
@@ -698,6 +781,8 @@ static void start_one_job(const char *user, CronLine *line) | |||
698 | free(mailFile2); | 781 | free(mailFile2); |
699 | } | 782 | } |
700 | } | 783 | } |
784 | |||
785 | return line->cl_pid; | ||
701 | } | 786 | } |
702 | 787 | ||
703 | /* | 788 | /* |
@@ -748,7 +833,7 @@ static void process_finished_job(const char *user, CronLine *line) | |||
748 | 833 | ||
749 | #else /* !ENABLE_FEATURE_CROND_CALL_SENDMAIL */ | 834 | #else /* !ENABLE_FEATURE_CROND_CALL_SENDMAIL */ |
750 | 835 | ||
751 | static void start_one_job(const char *user, CronLine *line) | 836 | static pid_t start_one_job(const char *user, CronLine *line) |
752 | { | 837 | { |
753 | const char *shell; | 838 | const char *shell; |
754 | struct passwd *pas; | 839 | struct passwd *pas; |
@@ -782,6 +867,7 @@ static void start_one_job(const char *user, CronLine *line) | |||
782 | pid = 0; | 867 | pid = 0; |
783 | } | 868 | } |
784 | line->cl_pid = pid; | 869 | line->cl_pid = pid; |
870 | return pid; | ||
785 | } | 871 | } |
786 | 872 | ||
787 | #define process_finished_job(user, line) ((line)->cl_pid = 0) | 873 | #define process_finished_job(user, line) ((line)->cl_pid = 0) |
@@ -825,7 +911,7 @@ static void flag_starting_jobs(time_t t1, time_t t2) | |||
825 | log8("user %s: process already running: %s", | 911 | log8("user %s: process already running: %s", |
826 | file->cf_username, line->cl_cmd); | 912 | file->cf_username, line->cl_cmd); |
827 | } else if (line->cl_pid == 0) { | 913 | } else if (line->cl_pid == 0) { |
828 | line->cl_pid = -1; | 914 | line->cl_pid = START_ME_NORMAL; |
829 | file->cf_wants_starting = 1; | 915 | file->cf_wants_starting = 1; |
830 | } | 916 | } |
831 | } | 917 | } |
@@ -834,7 +920,20 @@ static void flag_starting_jobs(time_t t1, time_t t2) | |||
834 | } | 920 | } |
835 | } | 921 | } |
836 | 922 | ||
837 | static void start_jobs(void) | 923 | #if ENABLE_FEATURE_CROND_SPECIAL_TIMES |
924 | static int touch_reboot_file(void) | ||
925 | { | ||
926 | int fd = open(CRON_REBOOT, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, 0000); | ||
927 | if (fd >= 0) { | ||
928 | close(fd); | ||
929 | return 1; | ||
930 | } | ||
931 | /* File (presumably) exists - this is not the first run after reboot */ | ||
932 | return 0; | ||
933 | } | ||
934 | #endif | ||
935 | |||
936 | static void start_jobs(int wants_start) | ||
838 | { | 937 | { |
839 | CronFile *file; | 938 | CronFile *file; |
840 | CronLine *line; | 939 | CronLine *line; |
@@ -846,11 +945,10 @@ static void start_jobs(void) | |||
846 | file->cf_wants_starting = 0; | 945 | file->cf_wants_starting = 0; |
847 | for (line = file->cf_lines; line; line = line->cl_next) { | 946 | for (line = file->cf_lines; line; line = line->cl_next) { |
848 | pid_t pid; | 947 | pid_t pid; |
849 | if (line->cl_pid >= 0) | 948 | if (line->cl_pid != wants_start) |
850 | continue; | 949 | continue; |
851 | 950 | ||
852 | start_one_job(file->cf_username, line); | 951 | pid = start_one_job(file->cf_username, line); |
853 | pid = line->cl_pid; | ||
854 | log8("USER %s pid %3d cmd %s", | 952 | log8("USER %s pid %3d cmd %s", |
855 | file->cf_username, (int)pid, line->cl_cmd); | 953 | file->cf_username, (int)pid, line->cl_cmd); |
856 | if (pid < 0) { | 954 | if (pid < 0) { |
@@ -950,6 +1048,10 @@ int crond_main(int argc UNUSED_PARAM, char **argv) | |||
950 | log8("crond (busybox "BB_VER") started, log level %d", G.log_level); | 1048 | log8("crond (busybox "BB_VER") started, log level %d", G.log_level); |
951 | rescan_crontab_dir(); | 1049 | rescan_crontab_dir(); |
952 | write_pidfile(CONFIG_PID_FILE_PATH "/crond.pid"); | 1050 | write_pidfile(CONFIG_PID_FILE_PATH "/crond.pid"); |
1051 | #if ENABLE_FEATURE_CROND_SPECIAL_TIMES | ||
1052 | if (touch_reboot_file()) | ||
1053 | start_jobs(START_ME_REBOOT); /* start @reboot entries, if any */ | ||
1054 | #endif | ||
953 | 1055 | ||
954 | /* Main loop */ | 1056 | /* Main loop */ |
955 | t2 = time(NULL); | 1057 | t2 = time(NULL); |
@@ -1002,7 +1104,7 @@ int crond_main(int argc UNUSED_PARAM, char **argv) | |||
1002 | } else if (dt > 0) { | 1104 | } else if (dt > 0) { |
1003 | /* Usual case: time advances forward, as expected */ | 1105 | /* Usual case: time advances forward, as expected */ |
1004 | flag_starting_jobs(t1, t2); | 1106 | flag_starting_jobs(t1, t2); |
1005 | start_jobs(); | 1107 | start_jobs(START_ME_NORMAL); |
1006 | sleep_time = 60; | 1108 | sleep_time = 60; |
1007 | if (check_completions() > 0) { | 1109 | if (check_completions() > 0) { |
1008 | /* some jobs are still running */ | 1110 | /* some jobs are still running */ |
diff --git a/miscutils/makedevs.c b/miscutils/makedevs.c index 9e7ca340f..f436b08f8 100644 --- a/miscutils/makedevs.c +++ b/miscutils/makedevs.c | |||
@@ -208,17 +208,17 @@ int makedevs_main(int argc UNUSED_PARAM, char **argv) | |||
208 | unsigned count = 0; | 208 | unsigned count = 0; |
209 | unsigned increment = 0; | 209 | unsigned increment = 0; |
210 | unsigned start = 0; | 210 | unsigned start = 0; |
211 | char name[41]; | ||
212 | char user[41]; | 211 | char user[41]; |
213 | char group[41]; | 212 | char group[41]; |
214 | char *full_name = name; | 213 | char *full_name; |
214 | int name_len; | ||
215 | uid_t uid; | 215 | uid_t uid; |
216 | gid_t gid; | 216 | gid_t gid; |
217 | 217 | ||
218 | linenum = parser->lineno; | 218 | linenum = parser->lineno; |
219 | 219 | ||
220 | if ((2 > sscanf(line, "%40s %c %o %40s %40s %u %u %u %u %u", | 220 | if ((1 > sscanf(line, "%*s%n %c %o %40s %40s %u %u %u %u %u", |
221 | name, &type, &mode, user, group, | 221 | &name_len, &type, &mode, user, group, |
222 | &major, &minor, &start, &increment, &count)) | 222 | &major, &minor, &start, &increment, &count)) |
223 | || ((unsigned)(major | minor | start | count | increment) > 255) | 223 | || ((unsigned)(major | minor | start | count | increment) > 255) |
224 | ) { | 224 | ) { |
@@ -229,9 +229,11 @@ int makedevs_main(int argc UNUSED_PARAM, char **argv) | |||
229 | 229 | ||
230 | gid = (*group) ? get_ug_id(group, xgroup2gid) : getgid(); | 230 | gid = (*group) ? get_ug_id(group, xgroup2gid) : getgid(); |
231 | uid = (*user) ? get_ug_id(user, xuname2uid) : getuid(); | 231 | uid = (*user) ? get_ug_id(user, xuname2uid) : getuid(); |
232 | line[name_len] = '\0'; | ||
233 | full_name = line; | ||
232 | /* We are already in the right root dir, | 234 | /* We are already in the right root dir, |
233 | * so make absolute paths relative */ | 235 | * so make absolute paths relative */ |
234 | if ('/' == *full_name) | 236 | if ('/' == full_name[0]) |
235 | full_name++; | 237 | full_name++; |
236 | 238 | ||
237 | if (type == 'd') { | 239 | if (type == 'd') { |
@@ -260,9 +262,7 @@ int makedevs_main(int argc UNUSED_PARAM, char **argv) | |||
260 | if (chmod(full_name, mode) < 0) | 262 | if (chmod(full_name, mode) < 0) |
261 | goto chmod_fail; | 263 | goto chmod_fail; |
262 | } else { | 264 | } else { |
263 | dev_t rdev; | ||
264 | unsigned i; | 265 | unsigned i; |
265 | char *full_name_inc; | ||
266 | 266 | ||
267 | if (type == 'p') { | 267 | if (type == 'p') { |
268 | mode |= S_IFIFO; | 268 | mode |= S_IFIFO; |
@@ -276,26 +276,29 @@ int makedevs_main(int argc UNUSED_PARAM, char **argv) | |||
276 | continue; | 276 | continue; |
277 | } | 277 | } |
278 | 278 | ||
279 | full_name_inc = xmalloc(strlen(full_name) + sizeof(int)*3 + 2); | 279 | if (count != 0) |
280 | if (count) | ||
281 | count--; | 280 | count--; |
282 | for (i = start; i <= start + count; i++) { | 281 | for (i = 0; i <= count; i++) { |
283 | sprintf(full_name_inc, count ? "%s%u" : "%s", full_name, i); | 282 | dev_t rdev; |
284 | rdev = makedev(major, minor + (i - start) * increment); | 283 | char *nameN = full_name; |
285 | if (mknod(full_name_inc, mode, rdev) != 0 | 284 | if (count != 0) |
285 | nameN = xasprintf("%s%u", full_name, start + i); | ||
286 | rdev = makedev(major, minor + i * increment); | ||
287 | if (mknod(nameN, mode, rdev) != 0 | ||
286 | && errno != EEXIST | 288 | && errno != EEXIST |
287 | ) { | 289 | ) { |
288 | bb_perror_msg("line %d: can't create node %s", linenum, full_name_inc); | 290 | bb_perror_msg("line %d: can't create node %s", linenum, nameN); |
289 | ret = EXIT_FAILURE; | 291 | ret = EXIT_FAILURE; |
290 | } else if (chown(full_name_inc, uid, gid) < 0) { | 292 | } else if (chown(nameN, uid, gid) < 0) { |
291 | bb_perror_msg("line %d: can't chown %s", linenum, full_name_inc); | 293 | bb_perror_msg("line %d: can't chown %s", linenum, nameN); |
292 | ret = EXIT_FAILURE; | 294 | ret = EXIT_FAILURE; |
293 | } else if (chmod(full_name_inc, mode) < 0) { | 295 | } else if (chmod(nameN, mode) < 0) { |
294 | bb_perror_msg("line %d: can't chmod %s", linenum, full_name_inc); | 296 | bb_perror_msg("line %d: can't chmod %s", linenum, nameN); |
295 | ret = EXIT_FAILURE; | 297 | ret = EXIT_FAILURE; |
296 | } | 298 | } |
299 | if (count != 0) | ||
300 | free(nameN); | ||
297 | } | 301 | } |
298 | free(full_name_inc); | ||
299 | } | 302 | } |
300 | } | 303 | } |
301 | if (ENABLE_FEATURE_CLEAN_UP) | 304 | if (ENABLE_FEATURE_CLEAN_UP) |
diff --git a/miscutils/ttysize.c b/miscutils/ttysize.c index 135ce8535..cba65b148 100644 --- a/miscutils/ttysize.c +++ b/miscutils/ttysize.c | |||
@@ -25,7 +25,7 @@ | |||
25 | //usage:#define ttysize_trivial_usage | 25 | //usage:#define ttysize_trivial_usage |
26 | //usage: "[w] [h]" | 26 | //usage: "[w] [h]" |
27 | //usage:#define ttysize_full_usage "\n\n" | 27 | //usage:#define ttysize_full_usage "\n\n" |
28 | //usage: "Print dimension(s) of stdin's terminal, on error return 80x25" | 28 | //usage: "Print dimensions of stdin tty, or 80x24" |
29 | 29 | ||
30 | #include "libbb.h" | 30 | #include "libbb.h" |
31 | 31 | ||
@@ -37,7 +37,10 @@ int ttysize_main(int argc UNUSED_PARAM, char **argv) | |||
37 | 37 | ||
38 | w = 80; | 38 | w = 80; |
39 | h = 24; | 39 | h = 24; |
40 | if (!ioctl(0, TIOCGWINSZ, &wsz)) { | 40 | if (ioctl(0, TIOCGWINSZ, &wsz) == 0 |
41 | || ioctl(1, TIOCGWINSZ, &wsz) == 0 | ||
42 | || ioctl(2, TIOCGWINSZ, &wsz) == 0 | ||
43 | ) { | ||
41 | w = wsz.ws_col; | 44 | w = wsz.ws_col; |
42 | h = wsz.ws_row; | 45 | h = wsz.ws_row; |
43 | } | 46 | } |
diff --git a/miscutils/watchdog.c b/miscutils/watchdog.c index 07ae64e52..d379a97f4 100644 --- a/miscutils/watchdog.c +++ b/miscutils/watchdog.c | |||
@@ -35,27 +35,60 @@ | |||
35 | //usage: "\nUse 500ms to specify period in milliseconds" | 35 | //usage: "\nUse 500ms to specify period in milliseconds" |
36 | 36 | ||
37 | #include "libbb.h" | 37 | #include "libbb.h" |
38 | #include "linux/types.h" /* for __u32 */ | 38 | #include <linux/types.h> /* for __u32 */ |
39 | #include "linux/watchdog.h" | 39 | #include <linux/watchdog.h> |
40 | |||
41 | #ifndef WDIOC_SETOPTIONS | ||
42 | # define WDIOC_SETOPTIONS 0x5704 | ||
43 | #endif | ||
44 | #ifndef WDIOC_SETTIMEOUT | ||
45 | # define WDIOC_SETTIMEOUT 0x5706 | ||
46 | #endif | ||
47 | #ifndef WDIOC_GETTIMEOUT | ||
48 | # define WDIOC_GETTIMEOUT 0x5707 | ||
49 | #endif | ||
50 | #ifndef WDIOS_ENABLECARD | ||
51 | # define WDIOS_ENABLECARD 2 | ||
52 | #endif | ||
40 | 53 | ||
41 | #define OPT_FOREGROUND (1 << 0) | 54 | #define OPT_FOREGROUND (1 << 0) |
42 | #define OPT_STIMER (1 << 1) | 55 | #define OPT_STIMER (1 << 1) |
43 | #define OPT_HTIMER (1 << 2) | 56 | #define OPT_HTIMER (1 << 2) |
44 | 57 | ||
45 | static void watchdog_shutdown(int sig UNUSED_PARAM) | 58 | static void shutdown_watchdog(void) |
46 | { | 59 | { |
47 | static const char V = 'V'; | 60 | static const char V = 'V'; |
61 | write(3, &V, 1); /* Magic, see watchdog-api.txt in kernel */ | ||
62 | close(3); | ||
63 | } | ||
48 | 64 | ||
65 | static void shutdown_on_signal(int sig UNUSED_PARAM) | ||
66 | { | ||
49 | remove_pidfile(CONFIG_PID_FILE_PATH "/watchdog.pid"); | 67 | remove_pidfile(CONFIG_PID_FILE_PATH "/watchdog.pid"); |
50 | write(3, &V, 1); /* Magic, see watchdog-api.txt in kernel */ | 68 | shutdown_watchdog(); |
51 | if (ENABLE_FEATURE_CLEAN_UP) | ||
52 | close(3); | ||
53 | _exit(EXIT_SUCCESS); | 69 | _exit(EXIT_SUCCESS); |
54 | } | 70 | } |
55 | 71 | ||
72 | static void watchdog_open(const char* device) | ||
73 | { | ||
74 | /* Use known fd # - avoid needing global 'int fd' */ | ||
75 | xmove_fd(xopen(device, O_WRONLY), 3); | ||
76 | |||
77 | /* If the watchdog driver can do something other than cause a reboot | ||
78 | * on a timeout, then it's possible this program may be starting from | ||
79 | * a state when the watchdog hadn't been previously stopped with | ||
80 | * the magic write followed by a close. In this case the driver may | ||
81 | * not start properly, so always do the proper stop first just in case. | ||
82 | */ | ||
83 | shutdown_watchdog(); | ||
84 | |||
85 | xmove_fd(xopen(device, O_WRONLY), 3); | ||
86 | } | ||
87 | |||
56 | int watchdog_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 88 | int watchdog_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
57 | int watchdog_main(int argc, char **argv) | 89 | int watchdog_main(int argc UNUSED_PARAM, char **argv) |
58 | { | 90 | { |
91 | static const int enable = WDIOS_ENABLECARD; | ||
59 | static const struct suffix_mult suffixes[] = { | 92 | static const struct suffix_mult suffixes[] = { |
60 | { "ms", 1 }, | 93 | { "ms", 1 }, |
61 | { "", 1000 }, | 94 | { "", 1000 }, |
@@ -80,31 +113,22 @@ int watchdog_main(int argc, char **argv) | |||
80 | if (!(opts & OPT_FOREGROUND)) | 113 | if (!(opts & OPT_FOREGROUND)) |
81 | bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv); | 114 | bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv); |
82 | 115 | ||
116 | /* maybe bb_logenv_override(); here for LOGGING=syslog to work? */ | ||
117 | |||
83 | if (opts & OPT_HTIMER) | 118 | if (opts & OPT_HTIMER) |
84 | htimer_duration = xatou_sfx(ht_arg, suffixes); | 119 | htimer_duration = xatou_sfx(ht_arg, suffixes); |
85 | stimer_duration = htimer_duration / 2; | 120 | stimer_duration = htimer_duration / 2; |
86 | if (opts & OPT_STIMER) | 121 | if (opts & OPT_STIMER) |
87 | stimer_duration = xatou_sfx(st_arg, suffixes); | 122 | stimer_duration = xatou_sfx(st_arg, suffixes); |
88 | 123 | ||
89 | bb_signals(BB_FATAL_SIGS, watchdog_shutdown); | 124 | bb_signals(BB_FATAL_SIGS, shutdown_on_signal); |
90 | 125 | ||
91 | /* Use known fd # - avoid needing global 'int fd' */ | 126 | watchdog_open(argv[optind]); |
92 | xmove_fd(xopen(argv[argc - 1], O_WRONLY), 3); | ||
93 | 127 | ||
94 | /* WDIOC_SETTIMEOUT takes seconds, not milliseconds */ | 128 | /* WDIOC_SETTIMEOUT takes seconds, not milliseconds */ |
95 | htimer_duration = htimer_duration / 1000; | 129 | htimer_duration = htimer_duration / 1000; |
96 | #ifndef WDIOC_SETTIMEOUT | 130 | ioctl_or_warn(3, WDIOC_SETOPTIONS, (void*) &enable); |
97 | # error WDIOC_SETTIMEOUT is not defined, cannot compile watchdog applet | ||
98 | #else | ||
99 | # if defined WDIOC_SETOPTIONS && defined WDIOS_ENABLECARD | ||
100 | { | ||
101 | static const int enable = WDIOS_ENABLECARD; | ||
102 | ioctl_or_warn(3, WDIOC_SETOPTIONS, (void*) &enable); | ||
103 | } | ||
104 | # endif | ||
105 | ioctl_or_warn(3, WDIOC_SETTIMEOUT, &htimer_duration); | 131 | ioctl_or_warn(3, WDIOC_SETTIMEOUT, &htimer_duration); |
106 | #endif | ||
107 | |||
108 | #if 0 | 132 | #if 0 |
109 | ioctl_or_warn(3, WDIOC_GETTIMEOUT, &htimer_duration); | 133 | ioctl_or_warn(3, WDIOC_GETTIMEOUT, &htimer_duration); |
110 | printf("watchdog: SW timer is %dms, HW timer is %ds\n", | 134 | printf("watchdog: SW timer is %dms, HW timer is %ds\n", |