Ошибка сегментации при возобновлении из режима ожидания - PullRequest
0 голосов
/ 14 сентября 2011

Я пишу очень простой значок состояния батареи, используя GTK.Это GtkStatusIcon, который показывает текущее состояние батареи во всплывающей подсказке.Чтобы получить информацию об аккумуляторе, я анализирую выходные данные команды acpi, которая обычно похожа на:

Battery 0: Discharging, 70%, 01:00:00 remaining

Мой значок состояния аккумулятора работает нормально, но когда я подвожу компьютер и затем возобновляю его,моя программа падает с ошибкой сегментации.

Весь код такой (я это прокомментировал):

#include <gtk/gtk.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

#define DEFAULT_ARRAY_SIZE 3
#define DEFAULT_TIME_UPDATE 5

const gchar * acpi_command = "acpi";

typedef enum batteryState{
    CHARGING,
    DISCHARGING,
} BatteryState;

typedef struct batteryTray {
    GtkStatusIcon * tray_icon;
    gchar * tooltip;
    gchar * icon;
} BatteryTray;

typedef struct battery {
    gchar * status;
    gint percentage;
    gchar * extra;
        BatteryTray batteryTray;
    BatteryState batteryState;
} Battery;

static void update_status_battery(Battery * battery);
static gboolean update_status_tray(Battery * battery);
static gchar * get_status_icon_name(Battery * battery);
static void create_tray_icon(Battery * battery);
static void parse_acpi_output(Battery * battery, gchar * acpi_output);
static char * get_acpi_output(const gchar * acpi_command);

static void update_status_battery(Battery * battery)
{
    if(strcmp(battery->status, "Charging") == 0)
        battery->batteryState = CHARGING;
    else if(strcmp(battery->status, "Discharging") == 0)
        battery->batteryState = DISCHARGING;
}

static gboolean update_status_tray(Battery * battery)
{
    gchar * icon_name = get_status_icon_name(battery);
    gchar * acpi_out = get_acpi_output(acpi_command);

    parse_acpi_output(battery, acpi_out);
    update_status_battery(battery);

    battery->batteryTray.tooltip = g_strdup_printf("%s (%d%%) %s", 
        battery->status, 
        battery->percentage,
        battery->extra);

    gtk_status_icon_set_tooltip_text(battery->batteryTray.tray_icon,
        battery->batteryTray.tooltip);

    gtk_status_icon_set_from_icon_name(battery->batteryTray.tray_icon,
        icon_name);

    return TRUE; 
}

static gchar * get_status_icon_name(Battery * battery)
{

    GString * icon_name = g_string_new("notification-battery");

    if (battery->percentage < 20)
        g_string_append(icon_name, "-low");
    else if (battery->percentage < 40)
        g_string_append(icon_name, "-020");
    else if (battery->percentage < 80)
        g_string_append(icon_name, "-060");
    else
        g_string_append(icon_name, "-100");

    if(battery->batteryState == CHARGING) {
        g_string_append(icon_name, "-plugged");
    }

    return icon_name->str;
}

static void create_tray_icon(Battery * battery) 
{
        /* create the gtkstatusicon and call the function
           `update_status_tray` every 5 seconds */

    battery->batteryTray.tray_icon = gtk_status_icon_new();
    battery->batteryTray.tooltip = "battery";
    gtk_status_icon_set_tooltip(battery->batteryTray.tray_icon, 
        battery->batteryTray.tooltip);
    gtk_status_icon_set_visible(battery->batteryTray.tray_icon, 
        TRUE);

    update_status_tray(battery);
    g_timeout_add_seconds(DEFAULT_TIME_UPDATE, (GSourceFunc) update_status_tray, battery);
}

static void parse_acpi_output(Battery * battery, gchar * acpi_output)
{
    /* acpi output is like:
       Battery 0: Discharging, 70%, 01:00:00 remaining

       In this function I assign "Discharging" to battery->status 
       70 to battery->percentage
       and "01:00:00 remaining" to battery->extra

       I use strtok to split the acpi output into tokens delimited by ',' and
       then, if there's a blank character ' ' in front of a token, i 'remove' it.
     */

    gint i = 0;
    gchar * t;
    gchar ** values_array;

    /* find the position of ':' in the string */
    int pos = strchr(acpi_output, ':') - acpi_output;
    t = strtok(acpi_output + pos + 1, ",");

    values_array = malloc(DEFAULT_ARRAY_SIZE * sizeof(gchar));

    while(t != NULL) {
        /* 'remove' the blank character */
        values_array[i++] = t[0] == ' ' ? t + 1 : t;
        t = strtok(NULL, ",");
    }

    /* remove newline */
    if(values_array[2][strlen(values_array[2]) - 1] == '\n') {
        values_array[2][strlen(values_array[2]) - 1] = '\0';
    }

    battery->status = values_array[0];
    battery->percentage = atoi(values_array[1]);
    battery->extra = values_array[2];

    free(values_array);
}

static gchar * get_acpi_output(const gchar * acpi_command)
{
    gchar * output;
    GError * error = NULL;

    /* assign the output of the acpi command to 'output' */
    g_spawn_command_line_sync(acpi_command, &output, NULL, NULL, &error);
    return output;
} 

int main(int argc, char ** argv)
{
    Battery battery;

    gtk_init(&argc, &argv);
    create_tray_icon(&battery);
    gtk_main();

    return 0;
}

Я надеюсь, что кто-то может мне помочь, потому что я действительно не могу понять.

1 Ответ

1 голос
/ 14 сентября 2011

Есть ряд мест, где вы можете сделать больше проверки ошибок;возможно, что-то вне вашего кода не работает во время пробуждения.Например, вы не проверяете результаты g_spawn_command_line_sync - вы предполагаете, что output указывает на правильную строку при возврате, но, возможно, это не всегда.И вы предполагаете, но на самом деле не подтверждаете, что на выходе запускаемого вами инструмента есть определенное количество токенов, но, возможно, это не всегда.

...