Skip to content

Commit

Permalink
Improve error logging from mce_write_number_string_to_file() helper
Browse files Browse the repository at this point in the history
There should be changes to mce behavior.

The only purpose of the code changes is to give more informative
error logging in cases where mce_write_number_string_to_file()
gets called without properly configured paths (due to hw and/or
kernel changes), i.e. instead of:

	(file == NULL) && ((fp == NULL) || (*fp == NULL))!
	(file == NULL) && ((fp == NULL) || (*fp == NULL))!
	(file == NULL) && ((fp == NULL) || (*fp == NULL))!

emit something like this:

	touchscreen_disable: output->path not configured
	keypad_disable: output->path not configured
	brightness: output->path not configured
  • Loading branch information
spiiroin committed Nov 15, 2012
1 parent 4db2bbf commit 0dd4d20
Show file tree
Hide file tree
Showing 8 changed files with 492 additions and 368 deletions.
148 changes: 65 additions & 83 deletions mce-io.c
Expand Up @@ -425,119 +425,101 @@ gboolean mce_write_string_to_file(const gchar *const file,
return status;
}

/**
* Cleanup function for output file control structures
*
* Closes file stream associated with output if it is open
*
* It is explicitly permitted to call this function:
* 1) with NULL output parameter
* 2) without open stream in ouput
* 3) more than one times
*
* @param output control structure for writing to a file
*/

void mce_close_output(output_state_t *output)
{
if( output && output->file ) {
if( fclose(output->file) == EOF ) {
mce_log(LL_WARN,"%s: can't close %s: %m", output->context, output->path);
}
output->file = 0;
}
}

/**
* Write a string representation of a number to a file
*
* Note: this variant uses in-place rewrites when truncating.
* It should thus not be used in cases where atomicity is expected.
* For atomic replace, use mce_write_number_string_to_file_atomic()
*
* @param file Path to the file, or NULL to user an already open FILE * instead
* @param output control structure for writing to a file
* @param number The number to write
* @param fp A pointer to a FILE *; set the FILE * to NULL to use the file
* path instead
* @param truncate_file TRUE to truncate the file before writing,
* FALSE to append to the end of the file
* @param close_on_exit TRUE to close the file on exit,
* FALSE to leave the file open
*
* @return TRUE on success, FALSE on failure
*/
gboolean mce_write_number_string_to_file(const gchar *const file,
const gulong number, FILE **fp,
gboolean truncate_file,
gboolean close_on_exit)

