diff options
author | xiota | 2023-10-19 01:40:55 -0700 |
---|---|---|
committer | xiota | 2023-10-19 01:41:40 -0700 |
commit | 87c51cb7059905cde3372c64e5bdef9815bdb1e3 (patch) | |
tree | ef7d8b4b833d72a92470d08e677228afee156e2e | |
parent | 27896c1ca508945463086c25e9de00e00c7d601f (diff) | |
download | aur-87c51cb7059905cde3372c64e5bdef9815bdb1e3.tar.gz |
1.0.2.r18.gd69afa9
-rw-r--r-- | .SRCINFO | 29 | ||||
-rw-r--r-- | .gitignore | 4 | ||||
-rw-r--r-- | 0001-d69afa94.patch | 1713 | ||||
-rw-r--r-- | 0002-makefile.patch | 40 | ||||
-rw-r--r-- | PKGBUILD | 116 |
5 files changed, 1859 insertions, 43 deletions
@@ -1,26 +1,25 @@ -# Generated by mksrcinfo v8 -# Wed Jun 8 13:09:06 UTC 2016 pkgbase = systemd-cron-next - pkgdesc = systemd generator to generate timers/services from crontab and anacrontab files - pkgver = 1.0.2 - pkgrel = 2 + pkgdesc = Systemd generator to generate timers/services from crontab and anacrontab files + pkgver = 1.0.2.r18.gd69afa9 + pkgrel = 1 url = https://github.com/systemd-cron/systemd-cron-next arch = i686 arch = x86_64 license = MIT - makedepends = rust>=1.4.0 - makedepends = cargo>=0.6.0 - depends = systemd>=217 + makedepends = rust depends = run-parts + depends = systemd optdepends = smtp-forwarder: sending emails - provides = cron provides = anacron - conflicts = cron + provides = cron + provides = systemd-cron conflicts = anacron - replaces = cron - replaces = anacron - source = https://github.com/systemd-cron/systemd-crontab-generator/archive/v1.0.2.zip - md5sums = fe6150aba32ba2cc4fd33a12a84044d9 + conflicts = cron + source = 0002-makefile.patch + source = 0001-d69afa94.patch + source = systemd-cron-next-1.0.2.zip::https://github.com/systemd-cron/systemd-crontab-generator/archive/v1.0.2.zip + sha256sums = 095f20fd780717da18c0251df0ff702a5953816120f3040a317ccc9dc3e1572b + sha256sums = 236cbbaa3cc56176874d96162ba49c5f642615596f9d50056c04ed65347fbf80 + sha256sums = 455d1ea09ecb29efaec44255f6439794d2118d63133936b389fd3afd9c60cc2f pkgname = systemd-cron-next - diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000000..018a3de08144 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +* +!PKGBUILD +!.SRCINFO +!.gitignore diff --git a/0001-d69afa94.patch b/0001-d69afa94.patch new file mode 100644 index 000000000000..7c253a8ef13f --- /dev/null +++ b/0001-d69afa94.patch @@ -0,0 +1,1713 @@ + Cargo.lock | 140 +++++++++++---- + Cargo.toml | 7 +- + Makefile.in | 12 +- + README.md | 4 +- + build.rs | 88 +++++++--- + configure | 8 + + man/crontab.5.in | 2 +- + man/systemd-crontab-generator.8.in | 2 +- + src/bin/boot-delay.rs | 16 +- + src/bin/crontab.rs | 122 ++++++------- + src/bin/mail-on-failure.rs | 38 ++-- + src/bin/remove-stale-stamps.rs | 50 +++--- + src/generate.rs | 346 ++++++++++++++++++++----------------- + src/main.rs | 52 +++--- + src/process.rs | 67 +++---- + 15 files changed, 561 insertions(+), 393 deletions(-) + +diff --git a/Cargo.lock b/Cargo.lock +index 04410c7..9ed802c 100644 +--- a/Cargo.lock ++++ b/Cargo.lock +@@ -1,22 +1,5 @@ +-[root] +-name = "systemd-crontab-generator" +-version = "1.0.1" +-dependencies = [ +- "cronparse 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +- "docopt 0.6.80 (registry+https://github.com/rust-lang/crates.io-index)", +- "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", +- "handlebars 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", +- "kernlog 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +- "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", +- "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +- "md5 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +- "pgs-files 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)", +- "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", +- "tempfile 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +- "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", +- "users 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +-] +- ++# This file is automatically @generated by Cargo. ++# It is not intended for manual editing. + [[package]] + name = "aho-corasick" + version = "0.5.2" +@@ -25,6 +8,21 @@ dependencies = [ + "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + ] + ++[[package]] ++name = "bitflags" ++version = "1.2.1" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++ ++[[package]] ++name = "cc" ++version = "1.0.53" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++ ++[[package]] ++name = "cfg-if" ++version = "0.1.10" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++ + [[package]] + name = "cronparse" + version = "0.5.0" +@@ -36,7 +34,7 @@ version = "0.6.80" + source = "registry+https://github.com/rust-lang/crates.io-index" + dependencies = [ + "regex 0.1.71 (registry+https://github.com/rust-lang/crates.io-index)", +- "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", ++ "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + ] + +@@ -55,7 +53,7 @@ dependencies = [ + "num 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-error 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.71 (registry+https://github.com/rust-lang/crates.io-index)", +- "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", ++ "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + ] + + [[package]] +@@ -87,7 +85,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" + + [[package]] + name = "libc" +-version = "0.2.11" ++version = "0.2.70" + source = "registry+https://github.com/rust-lang/crates.io-index" + + [[package]] +@@ -105,7 +103,19 @@ name = "memchr" + version = "0.1.11" + source = "registry+https://github.com/rust-lang/crates.io-index" + dependencies = [ +- "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ++ "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", ++] ++ ++[[package]] ++name = "nix" ++version = "0.17.0" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++dependencies = [ ++ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ++ "cc 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", ++ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ++ "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", ++ "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + ] + + [[package]] +@@ -129,7 +139,7 @@ dependencies = [ + "num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", +- "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", ++ "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + ] + + [[package]] +@@ -138,7 +148,7 @@ version = "0.1.32" + source = "registry+https://github.com/rust-lang/crates.io-index" + dependencies = [ + "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", +- "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", ++ "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + ] + + [[package]] +@@ -166,7 +176,7 @@ dependencies = [ + "num-bigint 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", +- "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", ++ "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + ] + + [[package]] +@@ -192,7 +202,7 @@ name = "rand" + version = "0.3.14" + source = "registry+https://github.com/rust-lang/crates.io-index" + dependencies = [ +- "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ++ "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", + ] + + [[package]] +@@ -214,7 +224,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" + + [[package]] + name = "rustc-serialize" +-version = "0.3.19" ++version = "0.3.24" + source = "registry+https://github.com/rust-lang/crates.io-index" + + [[package]] +@@ -222,13 +232,33 @@ name = "strsim" + version = "0.3.0" + source = "registry+https://github.com/rust-lang/crates.io-index" + ++[[package]] ++name = "systemd-crontab-generator" ++version = "1.0.2" ++dependencies = [ ++ "cronparse 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ++ "docopt 0.6.80 (registry+https://github.com/rust-lang/crates.io-index)", ++ "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ++ "handlebars 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", ++ "kernlog 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ++ "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", ++ "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ++ "md5 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ++ "nix 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", ++ "pgs-files 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ++ "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", ++ "tempfile 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ++ "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", ++ "users 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ++] ++ + [[package]] + name = "tempfile" + version = "1.1.3" + source = "registry+https://github.com/rust-lang/crates.io-index" + dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +- "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ++ "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + ] +@@ -239,7 +269,7 @@ version = "2.0.0" + source = "registry+https://github.com/rust-lang/crates.io-index" + dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +- "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ++ "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", + ] + + [[package]] +@@ -256,7 +286,7 @@ version = "0.1.35" + source = "registry+https://github.com/rust-lang/crates.io-index" + dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +- "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ++ "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + ] + +@@ -265,7 +295,7 @@ name = "users" + version = "0.5.1" + source = "registry+https://github.com/rust-lang/crates.io-index" + dependencies = [ +- "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ++ "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", + ] + + [[package]] +@@ -273,6 +303,11 @@ name = "utf8-ranges" + version = "0.1.3" + source = "registry+https://github.com/rust-lang/crates.io-index" + ++[[package]] ++name = "void" ++version = "1.0.2" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++ + [[package]] + name = "winapi" + version = "0.2.7" +@@ -283,3 +318,44 @@ name = "winapi-build" + version = "0.1.1" + source = "registry+https://github.com/rust-lang/crates.io-index" + ++[metadata] ++"checksum aho-corasick 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2b3fb52b09c1710b961acb35390d514be82e4ac96a9969a8e38565a29b878dc9" ++"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" ++"checksum cc 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)" = "404b1fe4f65288577753b17e3b36a04596ee784493ec249bf81c7f2d2acd751c" ++"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" ++"checksum cronparse 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ffab399727c0d7ff383c9abbad03a24cfd468bed510616c7acabd8331916a8d3" ++"checksum docopt 0.6.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4cc0acb4ce0828c6a5a11d47baa432fe885881c27428c3a4e473e454ffe57a76" ++"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" ++"checksum handlebars 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "120b3b01f000620d46466d37a1c062d65ac7e8dfa11bfeecc2d35398bfd3512a" ++"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" ++"checksum kernlog 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d998b430f80e016e2bb08eb0fc9b61631ef200ec9f7adef7ceec56db89cd2c48" ++"checksum lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "cf186d1a8aa5f5bee5fd662bc9c1b949e0259e1bcc379d1f006847b0080c7417" ++"checksum libc 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "e32a70cf75e5846d53a673923498228bbec6a8624708a9ea5645f075d6276122" ++"checksum libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)" = "3baa92041a6fec78c687fa0cc2b3fae8884f743d672cf551bed1d6dac6988d0f" ++"checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054" ++"checksum md5 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a5539a8dee9b4ae308c9c406a379838b435a8f2c84cf9fedc6d5a576be9888db" ++"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20" ++"checksum nix 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50e4785f2c3b7589a0d0c1dd60285e1188adac4006e8abd6dd578e1567027363" ++"checksum num 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "c04bd954dbf96f76bab6e5bd6cef6f1ce1262d15268ce4f926d2b5b778fa7af2" ++"checksum num-bigint 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "41655c8d667be847a0b72fe0888857a7b3f052f691cf40852be5fcf87b274a65" ++"checksum num-complex 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "ccac67baf893ac97474f8d70eff7761dabb1f6c66e71f8f1c67a6859218db810" ++"checksum num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "fb24d9bfb3f222010df27995441ded1e954f8f69cd35021f6bef02ca9552fb92" ++"checksum num-iter 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "287a1c9969a847055e1122ec0ea7a5c5d6f72aad97934e131c83d5c08ab4e45c" ++"checksum num-rational 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "48cdcc9ff4ae2a8296805ac15af88b3d88ce62128ded0cb74ffb63a587502a84" ++"checksum num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "51eab148f171aefad295f8cece636fc488b9b392ef544da31ea4b8ef6b9e9c39" ++"checksum pgs-files 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8de73733f1d567f1188c2cf51eaf072272d24c1d6d9549456a11f59a8c248410" ++"checksum quick-error 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5fb6ccf8db7bbcb9c2eae558db5ab4f3da1c2a87e4e597ed394726bc8ea6ca1d" ++"checksum rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2791d88c6defac799c3f20d74f094ca33b9332612d9aef9078519c82e4fe04a5" ++"checksum regex 0.1.71 (registry+https://github.com/rust-lang/crates.io-index)" = "e58a1b7d2bfecc0746e8587c30a53d01ea7bc0e98fac54e5aaa375b94338a0cc" ++"checksum regex-syntax 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "baa04823ba7be7ed0bed3d0704c7b923019d9c4e4931c5af2804c7c7a0e3d00b" ++"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" ++"checksum strsim 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e4d73a2c36a4d095ed1a6df5cbeac159863173447f7a82b3f4757426844ab825" ++"checksum tempfile 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ea9234ab6f388c147f9a44dfd331f2c5ad956387acbb9fa03e99abc5a28e5eaa" ++"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" ++"checksum thread_local 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "55dd963dbaeadc08aa7266bf7f91c3154a7805e32bb94b820b769d2ef3b4744d" ++"checksum time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "3c7ec6d62a20df54e07ab3b78b9a3932972f4b7981de295563686849eb3989af" ++"checksum users 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d6d73ff26a6a57e6328f6e0b31738dfe27478e90ea828c3aba85a774d815c971" ++"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f" ++"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" ++"checksum winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3969e500d618a5e974917ddefd0ba152e4bcaae5eb5d9b8c1fbc008e9e28c24e" ++"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" +diff --git a/Cargo.toml b/Cargo.toml +index 8ad24ad..1d609aa 100644 +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -8,10 +8,11 @@ name = "systemd-crontab-generator" + readme = "README.md" + repository = "https://github.com/systemd-cron/systemd-cron-next" + version = "1.0.2" ++edition = "2018" + + [build-dependencies] + handlebars = "0.12.0" +-rustc-serialize = "0.3.16" ++rustc-serialize = "0.3.20" + + [dependencies] + cronparse = "0.5.0" +@@ -22,13 +23,13 @@ libc = "0.2.2" + log = "0.3.4" + md5 = "0.1.1" + pgs-files = "0.0.6" +-rustc-serialize = "0.3.16" ++rustc-serialize = "0.3.20" + tempfile = "1.1.3" + time = "0.1.34" + users = "0.5.1" ++nix = "0.17.0" + + [features] +-default = ["sched-boot", "sched-hourly", "sched-daily", "sched-weekly", "sched-monthly", "randomized-delay"] + persistent = [] + randomized-delay = [] + sched-boot = [] +diff --git a/Makefile.in b/Makefile.in +index cbafc03..147b0c8 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -5,6 +5,7 @@ version := $(shell awk '/^version =/ { gsub("\"", "", $$3); print $$3; exit }' + schedules := @schedules@ + enable_persistent := @enable_persistent@ + enable_randomized_delay := @enable_randomized_delay@ ++enable_strip := @enable_strip@ + + prefix := @prefix@ + bindir := @bindir@ +@@ -43,6 +44,7 @@ endef + null := + persistent = $(if $(filter $(enable_persistent),yes),persistent,) + randomized_delay = $(if $(filter $(enable_randomized_delay),yes),randomized-delay,) ++strip = $(if $(filter $(enable_strip),yes),-s,) + + all: build + +@@ -71,11 +73,11 @@ build: all + --features "$(foreach schedule,$(schedules),sched-$(schedule)) $(persistent) $(randomized_delay)" + + install: build +- install -m2755 -g `getent group cron || echo root` -s -D $(builddir)/bin/crontab $(DESTDIR)$(bindir)/crontab +- install -m755 -s -D $(builddir)/bin/systemd-crontab-generator $(DESTDIR)$(libdir)/systemd/system-generators/systemd-crontab-generator +- install -m755 -s -D $(builddir)/bin/remove-stale-stamps $(DESTDIR)$(libdir)/$(packagedir)/remove-stale-stamps +- install -m755 -s -D $(builddir)/bin/mail-on-failure $(DESTDIR)$(libdir)/$(packagedir)/mail-on-failure +- install -m755 -s -D $(builddir)/bin/boot-delay $(DESTDIR)$(libdir)/$(packagedir)/boot-delay ++ install -m2755 -g `getent group cron || echo root` $(strip) -D $(builddir)/bin/crontab $(DESTDIR)$(bindir)/crontab ++ install -m755 $(strip) -D $(builddir)/bin/systemd-crontab-generator $(DESTDIR)$(libdir)/systemd/system-generators/systemd-crontab-generator ++ install -m755 $(strip) -D $(builddir)/bin/remove-stale-stamps $(DESTDIR)$(libdir)/$(packagedir)/remove-stale-stamps ++ install -m755 $(strip) -D $(builddir)/bin/mail-on-failure $(DESTDIR)$(libdir)/$(packagedir)/mail-on-failure ++ install -m755 $(strip) -D $(builddir)/bin/boot-delay $(DESTDIR)$(libdir)/$(packagedir)/boot-delay + + install -m644 -D $(builddir)/man/systemd.cron.7 $(DESTDIR)$(mandir)/man7/systemd.cron.7 + install -m644 -D $(builddir)/man/crontab.1 $(DESTDIR)$(mandir)/man1/crontab.1 +diff --git a/README.md b/README.md +index cf2b5ba..762c7df 100644 +--- a/README.md ++++ b/README.md +@@ -133,7 +133,7 @@ Other options include: + + * `--unitdir=<path>` Path to systemd unit files. + Default: `<libdir>/systemd/system`. +-* `--runpaths=<path>` The path installations should use for the `run-parts` executable. ++* `--runparts=<path>` The path installations should use for the `run-parts` executable. + Default: `<prefix>/bin/run-parts`. + * `--enable-boot[=yes|no]` Include support for the boot timer. + Default: `yes`. +@@ -157,6 +157,8 @@ Other options include: + Default: `no`. + * `--enable-randomized-delay=[yes|no]` Use [`RandomizedDelaySec`][6] option for `RANDOM_DELAY` support. Requires systemd ≥ 229. + Default: `yes`. ++* `--enable-strip=[yes|no]` Strip binaries. ++ Default: `yes`. + + A typical configuration for the latest systemd would be: + +diff --git a/build.rs b/build.rs +index 63243a3..20b66ab 100644 +--- a/build.rs ++++ b/build.rs +@@ -1,13 +1,13 @@ + extern crate handlebars; + extern crate rustc_serialize; + ++use std::collections::BTreeMap; + use std::env; +-use std::path::Path; +-use std::fs::{self, File, create_dir_all}; ++use std::fs::{self, create_dir_all, File}; + use std::io::{Read, Write}; +-use std::collections::BTreeMap; ++use std::path::Path; + +-use handlebars::{Handlebars, Context, Template}; ++use handlebars::{Context, Handlebars, Template}; + use rustc_serialize::json::{Json, ToJson}; + + static UNITS_DIR: &'static str = "units"; +@@ -24,21 +24,29 @@ fn main() { + let data = build_render_data(); + + let mut config = File::create(out_dir.clone() + "/config.rs").unwrap(); +- writeln!(config, "pub static USERS_CRONTAB_DIR: &'static str = {:?};", data["statedir"].as_string().unwrap()).unwrap(); +- writeln!(config, "pub static PACKAGE: &'static str = {:?};", data["package"].as_string().unwrap()).unwrap(); +- writeln!(config, "pub static BIN_DIR: &'static str = {:?};", data["bindir"].as_string().unwrap()).unwrap(); +- writeln!(config, "pub static LIB_DIR: &'static str = {:?};", data["libdir"].as_string().unwrap()).unwrap(); ++ writeln!( ++ config, ++ "pub static USERS_CRONTAB_DIR: &str = {:?};", ++ data["statedir"].as_string().unwrap() ++ ) ++ .unwrap(); ++ writeln!(config, "pub static PACKAGE: &str = {:?};", data["package"].as_string().unwrap()).unwrap(); ++ writeln!(config, "pub static BIN_DIR: &str = {:?};", data["bindir"].as_string().unwrap()).unwrap(); ++ writeln!(config, "pub static LIB_DIR: &str = {:?};", data["libdir"].as_string().unwrap()).unwrap(); + + let mut data = Json::Object(data); + let schedules = get_required_schedules(); + + for schedule in schedules.iter() { +- data.as_object_mut().unwrap().insert("schedule".to_owned(), Json::String(schedule.clone())); +- for schedule_unit in [ "target", "timer", "service" ].iter() { ++ data.as_object_mut() ++ .unwrap() ++ .insert("schedule".to_owned(), Json::String(schedule.clone())); ++ for schedule_unit in ["target", "timer", "service"].iter() { + compile_template( + format!("{}/cron-schedule.{}.in", UNITS_DIR, schedule_unit), + output.join("units").join(format!("cron-{}.{}", schedule, schedule_unit)), +- &data); ++ &data, ++ ); + } + } + +@@ -49,12 +57,18 @@ fn main() { + } + + fn compile_template<S: AsRef<Path>, T: AsRef<Path>>(source_file: S, target_file: T, data: &Json) { +- println!("compiling from template: {:?} -> {:?}...", source_file.as_ref(), target_file.as_ref()); +- +- let tmpl = File::open(source_file).and_then(|mut file| { +- let mut buf = String::new(); +- file.read_to_string(&mut buf).map(|_| Template::compile(&*buf).unwrap()) +- }).unwrap(); ++ println!( ++ "compiling from template: {:?} -> {:?}...", ++ source_file.as_ref(), ++ target_file.as_ref() ++ ); ++ ++ let tmpl = File::open(source_file) ++ .and_then(|mut file| { ++ let mut buf = String::new(); ++ file.read_to_string(&mut buf).map(|_| Template::compile(&*buf).unwrap()) ++ }) ++ .unwrap(); + + let mut handle = Handlebars::new(); + handle.register_template("default", tmpl); +@@ -68,7 +82,7 @@ fn compile_templates<P: AsRef<Path>>(source_dir: &str, output_dir: P, data: &Jso + let entry = entry.unwrap(); + let name = entry.file_name().into_string().unwrap(); + if name.ends_with(".in") && !name.starts_with("cron-schedule.") { +- let target = output_dir.as_ref().join(&name[..name.len()-3]); ++ let target = output_dir.as_ref().join(&name[..name.len() - 3]); + compile_template(entry.path(), target, data); + } + } +@@ -82,23 +96,44 @@ fn build_render_data() -> BTreeMap<String, Json> { + + ctx.insert("package".to_owned(), Json::String(package.to_owned())); + +- ctx.insert("bindir".to_owned(), Json::String(env::var("BIN_DIR").unwrap_or_else(|_| prefix.clone() + "/bin"))); +- ctx.insert("confdir".to_owned(), Json::String(env::var("CONF_DIR").unwrap_or_else(|_| prefix.clone() + "/etc"))); ++ ctx.insert( ++ "bindir".to_owned(), ++ Json::String(env::var("BIN_DIR").unwrap_or_else(|_| prefix.clone() + "/bin")), ++ ); ++ ctx.insert( ++ "confdir".to_owned(), ++ Json::String(env::var("CONF_DIR").unwrap_or_else(|_| prefix.clone() + "/etc")), ++ ); + + let datadir = env::var("DATA_DIR").unwrap_or_else(|_| prefix.clone() + "/share"); + let libdir = env::var("LIB_DIR").unwrap_or_else(|_| prefix.clone() + "/lib"); + +- ctx.insert("mandir".to_owned(), Json::String(env::var("MAN_DIR").unwrap_or_else(|_| datadir.clone() + "/man"))); +- ctx.insert("docdir".to_owned(), Json::String(env::var("DOC_DIR").unwrap_or_else(|_| datadir.clone() + "/doc/" + package))); +- ctx.insert("unitdir".to_owned(), Json::String(env::var("UNIT_DIR").unwrap_or_else(|_| libdir.clone() + "/systemd/system"))); ++ ctx.insert( ++ "mandir".to_owned(), ++ Json::String(env::var("MAN_DIR").unwrap_or_else(|_| datadir.clone() + "/man")), ++ ); ++ ctx.insert( ++ "docdir".to_owned(), ++ Json::String(env::var("DOC_DIR").unwrap_or_else(|_| datadir.clone() + "/doc/" + package)), ++ ); ++ ctx.insert( ++ "unitdir".to_owned(), ++ Json::String(env::var("UNIT_DIR").unwrap_or_else(|_| libdir.clone() + "/systemd/system")), ++ ); + + ctx.insert("libdir".to_owned(), Json::String(libdir)); + ctx.insert("datadir".to_owned(), Json::String(datadir)); + ctx.insert("prefix".to_owned(), Json::String(prefix)); + +- ctx.insert("statedir".to_owned(), Json::String(env::var("STATE_DIR").unwrap_or_else(|_| "/var/spool/cron".to_owned()))); ++ ctx.insert( ++ "statedir".to_owned(), ++ Json::String(env::var("STATE_DIR").unwrap_or_else(|_| "/var/spool/cron".to_owned())), ++ ); + +- ctx.insert("runparts".to_owned(), Json::String(env::var("RUN_PARTS").unwrap_or_else(|_| "/usr/bin/run-parts".to_owned()))); ++ ctx.insert( ++ "runparts".to_owned(), ++ Json::String(env::var("RUN_PARTS").unwrap_or_else(|_| "/usr/bin/run-parts".to_owned())), ++ ); + + ctx.insert("persistent".to_owned(), Json::Boolean(env::var("CARGO_FEATURE_PERSISTENT").is_ok())); + +@@ -118,7 +153,8 @@ fn get_required_schedules() -> Vec<String> { + ("CARGO_FEATURE_SCHED_SEMI_ANNUALLY", "semi-annually"), + ]; + +- features.iter() ++ features ++ .iter() + .filter(|&&(e, _)| env::var(e).is_ok()) + .map(|&(_, f)| f.to_owned()) + .collect::<Vec<_>>() +diff --git a/configure b/configure +index df35e64..2182d13 100755 +--- a/configure ++++ b/configure +@@ -11,6 +11,8 @@ docdir='$(datadir)/doc/$(package)' + unitdir='$(libdir)/systemd/system' + runparts='/usr/bin/run-parts' + ++enable_strip=yes ++ + # systemd ≥ 197 + enable_boot=yes + enable_hourly=yes +@@ -54,6 +56,7 @@ enable-semi_annually::, + enable-yearly::, + enable-persistent::, + enable-randomized-delay::, ++enable-strip::, + ' -- "${@}") + + if [ $? -ne 0 ]; then +@@ -159,6 +162,10 @@ do + set_enable_flag randomized_delay ${2} + shift 2;; + ++ '--enable-strip') ++ set_enable_flag strip ${2} ++ shift 2;; ++ + '--') + shift + break;; +@@ -199,6 +206,7 @@ sed " + s|@schedules@|${schedules}|g + s|@enable_persistent@|${enable_persistent}|g + s|@enable_randomized_delay@|${enable_randomized_delay}|g ++s|@enable_strip@|${enable_strip}|g + s|@prefix@|${prefix}|g + s|@bindir@|${bindir}|g + s|@confdir@|${confdir}|g +diff --git a/man/crontab.5.in b/man/crontab.5.in +index 1db13af..f121574 100644 +--- a/man/crontab.5.in ++++ b/man/crontab.5.in +@@ -99,7 +99,7 @@ Otherwise mail is sent to the owner of the crontab. + .br + This mail only contains an small excerpt from the log, as seen when using + .B systemctl status +-The full output remains avaible in the journal. ++The full output remains available in the journal. + + .TP + .B RANDOM_DELAY +diff --git a/man/systemd-crontab-generator.8.in b/man/systemd-crontab-generator.8.in +index f654c59..28f39fc 100644 +--- a/man/systemd-crontab-generator.8.in ++++ b/man/systemd-crontab-generator.8.in +@@ -1,7 +1,7 @@ + .TH SYSTEMD-CRONTAB-GENERATOR 8 "2014-06-29" "{{ package }} {{ version }}" systemd-crontab-generator + + .SH NAME +-systemd-crontab-generator - translate cron schedules in systemd Units ++systemd-crontab-generator - translate cron schedules to systemd units + + .SH SYNOPSIS + {{ libdir }}/systemd/system-generators/systemd-crontab-generator output_folder +diff --git a/src/bin/boot-delay.rs b/src/bin/boot-delay.rs +index d0f3d4a..74e4fdd 100644 +--- a/src/bin/boot-delay.rs ++++ b/src/bin/boot-delay.rs +@@ -1,11 +1,9 @@ ++use std::env; + use std::fs::File; + use std::io::Read; +-use std::mem::transmute; + use std::thread::sleep; +-use std::env; + use std::time::Duration; + +- + fn main() { + let delay = match env::args().nth(1).and_then(|s| s.parse::<f32>().ok()) { + Some(d) => 60.0 * d, +@@ -20,9 +18,15 @@ fn main() { + .and_then(|ref mut file| file.read(&mut buf)) + .map(|sz| { + buf.iter() +- .position(|&c| c == 0x20) +- .and_then(|p| if p < sz { unsafe { transmute::<_, &str>(&buf[..p]) }.parse::<f32>().ok() } else { None }) +- .unwrap() ++ .position(|&c| c == 0x20) ++ .and_then(|p| { ++ if p < sz { ++ std::str::from_utf8(&buf[..p]).unwrap().parse::<f32>().ok() ++ } else { ++ None ++ } ++ }) ++ .unwrap() + }) + .unwrap(); + +diff --git a/src/bin/crontab.rs b/src/bin/crontab.rs +index e47480c..6c8ea63 100644 +--- a/src/bin/crontab.rs ++++ b/src/bin/crontab.rs +@@ -1,40 +1,33 @@ +-extern crate rustc_serialize; ++extern crate cronparse; + extern crate docopt; +-extern crate users; + extern crate glob; +-extern crate tempfile; + extern crate libc; +-extern crate cronparse; ++extern crate nix; ++extern crate rustc_serialize; ++extern crate tempfile; ++extern crate users; + +-use cronparse::{CrontabFile, CrontabFileError}; + use cronparse::crontab::UserCrontabEntry; +-use tempfile::NamedTempFile; ++use cronparse::{CrontabFile, CrontabFileError}; + use docopt::Docopt; +-use users::User; ++use nix::unistd::{chown, Gid, Uid}; + use std::env; + use std::fs; +-use std::io::{self, Read, Write, copy, stderr, stdin, stdout}; + use std::fs::File; ++use std::io::{copy, stderr, stdin, stdout, Read, Write}; + use std::os::unix::fs::PermissionsExt; + use std::path::{Path, PathBuf}; +-use std::process::{Command, exit}; +-use std::ffi::CString; ++use std::process::{exit, Command}; ++use tempfile::NamedTempFile; ++use users::User; + + include!(concat!(env!("OUT_DIR"), "/config.rs")); + +-extern "C" { +- fn chown(path: *const libc::c_char, owner: libc::uid_t, group: libc::gid_t) -> libc::c_int; ++fn change_owner<P: AsRef<Path>>(path: P, owner: libc::uid_t, group: libc::gid_t) -> Result<(), nix::Error> { ++ chown(path.as_ref(), Some(Uid::from_raw(owner)), Some(Gid::from_raw(group))) + } + +-fn change_owner<P: AsRef<Path>>(path: P, owner: libc::uid_t, group: libc::gid_t) -> Result<(), io::Error> { +- match unsafe { chown(CString::new(path.as_ref().to_str().unwrap().as_bytes()).unwrap().as_ptr(), owner, group) } { +- 0 => Ok(()), +- -1 => Err(io::Error::last_os_error()), +- _ => unreachable!(), +- } +-} +- +-static USAGE: &'static str = r#" ++static USAGE: &str = r#" + Usage: crontab [-u <user>] -l + crontab [-u <user>] -e [<file>] + crontab [-u <user>] -s +@@ -81,19 +74,16 @@ struct Args { + } + + fn get_editor() -> Option<String> { +- env::var("EDITOR") +- .ok() +- .or_else(|| env::var("VISUAL").ok()) +- .or_else(|| { +- ["/usr/bin/editor", "/usr/bin/vim", "/usr/bin/nano", "/usr/bin/mcedit"] +- .iter() +- .find(|editor| { +- fs::metadata(editor) +- .map(|meta| meta.is_file() && meta.permissions().mode() & 0o0111 != 0) +- .unwrap_or(false) +- }) +- .map(|&s| s.to_owned()) +- }) ++ env::var("EDITOR").ok().or_else(|| env::var("VISUAL").ok()).or_else(|| { ++ ["/usr/bin/editor", "/usr/bin/vim", "/usr/bin/nano", "/usr/bin/mcedit"] ++ .iter() ++ .find(|editor| { ++ fs::metadata(editor) ++ .map(|meta| meta.is_file() && meta.permissions().mode() & 0o0111 != 0) ++ .unwrap_or(false) ++ }) ++ .map(|&s| s.to_owned()) ++ }) + } + + fn confirm(msg: &str) -> bool { +@@ -107,7 +97,7 @@ fn confirm(msg: &str) -> bool { + Ok(n) if n > 0 && (buf[0] == 121 || buf[0] == 89) => return true, + Ok(n) if n > 0 && (buf[0] == 110 || buf[0] == 78) => return false, + _ => { +- stdout.write_all("Please reply \"y\" or \"n\"\n".as_bytes()).unwrap(); ++ stdout.write_all(b"Please reply \"y\" or \"n\"\n").unwrap(); + } + } + } +@@ -132,10 +122,10 @@ fn remove(cron_file: &Path, cron_user: &User, args: &Args) -> i32 { + if let Err(e) = fs::remove_file(cron_file) { + use std::io::ErrorKind::*; + match e.kind() { +- NotFound => writeln!(stderr, "no crontab for {}", cron_user.name()), +- _ => writeln!(stderr, "failed to remove {}: {}", cron_file.display(), e), +- } +- .unwrap(); ++ NotFound => writeln!(stderr, "no crontab for {}", cron_user.name()), ++ _ => writeln!(stderr, "failed to remove {}: {}", cron_file.display(), e), ++ } ++ .unwrap(); + return 1; + } + } +@@ -211,7 +201,13 @@ fn edit(cron_file: &Path, cron_user: &User, _args: &Args) -> i32 { + } + + if let Err(err) = tmpfile.persist(cron_file) { +- writeln!(stderr, "unexpected error: {}, your edit is kept here: {}", err.error, err.file.path().display()).unwrap(); ++ writeln!( ++ stderr, ++ "unexpected error: {}, your edit is kept here: {}", ++ err.error, ++ err.file.path().display() ++ ) ++ .unwrap(); + return 1; + } + +@@ -246,7 +242,14 @@ fn replace(cron_file: &Path, cron_user: &User, args: &Args) -> i32 { + } + + if let Err(e) = tmpfile.persist(cron_file) { +- writeln!(stderr, "error renaming {} to {}: {}", e.file.path().display(), cron_file.display(), e.error).unwrap(); ++ writeln!( ++ stderr, ++ "error renaming {} to {}: {}", ++ e.file.path().display(), ++ cron_file.display(), ++ e.error ++ ) ++ .unwrap(); + return 1; + } + +@@ -257,39 +260,36 @@ fn replace(cron_file: &Path, cron_user: &User, args: &Args) -> i32 { + + fn main() { + let mut stderr = stderr(); +- let args: Args = Docopt::new(USAGE) +- .and_then(|d| d.decode()) +- .unwrap_or_else(|e| e.exit()); ++ let args: Args = Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|e| e.exit()); + + let cron_user = match args.flag_user { + Some(_) if users::get_current_uid() != 0 => { + writeln!(stderr, "must be privileged to use -u").unwrap(); + exit(1); + } +- Some(ref user) => { +- match users::get_user_by_name(&**user) { +- Some(user) => user, +- None => { +- writeln!(stderr, "unknown user: {}", user).unwrap(); +- exit(1); +- } ++ Some(ref user) => match users::get_user_by_name(&**user) { ++ Some(user) => user, ++ None => { ++ writeln!(stderr, "unknown user: {}", user).unwrap(); ++ exit(1); + } +- } ++ }, + None => users::get_user_by_uid(users::get_current_uid()).unwrap(), + }; + + match fs::metadata(USERS_CRONTAB_DIR) { +- Ok(ref meta) if !meta.is_dir() => { +- writeln!(stderr, "{} is not a directory!", USERS_CRONTAB_DIR).unwrap(); +- exit(1); ++ Ok(ref meta) => { ++ if !meta.is_dir() { ++ writeln!(stderr, "{} is not a directory!", USERS_CRONTAB_DIR).unwrap(); ++ exit(1); ++ } + } + Err(_) => { +- if let Err(_) = fs::create_dir_all(USERS_CRONTAB_DIR) { ++ if fs::create_dir_all(USERS_CRONTAB_DIR).is_err() { + writeln!(stderr, "{} doesn't exist!", USERS_CRONTAB_DIR).unwrap(); + exit(1); + } + } +- _ => (), + } + + let cron_file = PathBuf::from(USERS_CRONTAB_DIR).join(cron_user.name()); +@@ -297,7 +297,11 @@ fn main() { + exit(match args { + Args { flag_show: true, .. } => show(&*cron_file, &cron_user, &args), + Args { flag_list: true, .. } => list(&*cron_file, &cron_user, &args), +- Args { flag_edit: true, arg_file: None, .. } => edit(&*cron_file, &cron_user, &args), ++ Args { ++ flag_edit: true, ++ arg_file: None, ++ .. ++ } => edit(&*cron_file, &cron_user, &args), + Args { flag_edit: true, .. } => replace(&*cron_file, &cron_user, &args), + Args { flag_remove: true, .. } => remove(&*cron_file, &cron_user, &args), + _ => unreachable!(), +@@ -305,7 +309,7 @@ fn main() { + } + + fn check_crontab_syntax<P: AsRef<Path>>(path: P) -> Result<(), CrontabFileError> { +- match try!(CrontabFile::<UserCrontabEntry>::new(path)).find(Result::is_err) { ++ match CrontabFile::<UserCrontabEntry>::new(path)?.find(Result::is_err) { + Some(Err(err)) => Err(err), + _ => Ok(()), + } +diff --git a/src/bin/mail-on-failure.rs b/src/bin/mail-on-failure.rs +index 02f5840..0e61a2d 100644 +--- a/src/bin/mail-on-failure.rs ++++ b/src/bin/mail-on-failure.rs +@@ -1,15 +1,17 @@ +- + use std::env; +-use std::process::{Command, Stdio}; + use std::io::{Result, Write}; ++use std::process::{Command, Stdio}; + + macro_rules! try_log { + ($exp:expr) => { + match $exp { + Ok(v) => v, +- Err(e) => { println!("<3>{}", e); return; } ++ Err(e) => { ++ println!("<3>{}", e); ++ return; ++ } + } +- } ++ }; + } + + fn get_systemd_unit_property(unit: &str, prop: &str) -> Result<String> { +@@ -21,7 +23,7 @@ fn get_systemd_unit_property(unit: &str, prop: &str) -> Result<String> { + .output() + .map(|out| { + String::from_utf8_lossy(&out.stdout[prop.len() + 1..]) +- .trim_right_matches('\n') ++ .trim_end_matches('\n') + .to_owned() + }) + } +@@ -36,11 +38,10 @@ fn main() { + }; + + let mut user = try_log!(get_systemd_unit_property(&*unit, "User")); +- if user.len() == 0 { ++ if user.is_empty() { + user = "root".to_owned(); + } + +- + let job_env = try_log!(get_systemd_unit_property(&*unit, "Environment")); + for pair in job_env.split(' ') { + let mut p = pair.splitn(2, '='); +@@ -52,18 +53,15 @@ fn main() { + } + } + +- if user.len() == 0 { ++ if user.is_empty() { + return; + } + +- let mut hostname = String::from_utf8_lossy(&try_log!(Command::new("uname") +- .arg("-n") +- .output()) +- .stdout[..]) +- .trim_right_matches('\n') ++ let mut hostname = String::from_utf8_lossy(&try_log!(Command::new("uname").arg("-n").output()).stdout[..]) ++ .trim_end_matches('\n') + .to_owned(); + +- if hostname.len() == 0 { ++ if hostname.is_empty() { + hostname = "localhost".to_owned(); + } + +@@ -74,19 +72,17 @@ fn main() { + head.push_str(&*hostname); + head.push_str("] job "); + head.push_str(&*unit); +- head.push_str(r###" failed ++ head.push_str( ++ r###" failed + MIME-Version: 1.0 + Content-Type: text/plain; charset=UTF-8 + Content-Transfer-Encoding: 8bit + Auto-Submitted: auto-generated + +-"###); ++"###, ++ ); + +- let status = Command::new("systemctl") +- .arg("status") +- .arg(&*unit) +- .output() +- .unwrap(); ++ let status = Command::new("systemctl").arg("status").arg(&*unit).output().unwrap(); + + let mut mailer = try_log!(Command::new("sendmail") + .arg("-i") +diff --git a/src/bin/remove-stale-stamps.rs b/src/bin/remove-stale-stamps.rs +index a59b706..e2d761a 100644 +--- a/src/bin/remove-stale-stamps.rs ++++ b/src/bin/remove-stale-stamps.rs +@@ -1,23 +1,25 @@ +-extern crate time; + extern crate glob; ++extern crate time; + ++use std::collections::BTreeSet; + use std::fs::{metadata, remove_file}; +-use std::path::{Path, PathBuf}; + use std::os::unix::fs::MetadataExt; +-use std::collections::BTreeSet; ++use std::path::{Path, PathBuf}; + +-use time::{Duration, get_time}; + use glob::glob; ++use time::{get_time, Duration}; + +-static KNOWN_STAMPS: [&'static str; 6] = ["/var/lib/systemd/timers/stamp-cron-daily.timer", +- "/var/lib/systemd/timers/stamp-cron-weekly.timer", +- "/var/lib/systemd/timers/stamp-cron-monthly.timer", +- "/var/lib/systemd/timers/stamp-cron-quarterly.timer", +- "/var/lib/systemd/timers/stamp-cron-semi-annually.timer", +- "/var/lib/systemd/timers/stamp-cron-yearly.timer"]; ++static KNOWN_STAMPS: [&str; 6] = [ ++ "/var/lib/systemd/timers/stamp-cron-daily.timer", ++ "/var/lib/systemd/timers/stamp-cron-weekly.timer", ++ "/var/lib/systemd/timers/stamp-cron-monthly.timer", ++ "/var/lib/systemd/timers/stamp-cron-quarterly.timer", ++ "/var/lib/systemd/timers/stamp-cron-semi-annually.timer", ++ "/var/lib/systemd/timers/stamp-cron-yearly.timer", ++]; + +-static ACTUAL_STAMPS_GLOB: &'static str = "/var/lib/systemd/timers/stamp-cron-*.timer"; +-static TIMER_STAMPS_GLOB: &'static str = "/run/systemd/generator/cron-*.timer"; ++static ACTUAL_STAMPS_GLOB: &str = "/var/lib/systemd/timers/stamp-cron-*.timer"; ++static TIMER_STAMPS_GLOB: &str = "/run/systemd/generator/cron-*.timer"; + + fn cleanup<P: AsRef<Path>, I: IntoIterator<Item = P>>(iter: I) { + let ten_days_ago = get_time() - Duration::days(10); +@@ -34,18 +36,18 @@ fn main() { + let stale_stamps = &(&glob(ACTUAL_STAMPS_GLOB) + .unwrap() + .flat_map(Result::into_iter) +- .collect::<BTreeSet<_>>() - +- &glob(TIMER_STAMPS_GLOB) +- .unwrap() +- .flat_map(Result::into_iter) +- .map(|s| { +- PathBuf::from(s.to_string_lossy() +- .replace("/run/systemd/generator/cron-", "/var/lib/systemd/timers/stamp-cron-")) +- }) +- .collect::<BTreeSet<_>>()) - +- &KNOWN_STAMPS.iter() +- .map(PathBuf::from) +- .collect::<BTreeSet<_>>(); ++ .collect::<BTreeSet<_>>() ++ - &glob(TIMER_STAMPS_GLOB) ++ .unwrap() ++ .flat_map(Result::into_iter) ++ .map(|s| { ++ PathBuf::from( ++ s.to_string_lossy() ++ .replace("/run/systemd/generator/cron-", "/var/lib/systemd/timers/stamp-cron-"), ++ ) ++ }) ++ .collect::<BTreeSet<_>>()) ++ - &KNOWN_STAMPS.iter().map(PathBuf::from).collect::<BTreeSet<_>>(); + + cleanup(&stale_stamps); + } +diff --git a/src/generate.rs b/src/generate.rs +index 537a6db..fcffef8 100644 +--- a/src/generate.rs ++++ b/src/generate.rs +@@ -1,14 +1,14 @@ +-use std::io::{self, BufRead, Write}; +-use std::fs::{File, create_dir_all, metadata, set_permissions}; ++use std::collections::{BTreeMap, BTreeSet}; ++use std::fs::{create_dir_all, metadata, set_permissions, File}; ++use std::io::{self, Write}; + use std::os::unix::ffi::OsStrExt; +-use std::os::unix::fs::{MetadataExt, PermissionsExt, symlink}; ++use std::os::unix::fs::{symlink, MetadataExt, PermissionsExt}; + use std::path::Path; +-use std::collections::{BTreeMap, BTreeSet}; + +-use cronparse::Limited; + use cronparse::crontab::{CrontabEntry, SystemCrontabEntry, UserCrontabEntry}; +-use cronparse::schedule::{Calendar, Period, Schedule}; + use cronparse::interval::Interval; ++use cronparse::schedule::{Calendar, Period, Schedule}; ++use cronparse::Limited; + + use pgs_files::passwd::{get_entry_by_name, get_entry_by_uid}; + +@@ -19,124 +19,146 @@ pub fn generate_systemd_units(entry: CrontabEntry, env: &BTreeMap<String, String + + info!("generating units for {}: \"{}\", {:?}", path.display(), entry, env); + +- let owner = try!(metadata(path)).uid(); +- +- let mut persistent = env.get("PERSISTENT") +- .and_then(|v| { +- match &**v { +- "yes" | "true" | "1" => Some(true), +- "auto" | "" => None, +- _ => Some(false), +- } +- }) +- .unwrap_or_else(|| { +- match entry { +- Anacron(_) | +- User(UserCrontabEntry { sched: Schedule::Period(_), .. }) | +- System(SystemCrontabEntry { sched: Schedule::Period(_), .. }) => true, +- _ => false, +- } +- }); +- +- let batch = env.get("BATCH") +- .map(|v| { +- match &**v { +- "yes" | "true" | "1" => true, +- _ => false, +- } +- }) +- .unwrap_or(false); ++ let owner = metadata(path)?.uid(); ++ ++ let mut persistent = env ++ .get("PERSISTENT") ++ .and_then(|v| match &**v { ++ "yes" | "true" | "1" => Some(true), ++ "auto" | "" => None, ++ _ => Some(false), ++ }) ++ .unwrap_or_else(|| match entry { ++ Anacron(_) ++ | User(UserCrontabEntry { ++ sched: Schedule::Period(_), ++ .. ++ }) ++ | System(SystemCrontabEntry { ++ sched: Schedule::Period(_), ++ .. ++ }) => true, ++ _ => false, ++ }); ++ ++ let batch = env ++ .get("BATCH") ++ .map(|v| match &**v { ++ "yes" | "true" | "1" => true, ++ _ => false, ++ }) ++ .unwrap_or(false); + + let random_delay = env.get("RANDOM_DELAY").and_then(|v| v.parse::<u64>().ok()).unwrap_or(1); + let mut delay = env.get("DELAY").and_then(|v| v.parse::<u64>().ok()).unwrap_or(0); +- let hour = env.get("START_HOURS_RANGE") +- .and_then(|v| v.splitn(1, '-').next().and_then(|v| v.parse::<u64>().ok())) +- .unwrap_or(0); ++ let hour = env ++ .get("START_HOURS_RANGE") ++ .and_then(|v| v.splitn(1, '-').next().and_then(|v| v.parse::<u64>().ok())) ++ .unwrap_or(0); + let shell = env.get("SHELL").map(|v| &**v).unwrap_or("/bin/sh"); + let daemon_reload = metadata(REBOOT_FILE).map(|m| m.is_file()).unwrap_or(false); + +- let schedule = entry.period() +- .and_then(|period| { +- match *period { +- Period::Reboot => { +- persistent = false; +- if delay == 0 { +- delay = 1; +- } +- None +- } +- Period::Minutely => { +- persistent = false; +- Some("minutely".to_owned()) +- } +- Period::Hourly => if delay == 0 { Some("hourly".to_owned()) } else { Some(format!("*-*-* *:{}:0", delay)) }, +- Period::Midnight => { +- if delay == 0 { Some("daily".to_owned()) } else { Some(format!("*-*-* 0:{}:0", delay)) } +- } +- Period::Daily => { +- if delay == 0 && hour == 0 { +- Some("daily".to_owned()) +- } else { +- Some(format!("*-*-* {}:{}:0", hour, delay)) +- } +- } +- Period::Weekly => { +- if delay == 0 && hour == 0 { +- Some("weekly".to_owned()) +- } else { +- Some(format!("Mon *-*-* {}:{}:0", hour, delay)) +- } +- } +- Period::Monthly => { +- if delay == 0 && hour == 0 { +- Some("monthly".to_owned()) +- } else { +- Some(format!("*-*-1 {}:{}:0", hour, delay)) +- } +- } +- Period::Quaterly => { +- if delay == 0 && hour == 0 { +- Some("quaterly".to_owned()) +- } else { +- Some(format!("*-1,4,7,10-1 {}:{}:0", hour, delay)) +- } +- } +- Period::Biannually => { +- if delay == 0 && hour == 0 { +- Some("semiannually".to_owned()) +- } else { +- Some(format!("*-1,7-1 {}:{}:0", hour, delay)) +- } +- } +- Period::Yearly => { +- if delay == 0 && hour == 0 { +- Some("yearly".to_owned()) +- } else { +- Some(format!("*-1-1 {}:{}:0", hour, delay)) +- } +- } +- Period::Days(days) => { +- // workaround for anacrontab +- if days > 31 { +- Some(format!("*-1/{}-1 {}:{}:0", days / 30, hour, delay)) +- } else { +- Some(format!("*-*-1/{} {}:{}:0", days, hour, delay)) +- } +- } +- } +- }) +- .or_else(|| { +- entry.calendar().and_then(|cal| { +- let Calendar { ref dows, ref days, ref mons, ref hrs, ref mins } = *cal; +- +- Some(format!("{} *-{}-{} {}:{}:00", +- linearize(&**dows, "", ToString::to_string), +- linearize(&**mons, "*", |&mon| (mon as u8).to_string()), +- linearize(&**days, "*", ToString::to_string), +- linearize(&**hrs, "*", ToString::to_string), +- linearize(&**mins, "*", ToString::to_string))) +- }) +- }); ++ let schedule = entry ++ .period() ++ .and_then(|period| { ++ match *period { ++ Period::Reboot => { ++ persistent = false; ++ if delay == 0 { ++ delay = 1; ++ } ++ None ++ } ++ Period::Minutely => { ++ persistent = false; ++ Some("minutely".to_owned()) ++ } ++ Period::Hourly => { ++ if delay == 0 { ++ Some("hourly".to_owned()) ++ } else { ++ Some(format!("*-*-* *:{}:0", delay)) ++ } ++ } ++ Period::Midnight => { ++ if delay == 0 { ++ Some("daily".to_owned()) ++ } else { ++ Some(format!("*-*-* 0:{}:0", delay)) ++ } ++ } ++ Period::Daily => { ++ if delay == 0 && hour == 0 { ++ Some("daily".to_owned()) ++ } else { ++ Some(format!("*-*-* {}:{}:0", hour, delay)) ++ } ++ } ++ Period::Weekly => { ++ if delay == 0 && hour == 0 { ++ Some("weekly".to_owned()) ++ } else { ++ Some(format!("Mon *-*-* {}:{}:0", hour, delay)) ++ } ++ } ++ Period::Monthly => { ++ if delay == 0 && hour == 0 { ++ Some("monthly".to_owned()) ++ } else { ++ Some(format!("*-*-1 {}:{}:0", hour, delay)) ++ } ++ } ++ Period::Quaterly => { ++ if delay == 0 && hour == 0 { ++ Some("quaterly".to_owned()) ++ } else { ++ Some(format!("*-1,4,7,10-1 {}:{}:0", hour, delay)) ++ } ++ } ++ Period::Biannually => { ++ if delay == 0 && hour == 0 { ++ Some("semiannually".to_owned()) ++ } else { ++ Some(format!("*-1,7-1 {}:{}:0", hour, delay)) ++ } ++ } ++ Period::Yearly => { ++ if delay == 0 && hour == 0 { ++ Some("yearly".to_owned()) ++ } else { ++ Some(format!("*-1-1 {}:{}:0", hour, delay)) ++ } ++ } ++ Period::Days(days) => { ++ // workaround for anacrontab ++ if days > 31 { ++ Some(format!("*-1/{}-1 {}:{}:0", days / 30, hour, delay)) ++ } else { ++ Some(format!("*-*-1/{} {}:{}:0", days, hour, delay)) ++ } ++ } ++ } ++ }) ++ .or_else(|| { ++ entry.calendar().and_then(|cal| { ++ let Calendar { ++ ref dows, ++ ref days, ++ ref mons, ++ ref hrs, ++ ref mins, ++ } = *cal; ++ ++ Some(format!( ++ "{} *-{}-{} {}:{}:00", ++ linearize(&**dows, "", ToString::to_string), ++ linearize(&**mons, "*", |&mon| (mon as u8).to_string()), ++ linearize(&**days, "*", ToString::to_string), ++ linearize(&**hrs, "*", ToString::to_string), ++ linearize(&**mins, "*", ToString::to_string) ++ )) ++ }) ++ }); + + if daemon_reload && schedule.is_none() { + warn!("skipping job from {}: \"{}\"", path.display(), entry); +@@ -144,12 +166,12 @@ pub fn generate_systemd_units(entry: CrontabEntry, env: &BTreeMap<String, String + } + + if let Some(cmd) = entry.command() { +- + // make sure we know the user +- let user = try!(entry.user() +- .and_then(get_entry_by_name) +- .or_else(|| get_entry_by_uid(owner)) +- .ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "unknown user"))); ++ let user = entry ++ .user() ++ .and_then(get_entry_by_name) ++ .or_else(|| get_entry_by_uid(owner)) ++ .ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "unknown user"))?; + + // generate unique cron job id + let mut md5ctx = ::md5::Context::new(); +@@ -170,7 +192,7 @@ pub fn generate_systemd_units(entry: CrontabEntry, env: &BTreeMap<String, String + + // make sure cron.target.wants dir exists + let cron_target_wants_path = dstdir.join("cron.target.wants"); +- try!(create_dir_all(&cron_target_wants_path)); ++ create_dir_all(&cron_target_wants_path)?; + + // process command in case it should be put into script + let command = if metadata(cmd).map(|m| m.is_file()).unwrap_or(false) { +@@ -180,22 +202,24 @@ pub fn generate_systemd_units(entry: CrontabEntry, env: &BTreeMap<String, String + + debug!("generating script {:?} from {:?}", script_command_path, path); + { +- let mut script_command_file = try!(File::create(&script_command_path)); +- try!(writeln!(script_command_file, "#!{}", shell)); +- try!(writeln!(script_command_file, "{}", cmd)); ++ let mut script_command_file = File::create(&script_command_path)?; ++ writeln!(script_command_file, "#!{}", shell)?; ++ writeln!(script_command_file, "{}", cmd)?; + } + +- let mut perms = try!(metadata(&script_command_path)).permissions(); ++ let mut perms = metadata(&script_command_path)?.permissions(); + perms.set_mode(0o755); +- try!(set_permissions(&script_command_path, perms)); ++ set_permissions(&script_command_path, perms)?; + script_command_path.to_str().unwrap().to_owned() + }; + + debug!("generating service {:?} from {:?}", service_unit_path, path); + { +- let mut service_unit_file = try!(File::create(service_unit_path)); ++ let mut service_unit_file = File::create(service_unit_path)?; + +- try!(writeln!(service_unit_file, r###"[Unit] ++ writeln!( ++ service_unit_file, ++ r###"[Unit] + Description=[Cron] "{entry}" + Documentation=man:systemd-crontab-generator(8) + RefuseManualStart=true +@@ -203,55 +227,60 @@ RefuseManualStop=true + SourcePath={source_crontab_path}"###, + entry = entry, + source_crontab_path = path.display(), +- )); ++ )?; + + if env.contains_key("MAILTO") { +- try!(writeln!(service_unit_file, "OnFailure=cron-failure@%i.service")); ++ writeln!(service_unit_file, "OnFailure=cron-failure@%i.service")?; + } + + if user.uid != 0 { +- try!(writeln!(service_unit_file, "Requires=systemd-user-sessions.service")); ++ writeln!(service_unit_file, "Requires=systemd-user-sessions.service")?; + if !user.dir.is_empty() { +- try!(writeln!(service_unit_file, "RequiresMountsFor={}", user.dir)); ++ writeln!(service_unit_file, "RequiresMountsFor={}", user.dir)?; + } + } + +- try!(writeln!(service_unit_file, r###" ++ writeln!( ++ service_unit_file, ++ r###" + [Service] + Type=oneshot + IgnoreSIGPIPE=false + ExecStart={command}"###, + command = command, +- )); ++ )?; + + if schedule.is_some() && delay > 0 { +- try!(writeln!(service_unit_file, "ExecStartPre=-{}/{}/boot-delay {}", LIB_DIR, PACKAGE, delay)); ++ writeln!(service_unit_file, "ExecStartPre=-{}/{}/boot-delay {}", LIB_DIR, PACKAGE, delay)?; + } + + if user.uid != 0 { +- try!(writeln!(service_unit_file, "User={}", user.name)); ++ writeln!(service_unit_file, "User={}", user.name)?; ++ writeln!(service_unit_file, "WorkingDirectory=~")?; + } + + if let Some(group) = entry.group() { +- try!(writeln!(service_unit_file, "Group={}", group)); ++ writeln!(service_unit_file, "Group={}", group)?; + } + if batch { +- try!(writeln!(service_unit_file, "CPUSchedulingPolicy=idle")); +- try!(writeln!(service_unit_file, "IOSchedulingClass=idle")); ++ writeln!(service_unit_file, "CPUSchedulingPolicy=idle")?; ++ writeln!(service_unit_file, "IOSchedulingClass=idle")?; + } + + if !env.is_empty() { + for (name, value) in env.iter() { +- try!(writeln!(service_unit_file, r#"Environment="{}={}""#, name, value)); ++ writeln!(service_unit_file, r#"Environment="{}={}""#, name, value)?; + } + } + } + + debug!("generating timer {:?} from {:?}", timer_unit_path, path); + { +- let mut timer_unit_file = try!(File::create(&timer_unit_path)); ++ let mut timer_unit_file = File::create(&timer_unit_path)?; + +- try!(writeln!(timer_unit_file, r###"[Unit] ++ writeln!( ++ timer_unit_file, ++ r###"[Unit] + Description=[Timer] "{entry}" + Documentation=man:systemd-crontab-generator(8) + PartOf=cron.target +@@ -264,35 +293,36 @@ Unit={service_unit_name}"###, + entry = entry, + source_crontab_path = path.display(), + service_unit_name = service_unit_name, +- )); ++ )?; + + if cfg![feature = "persistent"] { +- try!(writeln!(timer_unit_file, "Persistent={}", persistent)); ++ writeln!(timer_unit_file, "Persistent={}", persistent)?; + } + + if let Some(schedule) = schedule { +- try!(writeln!(timer_unit_file, "OnCalendar={}", schedule)); ++ writeln!(timer_unit_file, "OnCalendar={}", schedule)?; + } else { +- try!(writeln!(timer_unit_file, "OnBootSec={}m", delay)); ++ writeln!(timer_unit_file, "OnBootSec={}m", delay)?; + } + + if random_delay != 1 { +- if cfg!(feature="randomized-delay") { +- try!(writeln!(timer_unit_file, "RandomizedDelaySec={}m", random_delay)); ++ if cfg!(feature = "randomized-delay") { ++ writeln!(timer_unit_file, "RandomizedDelaySec={}m", random_delay)?; + } else { +- try!(writeln!(timer_unit_file, "AccuracySec={}m", random_delay)); ++ writeln!(timer_unit_file, "AccuracySec={}m", random_delay)?; + } + } + } +- try!(symlink(timer_unit_path, cron_target_wants_path.join(timer_unit_name))); ++ symlink(timer_unit_path, cron_target_wants_path.join(timer_unit_name))?; + } + + Ok(()) + } + + fn linearize<T, C>(input: &[Interval<T>], star: &str, conv: C) -> String +- where T: Limited, +- C: Fn(&T) -> String ++where ++ T: Limited, ++ C: Fn(&T) -> String, + { + if input.len() == 1 && input[0] == Interval::Full(1) { + star.to_owned() +@@ -311,14 +341,14 @@ fn tohex(input: &[u8]) -> String { + #[inline] + fn hex(d: u8) -> char { + match d { +- 0...9 => (d + 0x30) as char, +- 10...15 => (d + 0x57) as char, ++ 0..=9 => (d + 0x30) as char, ++ 10..=15 => (d + 0x57) as char, + _ => unreachable!("unexpected value: {}", d), + } + } + + let mut buf = String::with_capacity(32); +- for b in input.into_iter() { ++ for b in input { + buf.push(hex(b >> 4)); + buf.push(hex(b & 0xf)); + } +diff --git a/src/main.rs b/src/main.rs +index ab2cb26..67b6b4e 100644 +--- a/src/main.rs ++++ b/src/main.rs +@@ -7,12 +7,13 @@ extern crate pgs_files; + extern crate log; + extern crate kernlog; + +-use std::thread::spawn; + use std::env; +-use std::fs::{File, create_dir_all, metadata}; ++use std::fs::{create_dir_all, metadata, File}; ++use std::io::{self, Error, Write}; + use std::os::unix::fs::symlink; +-use std::io::Write; + use std::path::Path; ++use std::process::exit; ++use std::thread::spawn; + + use cronparse::crontab::{AnacrontabEntry, SystemCrontabEntry, UserCrontabEntry}; + +@@ -20,27 +21,18 @@ mod generate; + mod process; + + include!(concat!(env!("OUT_DIR"), "/config.rs")); +-static SYSTEM_CRONTAB_DIR: &'static str = "/etc/cron.d"; // SystemCrontabEntry +-static SYSTEM_CRONTAB_FILE: &'static str = "/etc/crontab"; +-static ANACRONTAB_FILE: &'static str = "/etc/anacrontab"; // AnacrontabEntry +-static REBOOT_FILE: &'static str = "/run/crond.reboot"; +- +-macro_rules! try_ { +- ($exp:expr) => { +- match $exp { +- Ok(value) => value, +- Err(err) => { error!("{}", err); return; } +- } +- } +-} ++static SYSTEM_CRONTAB_DIR: &str = "/etc/cron.d"; // SystemCrontabEntry ++static SYSTEM_CRONTAB_FILE: &str = "/etc/crontab"; ++static ANACRONTAB_FILE: &str = "/etc/anacrontab"; // AnacrontabEntry ++static REBOOT_FILE: &str = "/run/crond.reboot"; + +-fn main() { ++fn main() -> Result<(), Error> { + log::set_logger(|filter| kernlog::KernelLog::init_level(log::LogLevelFilter::Error, filter)).unwrap(); + + let dest_dir = match env::args().nth(1) { + None => { + println!("Usage: systemd-crontab-generator <destination-directory>"); +- return; ++ exit(1); + } + Some(path) => path, + }; +@@ -53,6 +45,7 @@ fn main() { + + process::process_crontab_dir::<UserCrontabEntry, _>(USERS_CRONTAB_DIR, s); + create_reboot_lock_file(); ++ Ok(()) + }); + + let s = dest_dir.clone(); +@@ -61,7 +54,7 @@ fn main() { + process::process_crontab_dir::<SystemCrontabEntry, _>(SYSTEM_CRONTAB_DIR, &s); + }); + +- let s = dest_dir.clone(); ++ let s = dest_dir; + let anacron_thread = spawn(move || { + process::process_crontab_file::<AnacrontabEntry, _, _>(ANACRONTAB_FILE, &s); + }); +@@ -69,13 +62,16 @@ fn main() { + let _ = user_thread.join(); + let _ = system_thread.join(); + let _ = anacron_thread.join(); ++ ++ Ok(()) + } + +-fn generate_after_var_unit(dest_dir: &str) { ++fn generate_after_var_unit(dest_dir: &str) -> Result<(), io::Error> { + let cron_after_var_unit_path = Path::new(dest_dir).join("cron-after-var.service"); +- let mut cron_after_var_unit_file = try_!(File::create(&cron_after_var_unit_path)); +- try_!(writeln!(cron_after_var_unit_file, +- r###"[Unit] ++ let mut cron_after_var_unit_file = File::create(&cron_after_var_unit_path)?; ++ writeln!( ++ cron_after_var_unit_file, ++ r###"[Unit] + Description=Rerun systemd-crontab-generator because /var is a separate mount + Documentation=man:systemd.cron(7) + After=cron.target +@@ -84,12 +80,14 @@ ConditionDirectoryNotEmpty={statedir} + [Service] + Type=oneshot + ExecStart=/bin/sh -c "{bindir}/systemctl daemon-reload ; {bindir}/systemctl try-restart cron.target""###, +- statedir = USERS_CRONTAB_DIR, +- bindir = BIN_DIR)); ++ statedir = USERS_CRONTAB_DIR, ++ bindir = BIN_DIR ++ )?; + + let multiuser_wants_path = Path::new(dest_dir).join("multi-user.target.wants"); +- try_!(create_dir_all(&multiuser_wants_path)); +- try_!(symlink(cron_after_var_unit_path, multiuser_wants_path.join("cron-after-var.service"))); ++ create_dir_all(&multiuser_wants_path)?; ++ symlink(cron_after_var_unit_path, multiuser_wants_path.join("cron-after-var.service"))?; ++ Ok(()) + } + + fn create_reboot_lock_file() { +diff --git a/src/process.rs b/src/process.rs +index 2fb89da..abddd7b 100644 +--- a/src/process.rs ++++ b/src/process.rs +@@ -1,30 +1,30 @@ ++use std::collections::BTreeMap; + use std::convert::AsRef; + use std::fs::{metadata, read_dir}; + use std::path::{Path, PathBuf}; +-use std::collections::BTreeMap; + use std::str::FromStr; + +-use cronparse::{CrontabFile, CrontabFileError, CrontabFileErrorKind}; + use cronparse::crontab::{CrontabEntry, EnvVarEntry}; ++use cronparse::{CrontabFile, CrontabFileError, CrontabFileErrorKind}; + +-use generate::generate_systemd_units; ++use crate::generate::generate_systemd_units; + + pub fn process_crontab_dir<T: FromStr, D: AsRef<Path>>(srcdir: &str, dstdir: D) +- where CrontabEntry: From<T>, +- CrontabFileError: From<<T as FromStr>::Err> ++where ++ CrontabEntry: From<T>, ++ CrontabFileError: From<<T as FromStr>::Err>, + { + let files = read_dir(srcdir).and_then(|fs| { + fs.map(|r| r.map(|p| p.path())) +- .filter(|r| { +- r.as_ref() +- .map(|p| { +- !p.file_name() +- .and_then(|n| n.to_str().map(|n| n.starts_with("."))) +- .unwrap_or(true) && metadata(p).map(|m| m.is_file()).unwrap_or(true) +- }) +- .unwrap_or(true) +- }) +- .collect::<Result<Vec<PathBuf>, _>>() ++ .filter(|r| { ++ r.as_ref() ++ .map(|p| { ++ !p.file_name().and_then(|n| n.to_str().map(|n| n.starts_with('.'))).unwrap_or(true) ++ && metadata(p).map(|m| m.is_file()).unwrap_or(true) ++ }) ++ .unwrap_or(true) ++ }) ++ .collect::<Result<Vec<PathBuf>, _>>() + }); + match files { + Err(err) => warn!("error processing directory {}: {}", srcdir, err), +@@ -37,8 +37,9 @@ pub fn process_crontab_dir<T: FromStr, D: AsRef<Path>>(srcdir: &str, dstdir: D) + } + + pub fn process_crontab_file<T: FromStr, P: AsRef<Path>, D: AsRef<Path>>(path: P, dstdir: D) +- where CrontabEntry: From<T>, +- CrontabFileError: From<<T as FromStr>::Err> ++where ++ CrontabEntry: From<T>, ++ CrontabFileError: From<<T as FromStr>::Err>, + { + CrontabFile::<T>::new(path.as_ref()) + .map(|crontab| { +@@ -48,18 +49,26 @@ pub fn process_crontab_file<T: FromStr, P: AsRef<Path>, D: AsRef<Path>>(path: P, + Ok(CrontabEntry::EnvVar(EnvVarEntry(name, value))) => { + env.insert(name, value); + } +- Ok(data) => { +- match generate_systemd_units(data, &env, path.as_ref(), dstdir.as_ref()) { +- Ok(_) => (), +- Err(err) => warn!("error generating unit from {}: {}", path.as_ref().display(), err), +- } +- } +- Err(err @ CrontabFileError { kind: CrontabFileErrorKind::Io(_), .. }) => { +- warn!("error accessing file {}: {}", path.as_ref().display(), err) +- } +- Err(err @ CrontabFileError { kind: CrontabFileErrorKind::Parse(_), .. }) => { +- warn!("skipping file {} due to parsing error: {}", path.as_ref().display(), err) +- } ++ Ok(data) => match generate_systemd_units(data, &env, path.as_ref(), dstdir.as_ref()) { ++ Ok(_) => (), ++ Err(err) => warn!("error generating unit from {}: {}", path.as_ref().display(), err), ++ }, ++ Err( ++ err ++ @ ++ CrontabFileError { ++ kind: CrontabFileErrorKind::Io(_), ++ .. ++ }, ++ ) => warn!("error accessing file {}: {}", path.as_ref().display(), err), ++ Err( ++ err ++ @ ++ CrontabFileError { ++ kind: CrontabFileErrorKind::Parse(_), ++ .. ++ }, ++ ) => warn!("skipping file {} due to parsing error: {}", path.as_ref().display(), err), + } + } + }) diff --git a/0002-makefile.patch b/0002-makefile.patch new file mode 100644 index 000000000000..89562217de44 --- /dev/null +++ b/0002-makefile.patch @@ -0,0 +1,40 @@ +diff --git a/Makefile.in b/Makefile.in +index 147b0c8..7fe3a69 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -33,7 +33,7 @@ out_units := $(out_services) $(out_timers) $(out_targets) $(builddir)/units/cro + $(builddir)/units/cron-update.path $(builddir)/units/cron-update.service \ + $(builddir)/units/cron-failure@.service + out_manuals := $(patsubst $(CURDIR)/man/%.in,$(builddir)/man/%,$(wildcard $(CURDIR)/man/*)) +-out_programs := $(patsubst $(srcdir)/bin/%.rs,$(builddir)/bin/%,$(wildcard $(srcdir)/bin/*.rs)) ++out_programs := $(patsubst $(srcdir)/bin/%.rs,$(builddir)/release/%,$(wildcard $(srcdir)/bin/*.rs)) + outputs := $(out_units) $(out_manuals) $(out_programs) + + define \n +@@ -65,19 +65,19 @@ test: all + cargo test + + build: all +- test -f $(builddir)/bin/systemd-crontab-generator || \ ++ test -f $(builddir)/release/systemd-crontab-generator || \ + PREFIX="$(prefix)" RUN_PARTS="$(runparts)" STATE_DIR="$(statedir)" \ + BIN_DIR="$(bindir)" CONF_DIR="$(confdir)" MAN_DIR="$(mandir)" DOC_DIR="$(docdir)" \ + DATA_DIR="$(datadir)" LIB_DIR="$(libdir)" UNIT_DIR="$(unitdir)" \ +- cargo install --path $(CURDIR) --root $(builddir) \ ++ cargo build --release --target-dir=$(builddir) \ + --features "$(foreach schedule,$(schedules),sched-$(schedule)) $(persistent) $(randomized_delay)" + + install: build +- install -m2755 -g `getent group cron || echo root` $(strip) -D $(builddir)/bin/crontab $(DESTDIR)$(bindir)/crontab +- install -m755 $(strip) -D $(builddir)/bin/systemd-crontab-generator $(DESTDIR)$(libdir)/systemd/system-generators/systemd-crontab-generator +- install -m755 $(strip) -D $(builddir)/bin/remove-stale-stamps $(DESTDIR)$(libdir)/$(packagedir)/remove-stale-stamps +- install -m755 $(strip) -D $(builddir)/bin/mail-on-failure $(DESTDIR)$(libdir)/$(packagedir)/mail-on-failure +- install -m755 $(strip) -D $(builddir)/bin/boot-delay $(DESTDIR)$(libdir)/$(packagedir)/boot-delay ++ install -m2755 -g `getent group cron || echo root` $(strip) -D $(builddir)/release/crontab $(DESTDIR)$(bindir)/crontab ++ install -m755 $(strip) -D $(builddir)/release/systemd-crontab-generator $(DESTDIR)$(libdir)/systemd/system-generators/systemd-crontab-generator ++ install -m755 $(strip) -D $(builddir)/release/remove-stale-stamps $(DESTDIR)$(libdir)/$(packagedir)/remove-stale-stamps ++ install -m755 $(strip) -D $(builddir)/release/mail-on-failure $(DESTDIR)$(libdir)/$(packagedir)/mail-on-failure ++ install -m755 $(strip) -D $(builddir)/release/boot-delay $(DESTDIR)$(libdir)/$(packagedir)/boot-delay + + install -m644 -D $(builddir)/man/systemd.cron.7 $(DESTDIR)$(mandir)/man7/systemd.cron.7 + install -m644 -D $(builddir)/man/crontab.1 $(DESTDIR)$(mandir)/man1/crontab.1 @@ -1,36 +1,96 @@ -# Maintainer: Konstantin Stepanov <me@kstep.me> -pkgname=systemd-cron-next -pkgver=1.0.2 -_gitver=1.0.2 -pkgrel=2 -pkgdesc="systemd generator to generate timers/services from crontab and anacrontab files" -url="https://github.com/systemd-cron/systemd-cron-next" +# Maintainer: +# Contributor: Ahmad Hasan Mubashshir <ahmubashshir@gmail.com> +# Contributor: Konstantin Stepanov <me@kstep.me> + +_pkgname="systemd-cron-next" +pkgname="$_pkgname" +pkgver=1.0.2.r18.gd69afa9 +pkgrel=1 +pkgdesc="Systemd generator to generate timers/services from crontab and anacrontab files" arch=('i686' 'x86_64') +url="https://github.com/systemd-cron/systemd-cron-next" license=('MIT') -depends=('systemd>=217' 'run-parts') -optdepends=('smtp-forwarder: sending emails') -makedepends=('rust>=1.4.0' 'cargo>=0.6.0') -provides=('cron' 'anacron') -conflicts=('cron' 'anacron') -replaces=('cron' 'anacron') -source=("https://github.com/systemd-cron/systemd-crontab-generator/archive/v${_gitver}.zip") -md5sums=('975aa9d302ea5b2785fec52dff1b8eac') -build() { - cd "${srcdir}/${pkgname}-${_gitver}" - if which multirust; then - multirust override stable - else - if which rustup; then - rustup override add stable - fi +depends=( + 'run-parts' + 'systemd' +) +makedepends=( + 'rust' +) +optdepends=( + 'smtp-forwarder: sending emails' +) + +provides=( + 'anacron' + 'cron' + 'systemd-cron' +) +conflicts=( + 'anacron' + 'cron' +) + +source=( + "0002-makefile.patch" +) +sha256sums=( + '095f20fd780717da18c0251df0ff702a5953816120f3040a317ccc9dc3e1572b' +) + +if [ x"$pkgname" == x"$_pkgname" ] ; then + # normal package + _pkgsrc="$_pkgname-${pkgver%.r*}" + _pkgext="zip" + source+=( + "0001-d69afa94.patch" + "$_pkgsrc.$_pkgext"::"https://github.com/systemd-cron/systemd-crontab-generator/archive/v${pkgver%.r*}.$_pkgext" + ) + sha256sums+=( + '236cbbaa3cc56176874d96162ba49c5f642615596f9d50056c04ed65347fbf80' + '455d1ea09ecb29efaec44255f6439794d2118d63133936b389fd3afd9c60cc2f' + ) +else + # git package + makedepends+=('git') + + provides+=("$_pkgname") + conflicts+=("$_pkgname") + + _pkgsrc="$_pkgname" + source+=( + "$_pkgsrc"::"git+$url.git" + ) + sha256sums+=( + 'SKIP' + ) + + pkgver() { + cd "$_pkgsrc" + git describe --long --tags | sed -E 's/^v//;s/([^-]*-g)/r\1/;s/-/./g' + } +fi + +prepare() { + cd "$_pkgsrc" + + for patch in "$srcdir"/*.patch ; do + if [ -f "$patch" ] ; then + printf 'Applying patch: %s\n' "${patch##*/}" + patch -Np1 -F100 -i "$patch" fi - ./configure --prefix="/usr" --confdir="/etc" - DESTDIR="${pkgdir}" make build + done +} + +build() { + cd "$_pkgsrc" + ./configure --prefix="/usr" --confdir="/etc" + DESTDIR="${pkgdir:?}" make build } package() { - cd "${srcdir}/${pkgname}-${_gitver}" - DESTDIR="${pkgdir}" make install - install -d -m 775 ${pkgdir}/var/spool/cron + cd "$_pkgsrc" + DESTDIR="${pkgdir:?}" make install + install -d -m 775 "${pkgdir:?}/var/spool/cron" } |