summarylogtreecommitdiffstats
path: root/crontab
blob: 5b95d32ae58fb2710587d2c4e95209b91dea1c43 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#!/usr/bin/python2

import tempfile
import sys
import os
import argparse
import getpass

EDITOR = (os.environ.get('EDITOR') or
	  os.environ.get('VISUAL','/usr/bin/vim'))
CRONTAB_DIR = '/var/spool/cron'

args_parser = argparse.ArgumentParser(description='maintain crontab files for individual users')

args_parser.add_argument('-u', '--user', type=str, dest='user', default=getpass.getuser(),
        help='''It specifies the name of the user whose crontab is to be
 tweaked. If this option is not given, crontab examines "your" crontab, i.e., the crontab of the person
 executing the command. Note that su(8) can confuse crontab and that if you are running inside of su(8) you
 should always use the -u option for safety's sake. The first form of this command is used to install a new
 crontab from some named file or standard input if the pseudo-filename "-" is given.''')

args_parser.add_argument('file', type=str, default='-', nargs='?')

args_parser.add_argument('-l', '--list', dest='action', action='store_const', const='list',
        help='''The current crontab will be displayed on standard output.''')

args_parser.add_argument('-r', '--remove', dest='action', action='store_const', const='remove',
        help='''The current crontab will be removed.''')

args_parser.add_argument('-e', '--edit', dest='action', action='store_const', const='edit',
        help='''This option is used to edit the current crontab using the editor
 specified by the VISUAL or EDITOR environment variables. After
 you exit from the editor, the modified crontab will be installed
 automatically.''')

args_parser.add_argument('-i', '--ask', dest='ask', action='store_true', default=False,
        help='''This option modifies the -r option to prompt the user for a
 'y/Y' response before actually removing the crontab.''')

#args_parser.add_argument('-s', '--secure', dest='secure', action='store_true', default=False,
        #help='''It will append the current SELinux security context string as an
 #MLS_LEVEL setting to the crontab file before editing / replacement occurs
 #- see the documentation of MLS_LEVEL in crontab(5).''')

def confirm(message):
    while True:
        answer = raw_input(message).lower()
        if answer not in 'yn':
            print('Please reply "y" or "n"')
            continue

        return answer == 'y'

def list(cron_file, args):
    with open(cron_file, 'r') as f:
        sys.stdout.write(f.read())

def remove(cron_file, args):
    if not args.ask or confirm('Are you sure you want to delete %s (y/n)? ' % cron_file):
        os.unlink(cron_file)

def edit(cron_file, args):
    with tempfile.NamedTemporaryFile() as tmp:
        with open(cron_file, 'r') as inp:
            tmp.file.write(inp.read())

        tmp.file.flush()

        if os.system("'%s' '%s'" % (EDITOR, tmp.name)) == 0:
            tmp.file.seek(0)
            with open(cron_file, 'w') as out:
                out.write(tmp.file.read())

def replace(cron_file, args):
    infile = args.file
    if infile == '-':
        with open(cron_file, 'w') as out:
            out.write(sys.stdin.read())

    else:
        with open(cron_file, 'w'), open(infile, 'r') as out, inp:
            out.write(inp.read())

if __name__ == '__main__':
    args = args_parser.parse_args()
    cron_file = os.path.join(CRONTAB_DIR, args.user)

    action = {
            'list': list,
            'edit': edit,
            'remove': remove,
            }.get(args.action, replace)

    action(cron_file, args)