gboolean mce_write_number_string_to_file(output_state_t *output, const gulong number)
{
gboolean status = FALSE;
FILE *new_fp = NULL;
gint retval;
gboolean status = FALSE; // assume failure

if ((file == NULL) && ((fp == NULL) || (*fp == NULL))) {
mce_log(LL_CRIT,
"(file == NULL) && ((fp == NULL) || (*fp == NULL))!");
goto EXIT;
if( !output ) {
mce_log(LL_CRIT, "NULL output passed, terminating");
abort();
}

if ((fp == NULL) && (close_on_exit == FALSE)) {
mce_log(LL_CRIT,
"(fp == NULL) && (close_on_exit == FALSE)!");
goto EXIT;
if( !output->context ) {
mce_log(LL_CRIT, "output->context missing, terminating");
abort();
}

/* If we cannot open the file, abort */
if ((fp == NULL) || (*fp == NULL)) {
if ((new_fp = fopen(file, truncate_file ? "w" : "a")) == NULL) {
mce_log(LL_ERR,
"Cannot open `%s' for %s; %s",
file,
truncate_file ? "writing" : "appending",
g_strerror(errno));

/* Ignore error */
errno = 0;
goto EXIT;
if( !output->path ) {
if( !output->invalid_config_reported ) {
output->invalid_config_reported = TRUE;
mce_log(LL_ERR, "%s: output->path not configured", output->context);
}
} else {
new_fp = *fp;
goto EXIT;
}

/* Truncate file if we already have one */
if ((fp != NULL) && (*fp != NULL) && (truncate_file == TRUE)) {
int fd = fileno(*fp);

if (fd == -1) {
mce_log(LL_ERR,
"Failed to convert *fp to fd; %s",
g_strerror(errno));

/* Ignore error */
errno = 0;
goto EXIT2;
if( !output->file ) {
output->file = fopen(output->path, output->truncate_file ? "w" : "a");
if( !output->file ) {
mce_log(LL_ERR,"%s: can't open %s: %m", output->context, output->path);
goto EXIT;
}

if (ftruncate(fd, 0L) == -1) {
mce_log(LL_ERR,
"Failed to truncate `%s'; %s",
file, g_strerror(errno));

/* Ignore error */
errno = 0;
goto EXIT2;
}
else if( output->truncate_file )
{
rewind(output->file);
if( ftruncate(fileno(output->file), 0) == -1 ) {
mce_log(LL_WARN,"%s: can't truncate %s: %m", output->context, output->path);
}
}

if ((fp != NULL) && (*fp == NULL))
*fp = new_fp;

retval = fprintf(new_fp, "%lu", number);

/* Was the write successful? */
if (retval < 0) {
mce_log(LL_ERR,
"Failed to write to `%s'; %s",
file, g_strerror(errno));
// from now on assume success
status = TRUE;

/* Ignore error */
errno = 0;
goto EXIT2;
if( fprintf(output->file, "%lu", number) < 0 ) {
mce_log(LL_WARN,"%s: can't write %s: %m", output->context, output->path);
status = FALSE;
}

status = TRUE;
if( fflush(output->file) == EOF ) {
mce_log(LL_WARN,"%s: can't flush %s: %m", output->context, output->path);
status = FALSE;
}

EXIT2:
/* XXX: improve close policy? */
if ((status == FALSE) || (close_on_exit == TRUE)) {
(void)mce_close_file(file, &new_fp);
EXIT:

if (fp != NULL)
*fp = NULL;
} else {
fflush(*fp);
if( output->close_on_exit && output->file ) {
if( fclose(output->file) == EOF ) {
mce_log(LL_WARN,"%s: can't close %s: %m", output->context, output->path);
}
output->file = 0;
}

/* Ignore error */
errno = 0;

EXIT:
return status;
}

Expand Down
40 changes: 36 additions & 4 deletions mce-io.h
Expand Up @@ -35,6 +35,40 @@ typedef enum {
MCE_IO_ERROR_POLICY_IGNORE
} error_policy_t;

/** Control structure for updating output files */
typedef struct {
/* static configuration */

/** descriptive context information used for identifying the
* purpose of the output file even if no valid output path
* is available */
const gchar *context;

/** TRUE to truncate the file before writing,
* FALSE to append to the end of the file */
gboolean truncate_file;

/** TRUE to close the file on exit
* [from mce_write_number_string_to_file() function],
* FALSE to leave the file open */
gboolean close_on_exit;

/* runtime configuration */

/** Path to the file, or NULL (in which case one misconfiguration
* error message will be logged if write helpers are called) */
const char *path;

/* dynamic state */

/** Cached output stream, use mce_close_output() to close */
FILE *file;

/** TRUE if missing path configuration error has already been
* written for this file */
gboolean invalid_config_reported;
} output_state_t;

/** Function pointer for I/O monitor callback */
typedef gboolean (*iomon_cb)(gpointer data, gsize bytes_read);
/** Function pointer for I/O monitor error callback */
Expand All @@ -50,10 +84,8 @@ gboolean mce_read_number_string_from_file(const gchar *const file,
gboolean close_on_exit);
gboolean mce_write_string_to_file(const gchar *const file,
const gchar *const string);
gboolean mce_write_number_string_to_file(const gchar *const file,
const gulong number, FILE **fp,
gboolean truncate_file,
gboolean close_on_exit);
void mce_close_output(output_state_t *output);
gboolean mce_write_number_string_to_file(output_state_t *output, const gulong number);
gboolean mce_write_number_string_to_file_atomic(const gchar *const file,
const gulong number);
void mce_suspend_io_monitor(gconstpointer io_monitor);
Expand Down

0 comments on commit 0dd4d20

Please sign in to comment.