From 52edeec10a7894f121c4a7869e97d00c171919f8 Mon Sep 17 00:00:00 2001 From: thib Date: Sat, 21 Apr 2001 08:46:55 +0000 Subject: [PATCH] new save system : the binary format has changed, so it is no more necessary to reinstall the fcrontabs when upgrading fcron/fcrontab (no more informations loss, etc). --- conf.c | 643 ++++++++++++++++++++++++++++++++++++++--------------- fcron.h | 7 +- fileconf.c | 115 ++++++++-- 3 files changed, 561 insertions(+), 204 deletions(-) diff --git a/conf.c b/conf.c index 2d9aa28..d0652ae 100644 --- a/conf.c +++ b/conf.c @@ -22,12 +22,13 @@ * `LICENSE' that comes with the fcron source distribution. */ - /* $Id: conf.c,v 1.40 2001-02-27 20:50:03 thib Exp $ */ + /* $Id: conf.c,v 1.41 2001-04-21 08:48:14 thib Exp $ */ #include "fcron.h" int read_file(const char *file_name, CF *cf); -char *read_str(FILE *f, char *buf, int max); +int read_strn(int fd, char **str, short int size); +int read_type(int fd, short int *type, short int *size); void synchronize_file(char *file_name); @@ -229,7 +230,6 @@ synchronize_file(char *file_name) Alloc(cur_f, CF); if ( read_file(file_name, cur_f) != 0 ) { /* an error as occured */ - free(cur_f); return; } @@ -306,7 +306,6 @@ synchronize_file(char *file_name) if ( read_file(file_name, cur_f) != 0 ) { /* an error as occured */ - free(cur_f); return; } @@ -331,7 +330,6 @@ synchronize_file(char *file_name) if ( read_file(file_name, cur_f) != 0 ) { /* an error as occured */ - free(cur_f); return; } @@ -344,53 +342,71 @@ synchronize_file(char *file_name) } -char * -read_str(FILE *f, char *buf, int max) - /* return a pointer to string read from file f - * if it is non-zero length */ +int +read_strn(int fd, char **str, short int size) +/* read a "size"-length string in a binary fcrontab file */ { - int i; + if ( (*str = calloc(size + 1, sizeof(char))) == NULL ) + goto err; + + if ( read(fd, *str, size) < size ) + goto err; + (*str)[size] = '\0'; + return OK; + + err: + if (*str) + free(*str); + *str = NULL; + return ERR; + +} - for (i = 0; i < max; i++) - if ( (buf[i] = fgetc(f)) == '\0') - break; - buf[max-1] = '\0'; +int +read_type(int fd, short int *type, short int *size) +/* read the type and size of the next field in a binary fcrontab file */ +{ + if ( read(fd, type, sizeof(short int)) < sizeof(short int) ) + goto err; + if ( read(fd, size, sizeof(short int)) < sizeof(short int) ) + goto err; + + return OK; - if ( strlen(buf) == 0 ) - return NULL; - else - return strdup2(buf); + err: + return ERR; } - int read_file(const char *file_name, CF *cf) /* read a formated fcrontab. - return 1 on error, 0 otherwise */ + return ERR on error, OK otherwise */ { FILE *ff = NULL; CL *cl = NULL; env_t *env = NULL; char buf[LINE_LEN]; + long int bufi = 0; time_t t_save = 0; time_t slept = 0; uid_t runas = 0; char *runas_str = NULL; struct stat file_stat; struct passwd *pass = NULL; + short int type = 0, size = 0; /* open file */ if ( (ff = fopen(file_name, "r")) == NULL ) { error_e("Could not read %s", file_name); - return 1; + goto err; } /* check if this file is owned by root : otherwise, all runas fields * of this field should be set to the owner */ if ( fstat(fileno(ff), &file_stat) != 0 ) { error_e("Could not stat %s", file_name); - return 1; + goto err; } if ( strncmp(file_name,"new.", 4) == 0 ) { @@ -403,7 +419,7 @@ read_file(const char *file_name, CF *cf) runas = file_stat.st_uid; if ( (pass = getpwuid(file_stat.st_uid)) == NULL ) { error_e("Could not getpwuid(%d)", file_stat.st_uid); - return 1; + goto err; } /* set cf_user field */ runas_str = cf->cf_user = strdup2(pass->pw_name); @@ -416,7 +432,7 @@ read_file(const char *file_name, CF *cf) runas = 0; else { error("Non-new file %s owned by someone else than root",file_name); - return 1; + goto err; } } @@ -427,177 +443,358 @@ read_file(const char *file_name, CF *cf) * a file which he won't understand the syntax, for exemple * a file using a depreciated format generated by an old fcrontab, * if the syntax has changed */ - if (fgets(buf, sizeof(buf), ff) == NULL || - strncmp(buf, "fcrontab-"FILEVERSION"\n", - sizeof("fcrontab-"FILEVERSION"\n")) != 0) { - + if ( read_type(fileno(ff), &type, &size) != OK || type != S_HEADER_T || + read(fileno(ff), &bufi, size) < size || bufi != S_FILEVERSION ) { error("File %s is not valid: ignored.", file_name); - error("Maybe this file has been generated by an old version" - " of fcron. In this case, you should install it again" - " using fcrontab."); - return 1; + error("This file may have been generated by an old version of fcron."); + error("In that case, you should try to use the converter given in the " + "source package, or install it again using fcrontab."); + goto err; } + if ( read_type(fileno(ff), &type, &size) != OK || type != S_USER_T ) { + error("Invalid binary fcrontab (no USER field)"); + goto err; + } if ( runas == 0 ) { /* get the owner's name */ - if ((cf->cf_user = read_str(ff, buf, sizeof(buf))) == NULL) { + if ( read_strn(fileno(ff), &cf->cf_user, size) != OK ) { error("Cannot read user's name : file ignored"); - return 1; + goto err; } } else - /* read the user name but ignore it */ - read_str(ff, buf, sizeof(buf)); + /* ignore the owner's name */ + if ( fseek(ff, size, SEEK_CUR) < 0 ) { + error_e("Could not fseek file %s", file_name); + goto err; + } /* get the time & date of the saving */ /* a new file generated by fcrontab has t_save set to 0 */ - if ( fscanf(ff, "%ld", &t_save) != 1 ) + if ( read_type(fileno(ff), &type, &size) != OK || type != S_TIMEDATE_T + || read(fileno(ff), &t_save, size) < size ) { error("could not get time and date of saving"); + goto err; + } slept = now - t_save; - /* read env variables */ - Alloc(env, env_t); - while( (env->e_val = read_str(ff, buf, sizeof(buf))) != NULL ) { - debug(" Env: \"%s\"", env->e_val ); - - env->e_next = cf->cf_env_base; - cf->cf_env_base = env; - Alloc(env, env_t); - } - /* free last alloc : unused */ - free(env); - - /* read lines */ Alloc(cl, CL); - while ( fread(cl, sizeof(CL), 1, ff) == 1 ) { + /* main loop : read env variables, and lines */ + while ( read_type(fileno(ff), &type, &size) == OK ) { + /* action is determined by the type of the field */ + switch ( type ) { + + case S_ENVVAR_T: + /* read a env variable and add it to the env var list */ + Alloc(env, env_t); + if ( read_strn(fileno(ff), &env->e_val, size) == OK ) { + debug(" Env: \"%s\"", env->e_val ); + env->e_next = cf->cf_env_base; + cf->cf_env_base = env; + } + else { + error_e("Error while reading env var"); + goto err; + } + break; - if ((cl->cl_shell = read_str(ff, buf, sizeof(buf))) == NULL) { - error("Line is not valid (empty shell command) : ignored"); - continue; - } - if ((cl->cl_runas = read_str(ff, buf, sizeof(buf))) == NULL) { - error("Line is not valid (empty runas field) : ignored"); - continue; - } - if ((cl->cl_mailto = read_str(ff, buf, sizeof(buf))) == NULL) { - error("Line is not valid (empty mailto field) : ignored"); - continue; - } + case S_SHELL_T: + if ( read_strn(fileno(ff), &cl->cl_shell, size) != OK ) { + error_e("Error while reading shell field"); + goto err; + } + break; - /* set runas field if necessary (to improve security) */ - if (runas > 0) { - if (strcmp(cl->cl_runas, runas_str) != 0) - warn("warning: runas(%s) is not owner (%s): overridden.", - cl->cl_runas, runas_str); - free(cl->cl_runas); - cl->cl_runas = strdup2(runas_str); - } + case S_RUNAS_T: + if ( read_strn(fileno(ff), &cl->cl_runas, size) != OK ) { + error_e("Error while reading runas field"); + goto err; + } + break; + + case S_MAILTO_T: + if ( read_strn(fileno(ff), &cl->cl_mailto, size) != OK ) { + error_e("Error while reading mailto field"); + goto err; + } + break; + + case S_NEXTEXE_T: + if ( read(fileno(ff), &bufi, size) < size ) { + error_e("Error while reading nextexe field"); + goto err; + } + cl->cl_nextexe = (time_t) bufi; + break; + + case S_OPTION_T: + if (size < OPTION_SIZE) + /* set the options not defined in the savefile to default */ + set_default_opt(cl->cl_option); + if ( read(fileno(ff), &(cl->cl_option), size) < size ) { + error_e("Error while reading option field"); + goto err; + } + break; + + case S_NUMEXE_T: + if ( read(fileno(ff), &(cl->cl_numexe), size) < size ) { + error_e("Error while reading numexe field"); + goto err; + } + break; + + case S_LAVG_T: + if ( read(fileno(ff), &(cl->cl_lavg), size) < size ) { + error_e("Error while reading lavg field"); + goto err; + } + break; + + case S_UNTIL_T: + if ( read(fileno(ff), &bufi, size) < size ) { + error_e("Error while reading until field"); + goto err; + } + cl->cl_until = (time_t) bufi; + break; - /* we need that here because the user's name (contained in the - * struct CF may be required */ - cl->cl_file = cf; - - /* check if the task has not been stopped during execution and insert - * in lavg or serial queues the jobs which was in one at fcron's stops - */ - if (cl->cl_numexe > 0) { - cl->cl_numexe = 0; - if ( ! is_strict(cl->cl_option) ) { - if ( is_lavg(cl->cl_option) ) - add_lavg_job(cl); - else if ( is_serial(cl->cl_option) - || is_serial_once(cl->cl_option) ) - add_serial_job(cl); - else { - /* job has been stopped during execution : - * launch it again */ - warn("job %s did not finish : running it again.", - cl->cl_shell); - set_serial_once(cl->cl_option); - add_serial_job(cl); + case S_NICE_T: + if ( read(fileno(ff), &(cl->cl_nice), size) < size ) { + error_e("Error while reading nice field"); + goto err; + } + break; + + case S_RUNFREQ_T: + if ( read(fileno(ff), &bufi, size) < size ) { + error_e("Error while reading runfreq field"); + goto err; + } + cl->cl_runfreq = (unsigned short) bufi; + break; + + case S_REMAIN_T: + if ( read(fileno(ff), &bufi, size) < size ) { + error_e("Error while reading remain field"); + goto err; + } + cl->cl_remain = (unsigned short) bufi; + break; + + case S_TIMEFREQ_T: + if ( read(fileno(ff), &bufi, size) < size ) { + error_e("Error while reading timefreq field"); + goto err; + } + cl->cl_timefreq = (time_t) bufi; + break; + + case S_MINS_T: + if ( read(fileno(ff), &(cl->cl_mins), size) < size ) { + error_e("Error while reading mins field"); + goto err; + } + break; + + case S_HRS_T: + if ( read(fileno(ff), &(cl->cl_hrs), size) < size ) { + error_e("Error while reading hrs field"); + goto err; + } + break; + + case S_DAYS_T: + if ( read(fileno(ff), &(cl->cl_days), size) < size ) { + error_e("Error while reading days field"); + goto err; + } + break; + + case S_MONS_T: + if ( read(fileno(ff), &(cl->cl_mons), size) < size ) { + error_e("Error while reading mons field"); + goto err; + } + break; + + case S_DOW_T: + if ( read(fileno(ff), &(cl->cl_dow), size) < size ) { + error_e("Error while reading dow field"); + goto err; + } + break; + + case S_ENDLINE_T: + /* make checks on the current line to make sure it is usable */ + if ( cl->cl_shell == NULL || cl->cl_runas == NULL || + cl->cl_mailto == NULL ) { + error("Line is not valid (empty shell, runas or mailto field)" + " : ignored"); + bzero(cl, sizeof(cl)); + continue; + } + + /* set runas field if necessary (to improve security) */ + if (runas > 0) { + if (strcmp(cl->cl_runas, runas_str) != 0) + warn("warning: runas(%s) is not owner (%s): overridden.", + cl->cl_runas, runas_str); + free(cl->cl_runas); + cl->cl_runas = strdup2(runas_str); + } + + /* we need that here because the user's name (contained in the + * struct CF may be required */ + cl->cl_file = cf; + + + /* check if the job hasn't been stopped during execution and insert + * it in lavg or serial queue if it was in one at fcron's stops */ + if (cl->cl_numexe > 0) { + cl->cl_numexe = 0; + if ( ! is_strict(cl->cl_option) ) { + if ( is_lavg(cl->cl_option) ) + add_lavg_job(cl); + else if ( is_serial(cl->cl_option) + || is_serial_once(cl->cl_option) ) + add_serial_job(cl); + else { + /* job has been stopped during execution : + * launch it again */ + warn("job %s did not finish : running it again.", + cl->cl_shell); + set_serial_once(cl->cl_option); + add_serial_job(cl); + } } } - } - if ( is_td(cl->cl_option) ) { + if ( is_td(cl->cl_option) ) { - /* set the time and date of the next execution */ - if ( cl->cl_nextexe <= now ) { - if ( cl->cl_nextexe == 0 ) - /* the is a line from a new file */ - set_next_exe(cl, NO_GOTO); - else if(cl->cl_runfreq == 1 && is_notice_notrun(cl->cl_option)) - set_next_exe_notrun(cl, SYSDOWN); - else if ( is_bootrun(cl->cl_option) && t_save != 0 - && cl->cl_runfreq != 1) { - if ( cl->cl_remain > 0 && --cl->cl_remain > 0 ) { - debug(" cl_remain: %d", cl->cl_remain); + /* set the time and date of the next execution */ + if ( cl->cl_nextexe <= now ) { + if ( cl->cl_nextexe == 0 ) + /* the is a line from a new file */ + set_next_exe(cl, NO_GOTO); + else if (cl->cl_runfreq == 1 && + is_notice_notrun(cl->cl_option)) + set_next_exe_notrun(cl, SYSDOWN); + else if ( is_bootrun(cl->cl_option) && t_save != 0 + && cl->cl_runfreq != 1) { + if ( cl->cl_remain > 0 && --cl->cl_remain > 0 ) { + debug(" cl_remain: %d", cl->cl_remain); + } + else { + /* run bootrun jobs */ + cl->cl_remain = cl->cl_runfreq; + debug(" boot-run %s", cl->cl_shell); + if ( ! is_lavg(cl->cl_option) ) { + set_serial_once(cl->cl_option); + add_serial_job(cl); + } + else + add_lavg_job(cl); + } + set_next_exe(cl, STD); } else { - /* run bootrun jobs */ - cl->cl_remain = cl->cl_runfreq; - debug(" boot-run %s", cl->cl_shell); - if ( ! is_lavg(cl->cl_option) ) { - set_serial_once(cl->cl_option); - add_serial_job(cl); - } + if ( is_notice_notrun(cl->cl_option) ) { + /* set next exe and mail user */ + struct tm *since2 = localtime(&cl->cl_nextexe); + struct tm since; + memcpy(&since, since2, sizeof(since)); + set_next_exe(cl, NO_GOTO); + mail_notrun(cl, SYSDOWN, &since); + } else - add_lavg_job(cl); + set_next_exe(cl, NO_GOTO); } - set_next_exe(cl, STD); } - else { - if ( is_notice_notrun(cl->cl_option) ) { - /* set next exe and mail user */ - struct tm *since2 = localtime(&cl->cl_nextexe), since; - memcpy(&since, since2, sizeof(since)); - set_next_exe(cl, NO_GOTO); - mail_notrun(cl, SYSDOWN, &since); - } - else - set_next_exe(cl, NO_GOTO); + else + /* value of nextexe is valid : just insert line in queue */ + insert_nextexe(cl); + } else { /* is_td(cl->cl_option) */ + /* standard @-lines */ + if ( cl->cl_timefreq < 60 ) { + error("Invalid timefreq for %s: set to 1 day", + cl->cl_shell); + cl->cl_timefreq = 3600*24; } - } - else - /* value of nextexe is valid : just insert line in queue */ + cl->cl_nextexe += slept; insert_nextexe(cl); - } else { /* is_td(cl->cl_option) */ - /* standard @-lines */ - if ( cl->cl_timefreq < 60 ) { - error("Invalid timefreq for %s: set to 1 day", cl->cl_shell); - cl->cl_timefreq = 3600*24; - } - cl->cl_nextexe += slept; - insert_nextexe(cl); - } - - if (debug_opt) { - struct tm *ftime; - ftime = localtime( &(cl->cl_nextexe) ); - debug(" cmd %s next exec %d/%d/%d wday:%d %02d:%02d", - cl->cl_shell, (ftime->tm_mon + 1), ftime->tm_mday, - (ftime->tm_year + 1900), ftime->tm_wday, - ftime->tm_hour, ftime->tm_min); - } - + } + + if (debug_opt) { + struct tm *ftime; + ftime = localtime( &(cl->cl_nextexe) ); + debug(" cmd %s next exec %d/%d/%d wday:%d %02d:%02d", + cl->cl_shell, (ftime->tm_mon + 1), ftime->tm_mday, + (ftime->tm_year + 1900), ftime->tm_wday, + ftime->tm_hour, ftime->tm_min); + } - cl->cl_next = cf->cf_line_base; - cf->cf_line_base = cl; - Alloc(cl, CL); + /* add the current line to the list, and allocate a new line */ + cl->cl_next = cf->cf_line_base; + cf->cf_line_base = cl; + Alloc(cl, CL); + break; + /* end of "case S_ENDLINE_T" in "switch(type)" */ + + /* default case in "switch(type)" */ + default: + error("Error while loading %s : unknown field type %d (ignored)", + file_name, type); + /* skip the data corresponding to the unknown field */ + if ( fseek(ff, size, SEEK_CUR) < 0 ) { + error_e("Could not fseek file %s", file_name); + goto err; + } + } } + + /* free last cl Alloc : unused */ + free(cl); + /* check for an error */ if ( ferror(ff) != 0 ) error("file %s is truncated : you should reinstall it with fcrontab", file_name); - /* free last calloc : unused */ - free(cl); - fclose(ff); - return 0; + return OK; + + err: + if ( ff != NULL) + fclose(ff); + + if ( cl != NULL && cl->cl_next == NULL ) { + /* line is not yet in the line list of the file : free it */ + if ( cl->cl_shell ) free(cl->cl_shell); + if ( cl->cl_runas) free(cl->cl_runas); + if ( cl->cl_mailto) free(cl->cl_mailto); + free(cl); + } + + /* check if we have started to read the lines and env var */ + if ( cl != NULL ) { + /* insert the line in the file list in order to be able to free + * the memory using delete_file() */ + + cf->cf_next = file_base; + file_base = cf; + + delete_file(cf->cf_user); + + } + else if (cf->cf_user != NULL) + free(cf->cf_user); + + return ERR; } @@ -750,30 +947,73 @@ delete_file(const char *user_name) } +/* save_file() error management */ +#define Save_type(file, type) \ + { \ + if ( save_type(file, type) != OK ) { \ + error_e("Could not write type : file has not been saved."); \ + fclose(file); \ + remove(cf->cf_user); \ + goto next_file; \ + } \ + } + +#define Save_str(file, type, str) \ + { \ + if ( save_str(file, type, str) != OK ) { \ + error_e("Could not write str : file has not been saved."); \ + fclose(file); \ + remove(cf->cf_user); \ + goto next_file; \ + } \ + } + +#define Save_strn(file, type, str, size) \ + { \ + if ( save_strn(file, type, str, size) != OK ) { \ + error_e("Could not write strn : file has not been saved."); \ + fclose(file); \ + remove(cf->cf_user); \ + goto next_file; \ + } \ + } + +#define Save_lint(file, type, value) \ + { \ + if ( save_lint(file, type, value) != OK ) { \ + error_e("Could not write lint : file has not been saved."); \ + fclose(file); \ + remove(cf->cf_user); \ + goto next_file; \ + } \ + } + void -save_file(CF *file) +save_file(CF *arg_file) /* Store the informations relatives to the executions * of tasks at a defined frequency of system's running time */ { - CF *cf = NULL; - CL *cl = NULL; + CF *file = NULL; + CL *line = NULL; FILE *f = NULL; - CF *start = NULL; + CF *start_file = NULL; env_t *env = NULL; - if (file != NULL) - start = file; + if (arg_file != NULL) + start_file = arg_file; else - start = file_base; + start_file = file_base; - for (cf = start; cf; cf = cf->cf_next) { + for (file = start_file; file; file = file->cf_next) { - debug("Saving %s...", cf->cf_user); + debug("Saving %s...", file->cf_user); - /* open file for writing */ - if ( (f = fopen(cf->cf_user, "w")) == NULL ) - error_e("save"); + /* open file */ + if ( (f = fopen(file->cf_user, "w")) == NULL ) { + error_e("Could not open %s", file->cf_user); + goto next_file; + } /* chown the file to root:root : this file should only be read and * modified by fcron (not fcrontab) */ @@ -782,39 +1022,72 @@ save_file(CF *file) /* save file : */ - /* put version of frontab file: it permit to daemon not to load + /* put program's version : it permit to daemon not to load * a file which he won't understand the syntax, for exemple * a file using a depreciated format generated by an old fcrontab, * if the syntax has changed */ - fprintf(f, "fcrontab-" FILEVERSION "\n"); + /* an binary fcrontab *must* start by such a header */ + save_lint(f, S_HEADER_T, S_FILEVERSION ); - /* put the user's name : it is used to check his uid has not changed */ - fprintf(f, "%s%c", cf->cf_user, '\0'); + /* put the user's name : needed to check if his uid has not changed */ + /* S_USER_T *must* be the 2nd field of a binary fcrontab */ + save_str(f, S_USER_T, file->cf_user); /* put the time & date of saving : this is use for calcutating - * the system down time */ - fprintf(f, "%ld", now); + * the system down time. As it is a new file, we set it to 0 */ + /* S_USER_T *must* be the 3rd field of a binary fcrontab */ + save_lint(f, S_TIMEDATE_T, 0); /* env variables, */ - for (env = cf->cf_env_base; env; env = env->e_next) - fprintf(f, "%s%c", env->e_val, '\0'); + for (env = file->cf_env_base; env; env = env->e_next) + save_str(f, S_ENVVAR_T, env->e_val); - fprintf(f, "%c", '\0'); - - /* finally, lines. */ - for (cl = cf->cf_line_base; cl; cl = cl->cl_next) { - if ( fwrite(cl, sizeof(CL), 1, f) != 1 ) - error_e("save"); - fprintf(f, "%s%c", cl->cl_shell, '\0'); - fprintf(f, "%s%c", cl->cl_runas, '\0'); - fprintf(f, "%s%c", cl->cl_mailto, '\0'); + /* then, lines. */ + for (line = file->cf_line_base; line; line = line->cl_next) { + + /* this ones are saved for every lines */ + save_str(f, S_SHELL_T, line->cl_shell); + save_str(f, S_RUNAS_T, line->cl_runas); + save_str(f, S_MAILTO_T, line->cl_mailto); + save_lint(f, S_NEXTEXE_T, line->cl_nextexe); + save_strn(f, S_OPTION_T, line->cl_option, OPTION_SIZE); + + /* the following are saved only if needed */ + if ( line->cl_numexe ) + save_strn(f, S_NUMEXE_T, &line->cl_numexe, 1); + if ( is_lavg(line->cl_option) ) + save_strn(f, S_LAVG_T, line->cl_lavg, LAVG_SIZE); + if ( line->cl_until > 0 ) + save_lint(f, S_UNTIL_T, line->cl_until); + if ( line->cl_nice != 0 ) + save_strn(f, S_NICE_T, &line->cl_nice, 1); + if ( line->cl_runfreq > 0 ) { + save_lint(f, S_RUNFREQ_T, line->cl_runfreq); + save_lint(f, S_REMAIN_T, line->cl_remain); + } + + if ( is_freq(line->cl_option) ) + /* save the frequency to run the line */ + save_lint(f, S_TIMEFREQ_T, line->cl_timefreq); + else { + /* save the time and date bit fields */ + save_strn(f, S_MINS_T, line->cl_mins, bitstr_size(60)); + save_strn(f, S_HRS_T, line->cl_hrs, bitstr_size(24)); + save_strn(f, S_DAYS_T, line->cl_days, bitstr_size(32)); + save_strn(f, S_MONS_T, line->cl_mons, bitstr_size(12)); + save_strn(f, S_DOW_T, line->cl_dow, bitstr_size(8)); + } + + /* This field *must* be the last of each line */ + save_type(f, S_ENDLINE_T); } - + fclose(f); - if (file != NULL) + if (arg_file != NULL) /* we have to save only a single file */ break ; + next_file: } } diff --git a/fcron.h b/fcron.h index c157342..83a25b7 100644 --- a/fcron.h +++ b/fcron.h @@ -21,7 +21,7 @@ * `LICENSE' that comes with the fcron source distribution. */ - /* $Id: fcron.h,v 1.18 2001-01-30 17:41:57 thib Exp $ */ + /* $Id: fcron.h,v 1.19 2001-04-21 08:46:55 thib Exp $ */ #ifndef __FCRONH__ #define __FCRONH__ @@ -60,6 +60,7 @@ extern char debug_opt; extern char foreground; extern char *cdir; extern pid_t daemon_pid; +extern mode_t saved_umask; extern char *prog_name; extern char sig_hup; extern CF *file_base; @@ -102,6 +103,10 @@ extern void Debug(char *fmt, ...); /* subs.c */ extern int remove_blanks(char *str); extern char *strdup2(const char *); +extern int save_type(FILE *f, short int type); +extern int save_str(FILE *f, short int type, char *str); +extern int save_strn(FILE *f, short int type, char *str, short int size); +extern int save_lint(FILE *f, short int type, long int value); /* end of subs.c */ /* database.c */ diff --git a/fileconf.c b/fileconf.c index 229218a..75b3723 100644 --- a/fileconf.c +++ b/fileconf.c @@ -22,7 +22,7 @@ * `LICENSE' that comes with the fcron source distribution. */ - /* $Id: fileconf.c,v 1.42 2001-03-10 13:10:23 thib Exp $ */ + /* $Id: fileconf.c,v 1.43 2001-04-21 08:47:07 thib Exp $ */ #include "fcrontab.h" @@ -167,7 +167,6 @@ read_file(char *filename, char *user) /* open file */ /* check if user is allowed to read file */ - /* create a temp file with user's permissions */ if ( access(file_name, R_OK) != 0 ) die_e("User %s can't read file \"%s\"", user, file_name); else if ( (file = fopen(file_name, "r")) == NULL ) { @@ -181,6 +180,7 @@ read_file(char *filename, char *user) default_line.cl_file = cf; default_line.cl_runas = strdup2(user); default_line.cl_mailto = strdup2(user); + set_default_opt(default_line.cl_option); if ( debug_opt ) fprintf(stderr, "FILE %s\n", file_name); @@ -532,6 +532,7 @@ read_opt(char *ptr, CL *cl) cl->cl_runas = strdup2(user); free(cl->cl_mailto); cl->cl_mailto = strdup2(user); + set_default_opt(cl->cl_option); } if (debug_opt) fprintf(stderr, " Opt : \"%s\"\n", opt_name); @@ -1540,7 +1541,48 @@ delete_file(const char *user_name) } -void +/* save_file() error management */ +#define Save_type(file, type) \ + { \ + if ( save_type(file, type) != OK ) { \ + error_e("Could not write type : file has not been installed."); \ + fclose(file); \ + remove(path); \ + return ERR; \ + } \ + } + +#define Save_str(file, type, str) \ + { \ + if ( save_str(file, type, str) != OK ) { \ + error_e("Could not write str : file has not been installed."); \ + fclose(file); \ + remove(path); \ + return ERR; \ + } \ + } + +#define Save_strn(file, type, str, size) \ + { \ + if ( save_strn(file, type, str, size) != OK ) { \ + error_e("Could not write strn : file has not been installed."); \ + fclose(file); \ + remove(path); \ + return ERR; \ + } \ + } + +#define Save_lint(file, type, value) \ + { \ + if ( save_lint(file, type, value) != OK ) { \ + error_e("Could not write lint : file has not been installed."); \ + fclose(file); \ + remove(path); \ + return ERR; \ + } \ + } + +int save_file(char *path) /* Store the informations relatives to the executions * of tasks at a defined frequency of system's running time */ @@ -1556,8 +1598,10 @@ save_file(char *path) for (file = file_base; file; file = file->cf_next) { /* open file */ - if ( (f = fopen(path, "w")) == NULL ) - die_e("File has not be saved"); + if ( (f = fopen(path, "w")) == NULL ) { + error_e("Could not open %s : file has not be installed.", path); + return ERR; + } /* save file : */ @@ -1565,32 +1609,67 @@ save_file(char *path) * a file which he won't understand the syntax, for exemple * a file using a depreciated format generated by an old fcrontab, * if the syntax has changed */ - fprintf(f, "fcrontab-" FILEVERSION "\n"); + /* an binary fcrontab *must* start by such a header */ + Save_lint(f, S_HEADER_T, S_FILEVERSION ); - /* put the user's name : it is used to check his uid has not changed */ - fprintf(f, "%s%c", user, '\0'); + /* put the user's name : needed to check if his uid has not changed */ + /* S_USER_T *must* be the 2nd field of a binary fcrontab */ + Save_str(f, S_USER_T, user); /* put the time & date of saving : this is use for calcutating * the system down time. As it is a new file, we set it to 0 */ - fprintf(f, "%d", 0); + /* S_USER_T *must* be the 3rd field of a binary fcrontab */ + Save_lint(f, S_TIMEDATE_T, 0); /* env variables, */ for (env = file->cf_env_base; env; env = env->e_next) - fprintf(f, "%s%c", env->e_val, '\0'); + Save_str(f, S_ENVVAR_T, env->e_val); - fprintf(f, "%c", '\0'); - /* then, lines. */ for (line = file->cf_line_base; line; line = line->cl_next) { - if ( fwrite(line, sizeof(CL), 1, f) != 1 ) - perror("save"); - fprintf(f, "%s%c", line->cl_shell, '\0'); - fprintf(f, "%s%c", line->cl_runas, '\0'); - fprintf(f, "%s%c", line->cl_mailto, '\0'); + + /* this ones are saved for every lines */ + Save_str(f, S_SHELL_T, line->cl_shell); + Save_str(f, S_RUNAS_T, line->cl_runas); + Save_str(f, S_MAILTO_T, line->cl_mailto); + Save_strn(f, S_OPTION_T, line->cl_option, OPTION_SIZE); + + /* the following are saved only if needed */ + if ( line->cl_numexe ) + Save_strn(f, S_NUMEXE_T, &line->cl_numexe, 1); + if ( is_lavg(line->cl_option) ) + Save_strn(f, S_LAVG_T, line->cl_lavg, LAVG_SIZE); + if ( line->cl_until > 0 ) + Save_lint(f, S_UNTIL_T, line->cl_until); + if ( line->cl_nice != 0 ) + Save_strn(f, S_NICE_T, &line->cl_nice, 1); + if ( line->cl_runfreq > 0 ) { + Save_lint(f, S_RUNFREQ_T, line->cl_runfreq); + Save_lint(f, S_REMAIN_T, line->cl_remain); + } + + if ( is_freq(line->cl_option) ) { + /* save the frequency and the first wait time */ + Save_lint(f, S_NEXTEXE_T, line->cl_nextexe); + Save_lint(f, S_TIMEFREQ_T, line->cl_timefreq); + } + else { + /* save the time and date bit fields */ + Save_strn(f, S_MINS_T, line->cl_mins, bitstr_size(60)); + Save_strn(f, S_HRS_T, line->cl_hrs, bitstr_size(24)); + Save_strn(f, S_DAYS_T, line->cl_days, bitstr_size(32)); + Save_strn(f, S_MONS_T, line->cl_mons, bitstr_size(12)); + Save_strn(f, S_DOW_T, line->cl_dow, bitstr_size(8)); + } + + /* This field *must* be the last of each line */ + { + Save_type(f, S_ENDLINE_T); + } } fclose(f); } + return OK; } - -- 2.40.0