#include "fileconf.h"
char *get_string(char *ptr);
+char *get_command(char *ptr);
int get_line(char *str, size_t size, FILE * file);
void init_default_line(cl_t * cl, cf_t * cf);
char *get_time(char *ptr, time_t * time, int zero_allowed);
char *
get_string(char *ptr)
- /* read string pointed by ptr, remove blanks and manage
- * string placed in quotes */
- /* return NULL on mismatched quotes */
+ /* Read string pointed by ptr, remove blanks and starting/ending quotes. */
+ /* ptr must not be NULL, and a string starting by quote must end with it too. */
+ /* Return a pointer to a new string, or NULL on mismatched quotes. */
{
char quote = 0;
int length = 0;
}
+char *
+get_command(char *ptr)
+ /* Read a shell command from ptr to the end of the (logical) line,
+ * removing trailing blanks. */
+ /* ptr must not be NULL. */
+ /* Return a pointer to a new string. */
+{
+ remove_blanks(ptr);
+ return strdup2(ptr);
+}
int
get_line(char *str, size_t size, FILE *file)
/* check for inline runas */
ptr = check_username(ptr, cf, cl);
- /* get cl_shell field ( remove trailing blanks ) */
- if ((cl->cl_shell = get_string(ptr)) == NULL) {
- fprintf(stderr, "%s:%d: Mismatched quotes: skipping line.\n",
- file_name, line);
- goto exiterr;
- }
+ /* get cl_shell field */
+ cl->cl_shell = get_command(ptr);
if (strcmp(cl->cl_shell, "\0") == 0) {
fprintf(stderr, "%s:%d: No shell command: skipping line.\n",
file_name, line);
/* check for inline runas */
ptr = check_username(ptr, cf, cl);
- /* get cl_shell field ( remove trailing blanks ) */
- if ((cl->cl_shell = get_string(ptr)) == NULL) {
- fprintf(stderr, "%s:%d: Mismatched quotes: skipping line.\n",
- file_name, line);
- goto exiterr;
- }
+ /* get cl_shell field */
+ cl->cl_shell = get_command(ptr);
if (strcmp(cl->cl_shell, "\0") == 0) {
fprintf(stderr, "%s:%d: No shell command: skipping line.\n",
file_name, line);
/* check for inline runas */
ptr = check_username(ptr, cf, cl);
- /* get the shell command (remove trailing blanks) */
- if ((cl->cl_shell = get_string(ptr)) == NULL) {
- fprintf(stderr, "%s:%d: Mismatched quotes: skipping line.\n",
- file_name, line);
- goto exiterr;
- }
+ /* get the shell command */
+ cl->cl_shell = get_command(ptr);
if (strcmp(cl->cl_shell, "\0") == 0) {
fprintf(stderr, "%s:%d: No shell command: skipping line.\n",
file_name, line);
/* check for inline runas */
ptr = check_username(ptr, cf, cl);
- /* get the shell command (remove trailing blanks) */
- if ((cl->cl_shell = get_string(ptr)) == NULL) {
- fprintf(stderr, "%s:%d: Mismatched quotes: skipping line.\n",
- file_name, line);
- goto exiterr;
- }
+ /* get the shell command */
+ cl->cl_shell = get_command(ptr);
if (strcmp(cl->cl_shell, "\0") == 0) {
fprintf(stderr, "%s:%d: No shell command: skipping line.\n",
file_name, line);
--- /dev/null
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h> /* setjmp.h is needed by cmocka.h */
+#include <cmocka.h>
+
+#include "../fcrontab.h"
+#include "../mem.h"
+#include "../fileconf.h"
+
+
+#define TestParser(PARSER, DESC, LINE, EXPECTED_COMMAND) \
+{ \
+ cf_t cf; \
+ char *input = strdup2(LINE); \
+ PARSER(input, &cf); \
+ assert_string_equal(cf.cf_line_base->cl_shell, EXPECTED_COMMAND); \
+ Free_safe(input); \
+}
+
+#define TestArysParser(D, L, E) TestParser(read_arys, D, L, E)
+#define TestPeriodParser(D, L, E) TestParser(read_period, D, L, E)
+#define TestFreqParser(D, L, E) TestParser(read_freq, D, L, E)
+#define TestShortcutParser(D, L, E) TestParser(read_shortcut, D, L, E)
+
+static void
+test_read_arys_shell_parser(void **state)
+{
+ TestArysParser("example 1",
+ "& 05,35 12-14 * * * mycommand -u me -o file ",
+ "mycommand -u me -o file");
+ TestArysParser("quoted command",
+ "* * * * * \"/root/my script\"", "\"/root/my script\"");
+ TestArysParser("Hourly Git Maintenance",
+ "32 1-23 * * * \"/usr/libexec/git-core/git\" --exec-path=\"/usr/libexec/git-core\" -c credential.interactive=false -c core.askPass=true for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=hourly",
+ "\"/usr/libexec/git-core/git\" --exec-path=\"/usr/libexec/git-core\" -c credential.interactive=false -c core.askPass=true for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=hourly");
+ TestArysParser("Daily Git Maintenance",
+ "32 0 * * 1-6 \"/usr/libexec/git-core/git\" --exec-path=\"/usr/libexec/git-core\" -c credential.interactive=false -c core.askPass=true for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=daily",
+ "\"/usr/libexec/git-core/git\" --exec-path=\"/usr/libexec/git-core\" -c credential.interactive=false -c core.askPass=true for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=daily");
+ TestArysParser("Weekly Git Maintenance",
+ "32 0 * * 0 \"/usr/libexec/git-core/git\" --exec-path=\"/usr/libexec/git-core\" -c credential.interactive=false -c core.askPass=true for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=weekly",
+ "\"/usr/libexec/git-core/git\" --exec-path=\"/usr/libexec/git-core\" -c credential.interactive=false -c core.askPass=true for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=weekly");
+}
+
+static void
+test_read_freq_shell_parser(void **state)
+{
+ TestFreqParser("example 1", "@ 30 getmails -all", "getmails -all");
+ TestFreqParser("example 2",
+ "@mailto(root),forcemail 2d /etc/security/msec/cron-sh/security.sh",
+ "/etc/security/msec/cron-sh/security.sh");
+ TestFreqParser("quoted command",
+ "@ 12h02 \"/root/my script\"", "\"/root/my script\"");
+ TestFreqParser("internal quotes", "@ 3d echo \"hi\"", "echo \"hi\"");
+ TestFreqParser("blanks", "@ 3w2d5h1 true ", "true");
+}
+
+static void
+test_read_period_shell_parser(void **state)
+{
+ TestPeriodParser("example 1",
+ "%nightly,mail(no) * 21-23,3-5 echo \"a nigthly entry\"",
+ "echo \"a nigthly entry\"");
+ TestPeriodParser("example 2",
+ "%hours * 0-22 * * * echo \"Ok.\"", "echo \"Ok.\"");
+ TestPeriodParser("quoted command",
+ "%hourly 31 \"/root/my script\"", "\"/root/my script\"");
+ TestPeriodParser("internal quotes",
+ "%middaily 21 7-10 echo \"hi\"", "echo \"hi\"");
+ TestPeriodParser("blanks", "%monthly 59 4 12 true ", "true");
+}
+
+static void
+test_read_shortcut_shell_parser(void **state)
+{
+ TestShortcutParser("example 1",
+ "@hourly check_laptop_logs.sh", "check_laptop_logs.sh");
+ TestShortcutParser("example 2",
+ "@daily check_web_server.sh", "check_web_server.sh");
+ TestShortcutParser("example 3",
+ "@daily check_file_server.sh", "check_file_server.sh");
+ TestShortcutParser("example 4",
+ "@monthly compress_home_made_app_log_files.sh",
+ "compress_home_made_app_log_files.sh");
+ TestShortcutParser("quoted command",
+ "@weekly \"/root/my script\"", "\"/root/my script\"");
+ TestShortcutParser("internal quotes", "@reboot echo \"hi\"", "echo \"hi\"");
+ TestShortcutParser("quoted command", "@yearly true ", "true");
+}
+
+int
+main(void)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_read_arys_shell_parser),
+ cmocka_unit_test(test_read_freq_shell_parser),
+ cmocka_unit_test(test_read_period_shell_parser),
+ cmocka_unit_test(test_read_shortcut_shell_parser),
+ };
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}