<title>High priority</title>
<itemizedlist>
<listitem>
- <para>could be worth checking fcron for memory leaks using specialized library (just in case...)</para>
+ <para>add audit (libaudit)</para>
</listitem>
<listitem>
- <para>option to put a maximum limit on the execution time of a task + terminate it if not finished yet + send email to let the user know</para>
+ <para>Use directory notifications (FAM) / inotify, and support a fcrontab
+ and a cron.d as Vixie cron does (directly included in fcron itself, not thanks to a script as now).
+ However the parsing work is done by fcrontab, and should probably keep on being done by fcrontab for
+ security and stability reasons: have fcron call fcrontab to do that job?</para>
</listitem>
<listitem>
- <para>jitter feature: if 100 jobs to be started at the same minute, then make them start at a random second of that minute to limit load spikes (see BSD cron jitter feature)</para>
+ <para>could be worth checking fcron for memory leaks using specialized library (just in case...)</para>
+ </listitem>
+ <listitem>
+ <para>option to put a maximum limit on the execution time of a task + terminate it if not finished yet + send email to let the user know</para>
</listitem>
<listitem>
<para>setting to limit the number of jobs of a single user in the serialq/lavgq to X jobs + make sure root always has Y slots that it can use in those queues (i.e. number of slots used by root + number of free slots >= Y)</para>
<sect2>
<title>Low priority</title>
<itemizedlist>
+ <listitem>
+ <para>use readline (if available) for fcrondyn.</para>
+ </listitem>
<listitem>
<para>add logging to a file (instead of syslog) with configuration in fcron.conf</para>
</listitem>
<para>add a return code for jobs which would mean that they
should not be run again (in case of an error, etc...).</para>
</listitem>
- <listitem>
- <para>Use directory notifications (FAM), and support a fcrontab
- and a cron.d as Vixie cron does (directly included in fcron itself, not thanks to a script as now).</para>
- </listitem>
<listitem>
<para>PAM support (included in fcron, but needs more tests by
people using PAM - not implemented in fcrondyn: is it needed
<listitem>
<para>support for per user serial queue (especially for root)</para>
</listitem>
- <listitem>
- <para>use readline (if available) for fcrondyn.</para>
- </listitem>
<listitem>
<para>add a mailsubject option, for custom mail subjects (for instance, in case of a job containing something secret -- password, etc -- in the command line).</para>
</listitem>
* all jobs that are due at the time when fcron is started */
char dosyslog = 1; /* set to 1 when we log messages to syslog, else 0 */
+/* Get the default locale character set for the mail
+ * "Content-Type: ...; charset=" header */
+char default_mail_charset[TERM_LEN] = "";
+
/* used in temp_file() : create it in current dir (normally spool dir) */
char *tmp_path = "";
int
main(int argc, char **argv)
{
+ char *codeset = NULL;
rootuid = get_user_uid_safe(ROOTNAME);
rootgid = get_group_gid_safe(ROOTGROUP);
if (chdir(fcrontabs) != 0)
die_e("Could not change dir to %s", fcrontabs);
+ /* Get the default locale character set for the mail
+ * "Content-Type: ...; charset=" header */
+ setlocale(LC_ALL,""); /* set locale to system defaults or to
+ that specified by any LC_* env vars */
+ /* Except that "US-ASCII" is preferred to "ANSI_x3.4-1968" in MIME,
+ * even though "ANSI_x3.4-1968" is the official charset name. */
+ if ( (codeset = nl_langinfo(CODESET)) != 0L &&
+ strcmp(codeset, "ANSI_x3.4-1968") != 0 )
+ strncpy(default_mail_charset, codeset, sizeof(default_mail_charset));
+ else
+ strcpy(default_mail_charset, "US-ASCII");
if ( freopen("/dev/null", "r", stdin) == NULL )
error_e("Could not open /dev/null as stdin");
if (is_mail(cl->cl_option)) {
char **envp = env_list_export_envp(env);
- FILE *mailf = create_mail(cl, "Could not run fcron job", envp);
+ FILE *mailf = create_mail(cl, "Could not run fcron job", NULL, NULL, envp);
/* print the error in both syslog and a file, in order to mail it to user */
if (dup2(fileno(mailf), 1) != 1 || dup2(1, 2) != 2)
void
setup_user_and_env(struct cl_t *cl, struct passwd *pas,
- char ***sendmailenv, char ***jobenv, char **curshell, char **curhome)
+ char ***sendmailenv, char ***jobenv, char **curshell,
+ char **curhome, char **content_type, char **encoding)
/* Check PAM authorization, and setup the environment variables
* to run sendmail and to run the job itself. Change dir to HOME and check if SHELL is ok */
/* (*curshell) and (*curhome) will be allocated and should thus be freed
if ( curshell != NULL )
*curshell = strdup2(myshell);
- if (jobenv != NULL)
- *jobenv = env_list_export_envp(env_list);
+ *jobenv = env_list_export_envp(env_list);
- env_list_destroy(env_list);
+ }
+ if ( content_type != NULL ) {
+ (*content_type) = strdup2(env_list_getenv(env_list, "CONTENT_TYPE"));
+ }
+ if ( encoding != NULL ) {
+ (*encoding) = strdup2(env_list_getenv(env_list, "CONTENT_TRANSFER_ENCODING"));
}
+ env_list_destroy(env_list);
+
}
void
change_user_setup_env(struct cl_t *cl,
- char ***sendmailenv, char ***jobenv, char **curshell, char **curhome)
+ char ***sendmailenv, char ***jobenv, char **curshell,
+ char **curhome, char **content_type, char **encoding)
/* call setup_user_and_env() and become_user().
* As a result, *curshell and *curhome will be allocated and should thus be freed
* if curshell and curhome are not NULL. */
if ( pas == NULL )
die_e("failed to get passwd fields for user \"%s\"", cl->cl_runas);
- setup_user_and_env(cl, pas, sendmailenv, jobenv, curshell, curhome);
+ setup_user_and_env(cl, pas, sendmailenv, jobenv, curshell, curhome,
+ content_type, encoding);
become_user(cl, pas, *curhome);
free_safe(*curhome);
}
FILE *
-create_mail(cl_t *line, char *subject, char **env)
+create_mail(cl_t *line, char *subject, char *content_type, char *encoding,
+ char **env)
/* create a temp file and write in it a mail header */
{
/* create temporary file for stdout and stderr of the job */
fprintf(mailf, "Subject: fcron <%s@%s> %s\n", line->cl_file->cf_user,
( hostname[0] != '\0')? hostname:"?" , line->cl_shell);
+ if (content_type == NULL) {
+ fprintf(mailf, "Content-Type: text/plain; charset=%s\n",
+ default_mail_charset);
+ }
+ else {
+ /* user specified Content-Type header. */
+ char *c = NULL;
+
+ /* Remove new-lines or users could specify arbitrary mail headers!
+ * (fcrontab should already prevent that, but better safe than sorry) */
+ for (c=content_type; *c != '\0'; c++) {
+ if (*c == '\n')
+ *c = ' ';
+ }
+ fprintf(mailf, "Content-Type: %s\n", content_type);
+ }
+
+ if (encoding != NULL) {
+ char *c = NULL;
+
+ /* Remove new-lines or users could specify arbitrary mail headers!
+ * (fcrontab should already prevent that, but better safe than sorry) */
+ for (c=encoding; *c != '\0'; c++) {
+ if (*c == '\n')
+ *c = ' ';
+ }
+ fprintf(mailf, "Content-Transfer-Encoding: %s\n", encoding);
+ }
+
/* Add headers so as automated systems can identify that this message
* is an automated one sent by fcron.
* That's useful for example for vacation auto-reply systems: no need
char **sendmailenv = NULL;
char *curshell = NULL;
char *curhome = NULL;
+ char *content_type = NULL;
+ char *encoding = NULL;
FILE *mailf = NULL;
int status = 0;
int to_stdout = foreground && is_stdout(line->cl_option);
if ( pas == NULL )
die_e("failed to get passwd fields for user \"%s\"", line->cl_runas);
- setup_user_and_env(line, pas, &sendmailenv, &jobenv, &curshell, &curhome);
+ setup_user_and_env(line, pas, &sendmailenv, &jobenv, &curshell,
+ &curhome, &content_type, &encoding);
/* close unneeded READ fd */
if ( close(pipe_pid_fd[0]) < 0 )
* as temp_file() needs root privileges */
/* if we run in foreground, stdout and stderr point to the console.
* Otherwise, stdout and stderr point to /dev/null . */
- mailf = create_mail(line, NULL, jobenv);
+ mailf = create_mail(line, NULL, content_type, encoding, jobenv);
mailpos = ftell(mailf);
if (pipe(pipe_fd) != 0)
die_e("could not pipe() (job not executed)");