summaryrefslogtreecommitdiffstats
path: root/source/a/dcron
diff options
context:
space:
mode:
Diffstat (limited to 'source/a/dcron')
-rw-r--r--source/a/dcron/crond.default10
-rwxr-xr-xsource/a/dcron/dcron.SlackBuild56
-rw-r--r--source/a/dcron/defs.h._DEFAULT_SOURCE.diff11
-rw-r--r--source/a/dcron/doinst.sh35
-rw-r--r--source/a/dcron/patches/0002-README-var-spool-cron-crontabs-root.patch26
-rw-r--r--source/a/dcron/patches/0003-CHANGELOG-tweak.patch34
-rw-r--r--source/a/dcron/patches/0006-Fixed-a-bug-whereby-syncs-killed-all-waiting-jobs.patch35
-rw-r--r--source/a/dcron/patches/0007-Update-main.c.patch (renamed from source/a/dcron/dcron.update.during.long.running.jobs.diff)10
-rw-r--r--source/a/dcron/patches/0008-Fix-3-every-Nth-day-of-week-syntax-not-working.patch538
-rw-r--r--source/a/dcron/patches/0009-Updated-manpage.patch45
-rw-r--r--source/a/dcron/patches/crontab.c.O_EXCL.diff (renamed from source/a/dcron/crontab.c.O_EXCL.diff)0
-rw-r--r--source/a/dcron/patches/defs.h.TMPDIR.diff (renamed from source/a/dcron/defs.h.TMPDIR.diff)2
-rw-r--r--source/a/dcron/rc.crond40
13 files changed, 810 insertions, 32 deletions
diff --git a/source/a/dcron/crond.default b/source/a/dcron/crond.default
new file mode 100644
index 000000000..032030060
--- /dev/null
+++ b/source/a/dcron/crond.default
@@ -0,0 +1,10 @@
+# Default log level is "notice". If you want cron to actually log activity
+# to /var/log/cron, then change "-l notice" to "-l info" to increase the
+# logging level.
+#
+# Valid log levels are:
+# alert, crit, debug, emerg, err, error (deprecated synonym for err),
+# info, notice, panic (deprecated synonym for emerg), warning,
+# warn (deprecated synonym for warning).
+
+CROND_OPTS="-l notice"
diff --git a/source/a/dcron/dcron.SlackBuild b/source/a/dcron/dcron.SlackBuild
index 5c32ace8e..abd76e219 100755
--- a/source/a/dcron/dcron.SlackBuild
+++ b/source/a/dcron/dcron.SlackBuild
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
# Copyright 2009, 2010, 2012, 2016, 2018 Patrick J. Volkerding, Sebeka, MN, USA
# All rights reserved.
@@ -24,7 +24,7 @@ cd $(dirname $0) ; CWD=$(pwd)
PKGNAM=dcron
VERSION=${VERSION:-$(echo dcron-*.tar.?z* | rev | cut -f 3- -d . | cut -f 1 -d - | rev)}
-BUILD=${BUILD:-6}
+BUILD=${BUILD:-7}
# Automatically determine the architecture we're building on:
if [ -z "$ARCH" ]; then
@@ -44,6 +44,7 @@ if [ ! -z "${PRINT_PACKAGE_NAME}" ]; then
exit 0
fi
+CWD=$(pwd)
TMP=${TMP:-/tmp}
PKG=$TMP/package-dcron
@@ -73,30 +74,47 @@ find . \
\( -perm 666 -o -perm 664 -o -perm 600 -o -perm 444 -o -perm 440 -o -perm 400 \) \
-exec chmod 644 {} \;
-# Define TMPDIR as /var/spool/cron instead of /tmp
-zcat $CWD/defs.h.TMPDIR.diff.gz | patch -p1 --verbose || exit 1
+# Apply patches from git:
+zcat $CWD/patches/0002-README-var-spool-cron-crontabs-root.patch.gz | patch -p1 --verbose || exit 1
+zcat $CWD/patches/0003-CHANGELOG-tweak.patch.gz | patch -p1 --verbose || exit 1
+zcat $CWD/patches/0006-Fixed-a-bug-whereby-syncs-killed-all-waiting-jobs.patch.gz | patch -p1 --verbose || exit 1
+zcat $CWD/patches/0007-Update-main.c.patch.gz | patch -p1 --verbose || exit 1
+zcat $CWD/patches/0008-Fix-3-every-Nth-day-of-week-syntax-not-working.patch.gz | patch -p1 --verbose || exit 1
+zcat $CWD/patches/0009-Updated-manpage.patch.gz | patch -p1 --verbose || exit 1
+
+# Define TMPDIR as /run/cron instead of /tmp:
+# This eliminates possibility of stale $TMPDIR/cron.??????/ dirs as
+# they won't survive a reboot when they're in a subdir of /run
+zcat $CWD/patches/defs.h.TMPDIR.diff.gz | patch -p1 --verbose || exit 1
# Fix problem where user creates /var/spool/cron/crontabs/<user>.new
# using 'crontab -', exits with control-c, and then crontab refuses to
-# overwrite the junk file. It would be better if dcron would wipe
+# overwrite the junk file. It would be better if dcron would wipe
# the junk file in the event it were not closed correctly, but oh well.
-zcat $CWD/crontab.c.O_EXCL.diff.gz | patch -p1 --verbose || exit 1
+zcat $CWD/patches/crontab.c.O_EXCL.diff.gz | patch -p1 --verbose || exit 1
-# Running jobs should not block cron.update:
-zcat $CWD/dcron.update.during.long.running.jobs.diff.gz | patch -p1 --verbose || exit 1
+CFLAGS+="$SLKCFLAGS" make \
+ PREFIX=/usr \
+ BINDIR=/usr/bin \
+ SBINDIR=/usr/sbin \
+ MANDIR=/usr/man \
+ CRONTAB_GROUP=root \
+ || exit 1
-# Change _BSD_SOURCE to _DEFAULT_SOURCE for recent glibc:
-zcat $CWD/defs.h._DEFAULT_SOURCE.diff.gz | patch -p1 --verbose || exit 1
+# This works now, but predictability is a good thing...
+#make install DESTDIR=$PKG
-CFLAGS+="$SLKCFLAGS" make || exit 1
strip --strip-unneeded crond crontab
-mkdir -p $PKG/usr/{bin,sbin}
+mkdir -p $PKG/usr/sbin
cat crond > $PKG/usr/sbin/crond
-cat crontab > $PKG/usr/bin/crontab
-zcat $CWD/run-parts.gz > $PKG/usr/bin/run-parts
chmod 0755 $PKG/usr/sbin/crond
+
+mkdir -p $PKG/usr/bin
+cat crontab > $PKG/usr/bin/crontab
chmod 4711 $PKG/usr/bin/crontab
+
+zcat $CWD/run-parts.gz > $PKG/usr/bin/run-parts
chmod 0755 $PKG/usr/bin/run-parts
mkdir -p $PKG/usr/man/man{1,8}
@@ -104,6 +122,15 @@ cat crontab.1 | gzip -9c > $PKG/usr/man/man1/crontab.1.gz
cat crond.8 | gzip -9c > $PKG/usr/man/man8/crond.8.gz
cat $CWD/run-parts.8.gz > $PKG/usr/man/man8/run-parts.8.gz
+# Add the init script:
+mkdir -p $PKG/etc/rc.d
+cat $CWD/rc.crond > $PKG/etc/rc.d/rc.crond.new
+chmod 755 $PKG/etc/rc.d/rc.crond.new
+
+# Add the default file:
+mkdir -p $PKG/etc/default
+cat $CWD/crond.default > $PKG/etc/default/crond.new
+
# Create some other stuff we need
mkdir -p $PKG/etc/cron.{hourly,daily,weekly,monthly}
mkdir -p $PKG/var/spool/cron/crontabs
@@ -112,6 +139,7 @@ chmod 0751 $PKG/var/spool/cron
chmod 0750 $PKG/var/spool/cron/crontabs $PKG/var/spool/cron/cronstamps
zcat $CWD/crontab.root > $PKG/var/spool/cron/crontabs/root.new
chmod 0600 $PKG/var/spool/cron/crontabs/root.new
+
# dcron will whine about "unable to scan" this directory, so we'll create it
mkdir -p $PKG/etc/cron.d
diff --git a/source/a/dcron/defs.h._DEFAULT_SOURCE.diff b/source/a/dcron/defs.h._DEFAULT_SOURCE.diff
deleted file mode 100644
index 8d17b33a8..000000000
--- a/source/a/dcron/defs.h._DEFAULT_SOURCE.diff
+++ /dev/null
@@ -1,11 +0,0 @@
---- ./defs.h.orig 2016-05-10 12:56:47.127582837 -0500
-+++ ./defs.h 2016-05-10 12:59:31.059577597 -0500
-@@ -17,7 +17,7 @@
- */
-
- #define _XOPEN_SOURCE 1
--#define _BSD_SOURCE 1
-+#define _DEFAULT_SOURCE 1
-
- #include <sys/types.h>
- #include <sys/stat.h>
diff --git a/source/a/dcron/doinst.sh b/source/a/dcron/doinst.sh
index ce8dc7f3b..0d5f1ee87 100644
--- a/source/a/dcron/doinst.sh
+++ b/source/a/dcron/doinst.sh
@@ -1,5 +1,30 @@
-if [ ! -r var/spool/cron/crontabs/root ]; then
- mv var/spool/cron/crontabs/root.new var/spool/cron/crontabs/root
-else
- rm -f var/spool/cron/crontabs/root.new
-fi
+config() {
+ for infile in $1; do
+ NEW="$infile"
+ OLD="$(dirname $NEW)/$(basename $NEW .new)"
+ # If there's no config file by that name, mv it over:
+ if [ ! -r $OLD ]; then
+ mv $NEW $OLD
+ elif [ "$(cat $OLD | md5sum)" = "$(cat $NEW | md5sum)" ]; then
+ # toss the redundant copy
+ rm $NEW
+ fi
+ # Otherwise, we leave the .new copy for the admin to consider...
+ done
+}
+
+preserve_perms() {
+ NEW="$1"
+ OLD="$(dirname $NEW)/$(basename $NEW .new)"
+ if [ -e $OLD ]; then
+ cp -a $OLD ${NEW}.incoming
+ cat $NEW > ${NEW}.incoming
+ mv ${NEW}.incoming $NEW
+ fi
+ config $NEW
+}
+
+preserve_perms etc/rc.d/rc.crond.new
+config etc/default/crond.new
+config var/spool/cron/crontabs/root.new
+rm -f var/spool/cron/crontabs/root.new
diff --git a/source/a/dcron/patches/0002-README-var-spool-cron-crontabs-root.patch b/source/a/dcron/patches/0002-README-var-spool-cron-crontabs-root.patch
new file mode 100644
index 000000000..57b8966da
--- /dev/null
+++ b/source/a/dcron/patches/0002-README-var-spool-cron-crontabs-root.patch
@@ -0,0 +1,26 @@
+From 500f3d402a94c6950946515d76ebd72872a6d0e2 Mon Sep 17 00:00:00 2001
+From: Jim Pryor <profjim@jimpryor.net>
+Date: Sun, 1 May 2011 18:56:17 -0400
+Subject: [PATCH 2/9] README: /var/spool/cron/crontabs/root
+
+Signed-off-by: Jim Pryor <profjim@jimpryor.net>
+---
+ README | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/README b/README
+index de02958..e33b1aa 100644
+--- a/README
++++ b/README
+@@ -115,7 +115,7 @@ are normally in /var/spool/cron/cronstamps. These directories normally have perm
+
+ Here is the superuser's crontab, created using `sudo crontab -e`:
+
+- -rw------- 0 root root 513 Jan 6 18:58 /var/spool/cron/root
++ -rw------- 0 root root 513 Jan 6 18:58 /var/spool/cron/crontabs/root
+
+ TESTING
+ -------
+--
+2.13.2
+
diff --git a/source/a/dcron/patches/0003-CHANGELOG-tweak.patch b/source/a/dcron/patches/0003-CHANGELOG-tweak.patch
new file mode 100644
index 000000000..56f3c750e
--- /dev/null
+++ b/source/a/dcron/patches/0003-CHANGELOG-tweak.patch
@@ -0,0 +1,34 @@
+From 2e3717c48ead5a962e2c29bc818672fff36f73f6 Mon Sep 17 00:00:00 2001
+From: Jim Pryor <profjim@jimpryor.net>
+Date: Sun, 1 May 2011 19:21:21 -0400
+Subject: [PATCH 3/9] CHANGELOG tweak
+
+Signed-off-by: Jim Pryor <profjim@jimpryor.net>
+---
+ CHANGELOG | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index a1ea4a7..0710c3b 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -19,12 +19,12 @@ git
+
+ * Documentation and error message updates.
+
+-v4.5 30-Apr-2011
++v4.5 1-May-2011
+ * Some cron jobs were running multiple times. Now we make sure not to
+ ArmJobs that are already running; and not to resynchronize while jobs are
+- running; and to poll the DST setting. (Fixes Arch FS#18681; thanks to Paul
+- Gideon Dann for identifying the second issue; and Tilman Sauerbeck for
+- identifying the third.)
++ running; and to poll the DST setting. (Fixes Arch FS#18681; thanks to Vincent
++ Cappe and Paul Gideon Dann for identifying the second issue; and Tilman
++ Sauerbeck for identifying the third.)
+
+ * @monthly was wrongly being parsed the same as @yearly (fixes Arch
+ FS#19123). Thanks to Peter Johnson, Paul Gideon Dann, and Tilman Sauerbeck.
+--
+2.13.2
+
diff --git a/source/a/dcron/patches/0006-Fixed-a-bug-whereby-syncs-killed-all-waiting-jobs.patch b/source/a/dcron/patches/0006-Fixed-a-bug-whereby-syncs-killed-all-waiting-jobs.patch
new file mode 100644
index 000000000..090e2e5f5
--- /dev/null
+++ b/source/a/dcron/patches/0006-Fixed-a-bug-whereby-syncs-killed-all-waiting-jobs.patch
@@ -0,0 +1,35 @@
+From 65d2649a7c8b72561eefcec239f97e7fd386114e Mon Sep 17 00:00:00 2001
+From: Corey Theiss <corey.theiss@maclaren.com>
+Date: Mon, 24 Mar 2014 16:25:31 -0400
+Subject: [PATCH 6/9] Fixed a bug whereby syncs killed all waiting jobs.
+
+---
+ database.c | 11 ++++++++++-
+ 1 file changed, 10 insertions(+), 1 deletion(-)
+
+diff --git a/database.c b/database.c
+index dd971ce..02c5c92 100644
+--- a/database.c
++++ b/database.c
+@@ -1232,8 +1232,17 @@ CheckJobs(void)
+ }
+ }
+ }
++ nStillRunning += file->cf_Running;
++ }
++ /* For the purposes of this check, increase the "still running" counter if a file has lines that are waiting */
++ if (file->cf_Running == 0) {
++ for (line = file->cf_LineBase; line; line = line->cl_Next) {
++ if (line->cl_Pid == -2) {
++ nStillRunning += 1;
++ break;
++ }
++ }
+ }
+- nStillRunning += file->cf_Running;
+ }
+ return(nStillRunning);
+ }
+--
+2.13.2
+
diff --git a/source/a/dcron/dcron.update.during.long.running.jobs.diff b/source/a/dcron/patches/0007-Update-main.c.patch
index cd1297c73..d120f37c0 100644
--- a/source/a/dcron/dcron.update.during.long.running.jobs.diff
+++ b/source/a/dcron/patches/0007-Update-main.c.patch
@@ -1,6 +1,12 @@
- Update main.c
+From abf8c4bf53a84ef3de530519a3bbb6b599595f2c Mon Sep 17 00:00:00 2001
+From: robdewit <rdewit@wise-guys.nl>
+Date: Tue, 31 Mar 2015 14:24:15 +0200
+Subject: [PATCH 7/9] Update main.c
Removed bug where cron.update is not picked up while jobs are still running. (We have long running cronjobs and experienced long overdue cron.update files)
+---
+ main.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/main.c b/main.c
index 595f07a..0eba280 100644
@@ -16,4 +22,6 @@ index 595f07a..0eba280 100644
CheckUpdates(CDir, NULL, t1, t2);
CheckUpdates(SCDir, "root", t1, t2);
}
+--
+2.13.2
diff --git a/source/a/dcron/patches/0008-Fix-3-every-Nth-day-of-week-syntax-not-working.patch b/source/a/dcron/patches/0008-Fix-3-every-Nth-day-of-week-syntax-not-working.patch
new file mode 100644
index 000000000..e50158f0f
--- /dev/null
+++ b/source/a/dcron/patches/0008-Fix-3-every-Nth-day-of-week-syntax-not-working.patch
@@ -0,0 +1,538 @@
+From f048a83da348c1d62204fcbdf407b7abf33e3db0 Mon Sep 17 00:00:00 2001
+From: Erik on RPi <ewfalor@gmail.com>
+Date: Tue, 17 Nov 2015 11:28:42 -0700
+Subject: [PATCH 8/9] Fix #3 '"every Nth [day of week]" syntax not working'
+
+---
+ database.c | 237 ++++++++++++++++++++++++++++++++++++++++++-------------------
+ defs.h | 24 ++++---
+ 2 files changed, 180 insertions(+), 81 deletions(-)
+
+diff --git a/database.c b/database.c
+index 02c5c92..c0cdc11 100644
+--- a/database.c
++++ b/database.c
+@@ -9,6 +9,14 @@
+
+ #include "defs.h"
+
++#define FIRST_DOW (1 << 0)
++#define SECOND_DOW (1 << 1)
++#define THIRD_DOW (1 << 2)
++#define FOURTH_DOW (1 << 3)
++#define FIFTH_DOW (1 << 4)
++#define LAST_DOW (1 << 5)
++#define ALL_DOW (FIRST_DOW|SECOND_DOW|THIRD_DOW|FOURTH_DOW|FIFTH_DOW|LAST_DOW)
++
+ Prototype void CheckUpdates(const char *dpath, const char *user_override, time_t t1, time_t t2);
+ Prototype void SynchronizeDir(const char *dpath, const char *user_override, int initial_scan);
+ Prototype void ReadTimestamps(const char *user);
+@@ -21,8 +29,10 @@ Prototype int CheckJobs(void);
+ void SynchronizeFile(const char *dpath, const char *fname, const char *uname);
+ void DeleteFile(CronFile **pfile);
+ char *ParseInterval(int *interval, char *ptr);
+-char *ParseField(char *userName, char *ary, int modvalue, int off, int onvalue, const char **names, char *ptr);
++char *ParseField(char *userName, char *ary, int modvalue, int offset, int onvalue, const char **names, char *ptr);
+ void FixDayDow(CronLine *line);
++void PrintLine(CronLine *line);
++void PrintFile(CronFile *file, char* loc, char* fname, int line);
+
+ CronFile *FileBase = NULL;
+
+@@ -454,15 +464,15 @@ SynchronizeFile(const char *dpath, const char *fileName, const char *userName)
+ * parse date ranges
+ */
+
+- ptr = ParseField(file->cf_UserName, line.cl_Mins, 60, 0, 1,
++ ptr = ParseField(file->cf_UserName, line.cl_Mins, FIELD_MINUTES, 0, 1,
+ NULL, ptr);
+- ptr = ParseField(file->cf_UserName, line.cl_Hrs, 24, 0, 1,
++ ptr = ParseField(file->cf_UserName, line.cl_Hrs, FIELD_HOURS, 0, 1,
+ NULL, ptr);
+- ptr = ParseField(file->cf_UserName, line.cl_Days, 32, 0, 1,
++ ptr = ParseField(file->cf_UserName, line.cl_Days, FIELD_M_DAYS, 0, 1,
+ NULL, ptr);
+- ptr = ParseField(file->cf_UserName, line.cl_Mons, 12, -1, 1,
++ ptr = ParseField(file->cf_UserName, line.cl_Mons, FIELD_MONTHS, -1, 1,
+ MonAry, ptr);
+- ptr = ParseField(file->cf_UserName, line.cl_Dow, 7, 0, 31,
++ ptr = ParseField(file->cf_UserName, line.cl_Dow, FIELD_W_DAYS, 0, ALL_DOW,
+ DowAry, ptr);
+ /*
+ * check failure
+@@ -634,12 +644,12 @@ SynchronizeFile(const char *dpath, const char *fileName, const char *userName)
+
+ if (line.cl_JobName) {
+ if (DebugOpt)
+- printlogf(LOG_DEBUG, " Command %s Job %s\n", line.cl_Shell, line.cl_JobName);
++ printlogf(LOG_DEBUG, " Command %s Job %s\n\n", line.cl_Shell, line.cl_JobName);
+ } else {
+ /* when cl_JobName is NULL, we point cl_Description to cl_Shell */
+ line.cl_Description = line.cl_Shell;
+ if (DebugOpt)
+- printlogf(LOG_DEBUG, " Command %s\n", line.cl_Shell);
++ printlogf(LOG_DEBUG, " Command %s\n\n", line.cl_Shell);
+ }
+
+ *pline = calloc(1, sizeof(CronLine));
+@@ -691,7 +701,7 @@ ParseInterval(int *interval, char *ptr)
+ }
+
+ char *
+-ParseField(char *user, char *ary, int modvalue, int off, int onvalue, const char **names, char *ptr)
++ParseField(char *user, char *ary, int modvalue, int offset, int onvalue, const char **names, char *ptr)
+ {
+ char *base = ptr;
+ int n1 = -1;
+@@ -714,9 +724,9 @@ ParseField(char *user, char *ary, int modvalue, int off, int onvalue, const char
+ ++ptr;
+ } else if (*ptr >= '0' && *ptr <= '9') {
+ if (n1 < 0)
+- n1 = strtol(ptr, &ptr, 10) + off;
++ n1 = strtol(ptr, &ptr, 10) + offset;
+ else
+- n2 = strtol(ptr, &ptr, 10) + off;
++ n2 = strtol(ptr, &ptr, 10) + offset;
+ skip = 1;
+ } else if (names) {
+ int i;
+@@ -805,7 +815,7 @@ ParseField(char *user, char *ary, int modvalue, int off, int onvalue, const char
+ int i;
+
+ for (i = 0; i < modvalue; ++i)
+- if (modvalue == 7)
++ if (modvalue == FIELD_W_DAYS)
+ printlogf(LOG_DEBUG, "%2x ", ary[i]);
+ else
+ printlogf(LOG_DEBUG, "%d", ary[i]);
+@@ -815,50 +825,66 @@ ParseField(char *user, char *ary, int modvalue, int off, int onvalue, const char
+ return(ptr);
+ }
+
++/* Reconcile Days of Month with Days of Week.
++ * There are four cases to cover:
++ * 1) DoM and DoW are both specified as *; the task may run on any day
++ * 2) DoM is * and DoW is specific; the task runs weekly on the specified DoW(s)
++ * 3) DoM is specific and DoW is *; the task runs on the specified DoM, regardless
++ * of which day of the week they fall
++ * 4) DoM is in the range [1..5] and DoW is specific; the task runs on the Nth
++ * specified DoW. DoM > 5 means the last such DoW in that month
++ */
+ void
+ FixDayDow(CronLine *line)
+ {
+- unsigned short i,j;
+- short weekUsed = 0;
+- short daysUsed = 0;
++ unsigned short i;
++ short DowStar = 1;
++ short DomStar = 1;
++ char mask = 0;
+
+ for (i = 0; i < arysize(line->cl_Dow); ++i) {
+ if (line->cl_Dow[i] == 0) {
+- weekUsed = 1;
++ /* '*' was NOT specified in the DoW field on this CronLine */
++ DowStar = 0;
+ break;
+ }
+ }
++
+ for (i = 0; i < arysize(line->cl_Days); ++i) {
+ if (line->cl_Days[i] == 0) {
+- if (weekUsed) {
+- if (!daysUsed) {
+- daysUsed = 1;
+- /* change from "every Mon" to "ith Mon"
+- * 6th,7th... Dow are treated as 1st,2nd... */
+- for (j = 0; j < arysize(line->cl_Dow); ++j) {
+- line->cl_Dow[j] &= 1 << (i-1)%5;
+- }
+- } else {
+- /* change from "nth Mon" to "nth or ith Mon" */
+- for (j = 0; j < arysize(line->cl_Dow); ++j) {
+- if (line->cl_Dow[j])
+- line->cl_Dow[j] |= 1 << (i-1)%5;
+- }
+- }
+- /* continue cycling through cl_Days */
+- }
+- else {
+- daysUsed = 1;
+- break;
+- }
++ /* '*' was NOT specified in the Date field on this CronLine */
++ DomStar = 0;
++ break;
+ }
+ }
+- if (weekUsed) {
+- memset(line->cl_Days, 0, sizeof(line->cl_Days));
++
++ /* When cases 1, 2 or 3 there is nothing left to do */
++ if (DowStar || DomStar)
++ return;
++
++ /* Set individual bits within the DoW mask... */
++ for (i = 0; i < arysize(line->cl_Days); ++i) {
++ if (line->cl_Days[i]) {
++ if (i < 6)
++ mask |= 1 << (i - 1);
++ else
++ mask |= LAST_DOW;
++ }
+ }
+- if (daysUsed && !weekUsed) {
+- memset(line->cl_Dow, 0, sizeof(line->cl_Dow));
++
++ /* and apply the mask to each DoW element */
++ for (i = 0; i < arysize(line->cl_Dow); ++i) {
++ if (line->cl_Dow[i])
++ line->cl_Dow[i] = mask;
++ else
++ line->cl_Dow[i] = 0;
+ }
++
++ /* case 4 relies on the DoW value to guard the date instead of using the
++ * cl_Days field for this purpose; so we must set each element of cl_Days
++ * to 1 to allow the DoW bitmask test to be made
++ */
++ memset(line->cl_Days, 1, sizeof(line->cl_Days));
+ }
+
+ /*
+@@ -881,7 +907,7 @@ DeleteFile(CronFile **pfile)
+ file->cf_Deleted = 1;
+
+ while ((line = *pline) != NULL) {
+- if (line->cl_Pid > 0) {
++ if (line->cl_Pid > JOB_NONE) {
+ file->cf_Running = 1;
+ pline = &line->cl_Next;
+ } else {
+@@ -942,13 +968,14 @@ TestJobs(time_t t1, time_t t2)
+ CronFile *file;
+ CronLine *line;
+
++ PrintFile(FileBase, "TestJobs()", __FILE__, __LINE__);
+ for (file = FileBase; file; file = file->cf_Next) {
+ if (file->cf_Deleted)
+ continue;
+ for (line = file->cf_LineBase; line; line = line->cl_Next) {
+ struct CronWaiter *waiter;
+
+- if (line->cl_Pid == -2) {
++ if (line->cl_Pid == JOB_WAITING) {
+ /* can job stop waiting? */
+ int ready = 1;
+ waiter = line->cl_Waiters;
+@@ -965,7 +992,7 @@ TestJobs(time_t t1, time_t t2)
+ if (ready == 2) {
+ if (DebugOpt)
+ printlogf(LOG_DEBUG, "cancelled waiting: user %s %s\n", file->cf_UserName, line->cl_Description);
+- line->cl_Pid = 0;
++ line->cl_Pid = JOB_NONE;
+ } else if (ready) {
+ if (DebugOpt)
+ printlogf(LOG_DEBUG, "finished waiting: user %s %s\n", file->cf_UserName, line->cl_Description);
+@@ -987,24 +1014,23 @@ TestJobs(time_t t1, time_t t2)
+ if (t > t1) {
+ struct tm *tp = localtime(&t);
+
+- unsigned short n_wday = (tp->tm_mday - 1)%7 + 1;
+- if (n_wday >= 4) {
++ char n_wday = 1 << ((tp->tm_mday - 1) / 7);
++ if (n_wday >= FOURTH_DOW) {
+ struct tm tnext = *tp;
+ tnext.tm_mday += 7;
+ if (mktime(&tnext) != (time_t)-1 && tnext.tm_mon != tp->tm_mon)
+- n_wday |= 16; /* last dow in month is always recognized as 5th */
++ n_wday |= LAST_DOW; /* last dow in month is always recognized as 6th bit */
+ }
+
+ for (file = FileBase; file; file = file->cf_Next) {
+ if (file->cf_Deleted)
+ continue;
+ for (line = file->cf_LineBase; line; line = line->cl_Next) {
+- if ((line->cl_Pid == -2 || line->cl_Pid == 0) && (line->cl_Freq == 0 || (line->cl_Freq > 0 && t2 >= line->cl_NotUntil))) {
++ if ((line->cl_Pid == JOB_WAITING || line->cl_Pid == JOB_NONE) && (line->cl_Freq == 0 || (line->cl_Freq > 0 && t2 >= line->cl_NotUntil))) {
+ /* (re)schedule job? */
+ if (line->cl_Mins[tp->tm_min] &&
+ line->cl_Hrs[tp->tm_hour] &&
+- (line->cl_Days[tp->tm_mday] || (n_wday && line->cl_Dow[tp->tm_wday]) ) &&
+- line->cl_Mons[tp->tm_mon]
++ (line->cl_Days[tp->tm_mday] && n_wday & line->cl_Dow[tp->tm_wday])
+ ) {
+ if (line->cl_NotUntil)
+ line->cl_NotUntil = t2 - t2 % 60 + line->cl_Delay; /* save what minute this job was scheduled/started waiting, plus cl_Delay */
+@@ -1027,19 +1053,19 @@ int
+ ArmJob(CronFile *file, CronLine *line, time_t t1, time_t t2)
+ {
+ struct CronWaiter *waiter;
+- if (line->cl_Pid > 0) {
++ if (line->cl_Pid > JOB_NONE) {
+ printlogf(LOG_NOTICE, "process already running (%d): user %s %s\n",
+ line->cl_Pid,
+ file->cf_UserName,
+ line->cl_Description
+ );
+- } else if (t2 == -1 && line->cl_Pid != -1) {
+- line->cl_Pid = -1;
++ } else if (t2 == -1 && line->cl_Pid != JOB_ARMED) {
++ line->cl_Pid = JOB_ARMED;
+ file->cf_Ready = 1;
+ return 1;
+- } else if (line->cl_Pid == 0) {
++ } else if (line->cl_Pid == JOB_NONE) {
+ /* arming a waiting job (cl_Pid == -2) without forcing has no effect */
+- line->cl_Pid = -1;
++ line->cl_Pid = JOB_ARMED;
+ /* if we have any waiters, zero them and arm cl_Pid=-2 */
+ waiter = line->cl_Waiters;
+ while (waiter != NULL) {
+@@ -1047,15 +1073,15 @@ ArmJob(CronFile *file, CronLine *line, time_t t1, time_t t2)
+ if (!waiter->cw_NotifLine)
+ /* notifier deleted */
+ waiter->cw_Flag = 0;
+- else if (waiter->cw_NotifLine->cl_Pid != 0) {
++ else if (waiter->cw_NotifLine->cl_Pid != JOB_NONE) {
+ /* if notifier is armed, or waiting, or running, we wait for it */
+ waiter->cw_Flag = -1;
+- line->cl_Pid = -2;
++ line->cl_Pid = JOB_WAITING;
+ } else if (waiter->cw_NotifLine->cl_Freq < 0) {
+ /* arm any @noauto or @reboot jobs we're waiting on */
+ ArmJob(file, waiter->cw_NotifLine, t1, t2);
+ waiter->cw_Flag = -1;
+- line->cl_Pid = -2;
++ line->cl_Pid = JOB_WAITING;
+ } else {
+ time_t t;
+ if (waiter->cw_MaxWait == 0)
+@@ -1068,21 +1094,20 @@ ArmJob(CronFile *file, CronLine *line, time_t t1, time_t t2)
+ if (t > t1) {
+ struct tm *tp = localtime(&t);
+
+- unsigned short n_wday = (tp->tm_mday - 1)%7 + 1;
+- if (n_wday >= 4) {
++ char n_wday = 1 << ((tp->tm_mday - 1) / 7);
++ if (n_wday >= FOURTH_DOW) {
+ struct tm tnext = *tp;
+ tnext.tm_mday += 7;
+ if (mktime(&tnext) != (time_t)-1 && tnext.tm_mon != tp->tm_mon)
+- n_wday |= 16; /* last dow in month is always recognized as 5th */
++ n_wday |= LAST_DOW; /* last dow in month is always recognized as 6th */
+ }
+ if (line->cl_Mins[tp->tm_min] &&
+ line->cl_Hrs[tp->tm_hour] &&
+- (line->cl_Days[tp->tm_mday] || (n_wday && line->cl_Dow[tp->tm_wday]) ) &&
+- line->cl_Mons[tp->tm_mon]
++ (line->cl_Days[tp->tm_mday] && n_wday & line->cl_Dow[tp->tm_wday])
+ ) {
+ /* notifier will run soon enough, we wait for it */
+ waiter->cw_Flag = -1;
+- line->cl_Pid = -2;
++ line->cl_Pid = JOB_WAITING;
+ break;
+ }
+ }
+@@ -1091,7 +1116,7 @@ ArmJob(CronFile *file, CronLine *line, time_t t1, time_t t2)
+ }
+ waiter = waiter->cw_Next;
+ }
+- if (line->cl_Pid == -1) {
++ if (line->cl_Pid == JOB_ARMED) {
+ /* job is ready to run */
+ file->cf_Ready = 1;
+ if (DebugOpt)
+@@ -1135,18 +1160,18 @@ TestStartupJobs(void)
+ if (line->cl_Freq == -1) {
+ /* freq is @reboot */
+
+- line->cl_Pid = -1;
++ line->cl_Pid = JOB_ARMED;
+ /* if we have any waiters, reset them and arm Pid = -2 */
+ waiter = line->cl_Waiters;
+ while (waiter != NULL) {
+ waiter->cw_Flag = -1;
+- line->cl_Pid = -2;
++ line->cl_Pid = JOB_WAITING;
+ /* we only arm @noauto jobs we're waiting on, not other @reboot jobs */
+ if (waiter->cw_NotifLine && waiter->cw_NotifLine->cl_Freq == -2)
+ ArmJob(file, waiter->cw_NotifLine, t1, t1+60);
+ waiter = waiter->cw_Next;
+ }
+- if (line->cl_Pid == -1) {
++ if (line->cl_Pid == JOB_ARMED) {
+ /* job is ready to run */
+ file->cf_Ready = 1;
+ ++nJobs;
+@@ -1173,7 +1198,7 @@ RunJobs(void)
+ file->cf_Ready = 0;
+
+ for (line = file->cf_LineBase; line; line = line->cl_Next) {
+- if (line->cl_Pid == -1) {
++ if (line->cl_Pid == JOB_ARMED) {
+
+ RunJob(file, line);
+
+@@ -1184,10 +1209,10 @@ RunJobs(void)
+ line->cl_Pid,
+ line->cl_Description
+ );
+- if (line->cl_Pid < 0)
++ if (line->cl_Pid < JOB_NONE)
+ /* QUESTION how could this happen? RunJob will leave cl_Pid set to 0 or the actual pid */
+ file->cf_Ready = 1;
+- else if (line->cl_Pid > 0)
++ else if (line->cl_Pid > JOB_NONE)
+ file->cf_Running = 1;
+ }
+ }
+@@ -1214,7 +1239,7 @@ CheckJobs(void)
+ file->cf_Running = 0;
+
+ for (line = file->cf_LineBase; line; line = line->cl_Next) {
+- if (line->cl_Pid > 0) {
++ if (line->cl_Pid > JOB_NONE) {
+ int status;
+ int r = waitpid(line->cl_Pid, &status, WNOHANG);
+
+@@ -1237,7 +1262,7 @@ CheckJobs(void)
+ /* For the purposes of this check, increase the "still running" counter if a file has lines that are waiting */
+ if (file->cf_Running == 0) {
+ for (line = file->cf_LineBase; line; line = line->cl_Next) {
+- if (line->cl_Pid == -2) {
++ if (line->cl_Pid == JOB_WAITING) {
+ nStillRunning += 1;
+ break;
+ }
+@@ -1247,3 +1272,69 @@ CheckJobs(void)
+ return(nStillRunning);
+ }
+
++void
++PrintLine(CronLine *line)
++{
++ int i;
++ if (!line)
++ return;
++
++ printlogf(LOG_DEBUG, "CronLine:\n------------\n");
++ printlogf(LOG_DEBUG, " Command: %s\n", line->cl_Shell);
++ //printlogf(LOG_DEBUG, " Desc: %s\n", line->cl_Description);
++ printlogf(LOG_DEBUG, " Freq: %s\n", (line->cl_Freq ?
++ (line->cl_Freq == -1 ? "(noauto)" : "(startup") : "(use arrays)"));
++ printlogf(LOG_DEBUG, " PID: %d\n", line->cl_Pid);
++
++ printlogf(LOG_DEBUG, " Mins: ");
++ for (i = 0; i < 60; ++i)
++ printlogf(LOG_DEBUG, "%d", line->cl_Mins[i]);
++
++ printlogf(LOG_DEBUG, "\n Hrs: ");
++ for (i = 0; i < 24; ++i)
++ printlogf(LOG_DEBUG, "%d", line->cl_Hrs[i]);
++
++ printlogf(LOG_DEBUG, "\n Days: ");
++ for (i = 0; i < 32; ++i)
++ printlogf(LOG_DEBUG, "%d", line->cl_Days[i]);
++
++ printlogf(LOG_DEBUG, "\n Mons: ");
++ for (i = 0; i < 12; ++i)
++ printlogf(LOG_DEBUG, "%d", line->cl_Mons[i]);
++
++ printlogf(LOG_DEBUG, "\n Dow: ");
++ for (i = 0; i < 7; ++i)
++ printlogf(LOG_DEBUG, "%02x ", line->cl_Dow[i]);
++ printlogf(LOG_DEBUG, "\n\n");
++}
++
++void
++PrintFile(CronFile *file, char* loc, char* fname, int line)
++{
++ CronFile *f;
++ CronLine *l;
++
++ printlogf(LOG_DEBUG, "%s %s:%d\n", loc, fname, line);
++
++ if (!file)
++ return;
++
++ f = file;
++ while (f) {
++
++ if (strncmp(file->cf_UserName, "root", 4)) {
++ printlogf(LOG_DEBUG, "FILE %s/%s USER %s\n=============================\n",
++ file->cf_DPath,
++ file->cf_FileName,
++ file->cf_UserName);
++ l = f->cf_LineBase;
++
++ while (l) {
++ PrintLine(l);
++ l = l->cl_Next;
++ }
++ }
++ f = f->cf_Next;
++ }
++
++}
+diff --git a/defs.h b/defs.h
+index b221636..cf77b5f 100644
+--- a/defs.h
++++ b/defs.h
+@@ -17,6 +17,7 @@
+ */
+
+ #define _XOPEN_SOURCE 1
++#define _DEFAULT_SOURCE 1
+ #define _BSD_SOURCE 1
+
+ #include <sys/types.h>
+@@ -102,6 +103,16 @@
+ #define MONTHLY_FREQ 30 * DAILY_FREQ
+ #define YEARLY_FREQ 365 * DAILY_FREQ
+
++#define FIELD_MINUTES 60
++#define FIELD_HOURS 24
++#define FIELD_M_DAYS 32
++#define FIELD_MONTHS 12
++#define FIELD_W_DAYS 7
++
++#define JOB_NONE 0
++#define JOB_ARMED -1
++#define JOB_WAITING -2
++
+ #define LOGHEADER TIMESTAMP_FMT " %%s " LOG_IDENT ": "
+ #define LOCALE_LOGHEADER "%c %%s " LOG_IDENT ": "
+
+@@ -112,9 +123,6 @@
+ #define RW_BUFFER 1024
+ #define LOG_BUFFER 2048 /* max size of log line */
+
+-
+-
+-
+ typedef struct CronFile {
+ struct CronFile *cf_Next;
+ struct CronLine *cf_LineBase;
+@@ -141,11 +149,11 @@ typedef struct CronLine {
+ int cl_Pid; /* running pid, 0, or armed (-1), or waiting (-2) */
+ int cl_MailFlag; /* running pid is for mail */
+ int cl_MailPos; /* 'empty file' size */
+- char cl_Mins[60]; /* 0-59 */
+- char cl_Hrs[24]; /* 0-23 */
+- char cl_Days[32]; /* 1-31 */
+- char cl_Mons[12]; /* 0-11 */
+- char cl_Dow[7]; /* 0-6, beginning sunday */
++ char cl_Mins[FIELD_MINUTES]; /* 0-59 */
++ char cl_Hrs[FIELD_HOURS]; /* 0-23 */
++ char cl_Days[FIELD_M_DAYS]; /* 1-31 */
++ char cl_Mons[FIELD_MONTHS]; /* 0-11 */
++ char cl_Dow[FIELD_W_DAYS]; /* 0-6, beginning sunday */
+ } CronLine;
+
+ typedef struct CronWaiter {
+--
+2.13.2
+
diff --git a/source/a/dcron/patches/0009-Updated-manpage.patch b/source/a/dcron/patches/0009-Updated-manpage.patch
new file mode 100644
index 000000000..5db2550c1
--- /dev/null
+++ b/source/a/dcron/patches/0009-Updated-manpage.patch
@@ -0,0 +1,45 @@
+From 496027f566df6968939c45ad1a0069af495a2d40 Mon Sep 17 00:00:00 2001
+From: "Erik Falor (fadein)" <ewfalor@gmail.com>
+Date: Tue, 24 Nov 2015 22:19:30 -0700
+Subject: [PATCH 9/9] Updated manpage
+
+---
+ crontab.1 | 13 ++++++++-----
+ 1 file changed, 8 insertions(+), 5 deletions(-)
+
+diff --git a/crontab.1 b/crontab.1
+index 36043a9..1e2f59f 100644
+--- a/crontab.1
++++ b/crontab.1
+@@ -92,20 +92,23 @@ Some examples:
+ .fi
+ .PP
+ To request the last Monday, etc.
+-in a month, ask for the \[lq]5th\[rq] one.
++in a month, ask for the \[lq]6th\[rq] one.
+ This will always match the last Monday, etc., even if there are
+ only four Mondays in the month:
+ .IP
+ .nf
+ \f[C]
+ #\ run\ at\ 11\ am\ on\ the\ first\ and\ last\ Mon,\ Tue,\ Wed\ of\ each\ month
+-0\ 11\ 1,5\ *\ mon-wed\ date
++0\ 11\ 1,6\ *\ mon-wed\ date
++
++#\ run\ at\ noon\ on\ the\ fourth\ and\ last\ Friday\ of\ each\ month
++0\ 12\ 4,6\ *\ fri\ date
+ \f[]
+ .fi
+ .PP
+-When the fourth Monday in a month is the last, it will match
+-against both the \[lq]4th\[rq] and the \[lq]5th\[rq] (it will only
+-run once if both are specified).
++When the fourth Monday in a month is also the last, this will match against
++both the \[lq]4th\[rq] and the \[lq]6th\[rq] but the job is scheduled only
++once.
+ .PP
+ The following formats are also recognized:
+ .IP
+--
+2.13.2
+
diff --git a/source/a/dcron/crontab.c.O_EXCL.diff b/source/a/dcron/patches/crontab.c.O_EXCL.diff
index f705487ec..f705487ec 100644
--- a/source/a/dcron/crontab.c.O_EXCL.diff
+++ b/source/a/dcron/patches/crontab.c.O_EXCL.diff
diff --git a/source/a/dcron/defs.h.TMPDIR.diff b/source/a/dcron/patches/defs.h.TMPDIR.diff
index 698f4ebc0..0210c55c9 100644
--- a/source/a/dcron/defs.h.TMPDIR.diff
+++ b/source/a/dcron/patches/defs.h.TMPDIR.diff
@@ -6,7 +6,7 @@ diff -Nur dcron-4.5.orig//defs.h dcron-4.5/defs.h
#endif
#ifndef TMPDIR
-#define TMPDIR "/tmp"
-+#define TMPDIR "/var/spool/cron"
++#define TMPDIR "/run/cron"
#endif
#ifndef SENDMAIL
diff --git a/source/a/dcron/rc.crond b/source/a/dcron/rc.crond
new file mode 100644
index 000000000..c9c94ec89
--- /dev/null
+++ b/source/a/dcron/rc.crond
@@ -0,0 +1,40 @@
+#!/bin/sh
+# /etc/rc.d/rc.crond - start/stop the cron daemon
+
+# To change the default options, edit /etc/default/crond.
+if [ -r /etc/default/crond ]; then
+ . /etc/default/crond
+fi
+
+start_crond() {
+ if ! /usr/bin/pgrep --ns $$ --exact crond 1> /dev/null 2> /dev/null ; then
+ echo "Starting crond: /usr/sbin/crond $CROND_OPTS"
+ mkdir -p /run/cron
+ /usr/sbin/crond $CROND_OPTS
+ fi
+}
+
+stop_crond() {
+ echo "Stopping crond."
+ /usr/bin/pkill --ns $$ --exact crond 2> /dev/null
+}
+
+restart_crond() {
+ stop_crond
+ sleep 1
+ start_crond
+}
+
+case "$1" in
+'start')
+ start_crond
+ ;;
+'stop')
+ stop_crond
+ ;;
+'restart')
+ restart_crond
+ ;;
+*)
+ echo "usage $0 start|stop|restart"
+esac