解决Crontab内apt-get -y upgrade不正常工作的问题(Debian)

一、现象描述

系统:Debian 3.16.39-1+deb8u2 (2017-03-07) x86_64 GNU/Linux

如果用户执行

crontab -e

并将

apt-get -y upgrade

作为一项任务,放入cron文档,系统并不会根据设置定时升级。如果用户导出升级命令的提示,可以看到,不能升级的原因是下面这个错误:

Note: root's PATH should usually contain /usr/local/sbin, /usr/sbin and /sbin
E: Sub-process /usr/bin/dpkg returned an error code (2)

由于Crontab任务是由root用户执行的,执行

echo $PATH

的结果是:

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

换言之,上述3个被报告称缺失的路径/usr/local/sbin, /usr/sbin 和 /sbin都是存在于环境变量里面的。

二、原因

造成这个问题的原因是,实际上,执行crontab -e命令打开的文件,是存放于“/var/spool/cron/crontabs/”路径下的文件。如果执行crontab -e的用户是root,那么文件名就会是:/var/spool/cron/crontabs/root。打开这个文件,其默认结构如下:

# Edit this file to introduce tasks to be run by cron.
#
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
#
# To define the time you can provide concrete values for
# minute (m), hour (h), day of month (dom), month (mon),
# and day of week (dow) or use '*' in these fields (for 'any').#
# Notice that tasks will be started based on the cron's system
# daemon's notion of time and timezones.
#
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
#
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
#
# For more information see the manual pages of crontab(5) and cron(8)
#
# m h dom mon dow command

与此对应的是, /etc/ crontab的默认文件结构如下:

# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# m h dom mon dow user command
17 * * * * root cd / && run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
#

可以看出,两者至少存在三处显著不同。第一个是:前者的注释比后者要长很多;第二个是:后者包含了四条默认任务;第三个是:后者定义了两个环境标量。这是由于第三个的不同,导致了

apt-get -y upgrade

在前者配置文件中无法正确执行。

三、解决方案

显然,最简单的解决方案是把/etc/ crontab文件里面关于环境变量的定义粘贴到/var/spool/cron/crontabs/root文件里。然而,这样做就不够符合“最小权限原则”了:因为Debian的设计就是用户自己的crontab文件不需要环境变量,如果直接将环境变量放入文件,相当于给其他不需要该变量的命令也开放了该变量。因此,更合理的做法是,将环境变量直接贴到需要他们的命令的前面,如下:

32 16 * * * PATH='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' apt-get -y upgrade

这样一来,就可以避免开放权限给不需要该权限的程序,同时给需要的程序提供必要的权限。

四、参考

本文主要参考了此网友的研究结果并对他的研究过程做了简化(只有英文版):https://serverfault.com/questions/644460/apt-get-y-upgrade-in-cron-task-runs-but-does-not-upgrade-the-system

发表评论

电子邮件地址不会被公开。 必填项已用*标注