Skip to content

crontab rewrite cannot tell "no crontab" from "could not read crontab" #41

Description

@PeGa

What happens

Every function that edits the crontab uses this shape:

crontab -l 2>/dev/null | grep -vF "$nudge_bin" > "$tmp" || true
crontab "$tmp"

crontab -l exits non-zero in two very different situations:

  1. there is no crontab yet — normal, and the intended case for || true;
  2. the crontab could not be read — spool permissions, a broken cron install, a filesystem problem.

Both produce an empty $tmp, which is then installed — replacing the user's entire crontab with nothing.

Reproduction

With a shim whose -l fails for a reason other than "no crontab":

cat > bin/crontab <<'SH'
#!/usr/bin/env bash
if [[ "$1" == "-l" ]]; then echo "crontab: cannot read: I/O error" >&2; exit 1; fi
echo "INSTALLED CONTENT:"; cat "$1"
SH

PATH="bin:$PATH" bash -c 'source env.sh; source services/cron.sh; cron_remove'
# INSTALLED CONTENT:
#          <- empty. every entry the user had is gone

Honest scoping

I could not construct a realistic trigger on a healthy system — on a working box crontab -l fails only when there is no crontab, which is exactly the case the code handles correctly. This is hardening, not an observed failure.

It is worth doing anyway because the data at risk is not refocus's: it is every unrelated cron job the user has. And the code path runs often — enable, disable, reset, import, and setup.sh install all rewrite the crontab.

Suggested fix

Capture output and status separately and only treat an empty read as legitimate:

existing=$(crontab -l 2>/dev/null) || existing=""
# proceed only when the failure really was "no crontab" (empty output);
# otherwise refuse to write and say so, rather than installing an empty file

Location

services/cron.shcron_install, cron_remove, cron_checkin_install, cron_checkin_remove. Same shape in setup.sh:88-91.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions