Что такое хорошая стратегия кода ошибки выхода Linux? - PullRequest
5 голосов
/ 26 декабря 2008

У меня есть несколько независимых исполняемых Perl, PHP CLI-скриптов и программ на C ++, для которых мне нужно разработать стратегию кода ошибки выхода. Эти программы вызываются другими программами, использующими класс-оболочку, созданный мной для использования exec() в PHP. Итак, я смогу вернуть код ошибки. Основываясь на этом коде ошибки, вызывающему скрипту нужно будет что-то делать.

Я провел небольшое исследование, и кажется, что все в диапазоне 1-254 (или, может быть, просто 1-127) может быть честной игрой с пользовательскими кодами ошибок.

Мне просто интересно, как другие люди подошли к обработке ошибок в этой ситуации.

Ответы [ 5 ]

8 голосов
/ 26 декабря 2008

Единственное соглашение состоит в том, что вы возвращаете 0 для успеха и что-то отличное от нуля для ошибки. Большинство известных программ для Unix документируют различные коды возврата, которые они могут вернуть, и вы тоже должны это делать. Не имеет большого смысла пытаться составить общий список для всех возможных кодов ошибок, которые может вернуть любая произвольная программа, иначе вы получите десятков тысяч из них, как в некоторых других ОС , и даже в этом случае он не всегда охватывает конкретный тип ошибки, которую вы хотите вернуть.

Так что будьте последовательны и не забудьте документировать любую схему, которую вы решите использовать.

6 голосов
/ 26 декабря 2008

1-127 - доступный диапазон. Предполагается, что все, что больше 127, является «ненормальным» выходом - прекращается сигналом.

Пока вы занимаетесь этим, рассмотрите возможность использования stdout, а не кода выхода. Код выхода по традиции используется для обозначения успеха, неудачи и может быть одним другим состоянием. Вместо того, чтобы использовать код завершения, попробуйте использовать stdout так, как это используют expr и wc. Затем вы можете использовать backtick или что-то подобное в вызывающей программе для извлечения результата.

4 голосов
/ 26 декабря 2008

состояний манифеста Unix -

Выходить как можно быстрее и как можно громче при ошибке

или что-то в этом роде

2 голосов
/ 26 декабря 2008

Не пытайтесь закодировать слишком много значения в значении выхода: подробные статусы и отчеты об ошибках должны идти в stdout / stderr, как предлагает Аркадий.

Однако я считаю очень полезным представлять лишь несколько состояний в выходных значениях, используя двоичные цифры для их кодирования. Например, предположим, что у вас есть следующие надуманные значения:

0000 : 0 (no error)
0001 : 1 (error)
0010 : 2 (I/O error)
0100 : 4 (user input error)
1000 : 8 (permission error)

Тогда ошибка ввода пользователя будет иметь возвращаемое значение 5 (4 + 1), в то время как файл журнала, не имеющий разрешения на запись, может иметь возвращаемое значение 11 (8 + 2 + 1). Поскольку различные значения независимо кодируются в возвращаемом значении, вы можете легко увидеть, что произошло, проверив, какие биты установлены.

В качестве особого случая, чтобы увидеть, если была ошибка, вы можете И код возврата с 1.

Делая это, вы можете кодировать несколько разных вещей в коде возврата простым и понятным способом. Я использую это только для принятия простых решений, таких как «должен ли процесс быть перезапущен», «нужно ли возвращаемое значение и соответствующие журналы должны быть отправлены администратору», и тому подобное. Любая подробная диагностическая информация должна идти в журналы или в stdout / stderr.

1 голос
/ 28 декабря 2008

Обычные состояния выхода варьируются от 0 до 255 (см. Коды выхода больше 255 возможных для обсуждения причин). Обычно статус 0 указывает на успех; все остальное является ошибкой, определяемой реализацией. Я знаю о программе, которая сообщает о состоянии сервера СУБД через состояние выхода; это особый случай определяемых реализацией состояний выхода. Обратите внимание, что вы можете определить реализацию статусов ваших программ.

Я не мог вписать это в 300 символов; в противном случае это был бы комментарий к ответу @ Arkadiy.

Аркадий прав, что в одной части слова состояния выхода значения, отличные от нуля, указывают на сигнал, завершивший процесс, а 8-й бит обычно указывает на дамп ядра, но этот раздел состояния выхода отличается от основного 0 ..255 статус. Однако оболочка (какая бы она ни была) представляет проблему, когда процесс умирает в результате сигнала. 16-битные данные должны быть представлены в 8-битном значении, что всегда сложно. Кажется, что оболочки делают, чтобы взять номер сигнала и добавить к нему 128. Таким образом, если процесс умирает в результате прерывания (сигнал № 2, SIGINT), оболочка сообщает о состоянии выхода как 130. Однако ядро ​​сообщило о состоянии как 0x0002; оболочка изменила то, что сообщает ядро.

Следующий код C демонстрирует это. Есть две программы

  • suicide, который убивает себя, используя выбранный вами сигнал (по умолчанию прерывание).
  • exitstatus, который запускает команду (например, suicide) и сообщает о состоянии завершения работы ядра.

Вот suicide.c:

/*
@(#)File:           $RCSfile: suicide.c,v $
@(#)Version:        $Revision: 1.2 $
@(#)Last changed:   $Date: 2008/12/28 03:45:18 $
@(#)Purpose:        Commit suicide using kill()
@(#)Author:         J Leffler
@(#)Copyright:      (C) JLSS 2008
@(#)Product:        :PRODUCT:
*/

/*TABSTOP=4*/

#if __STDC_VERSION__ >= 199901L
#define _XOPEN_SOURCE 600
#else
#define _XOPEN_SOURCE 500
#endif /* __STDC_VERSION__ */

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "stderr.h"

static const char usestr[] = "[-V][-s signal]";

#ifndef lint
/* Prevent over-aggressive optimizers from eliminating ID string */
extern const char jlss_id_suicide_c[];
const char jlss_id_suicide_c[] = "@(#)$Id: suicide.c,v 1.2 2008/12/28 03:45:18 jleffler Exp $";
#endif /* lint */

int main(int argc, char **argv)
{
    int signum = SIGINT;
    int opt;
    char *end;

    err_setarg0(argv[0]);

    while ((opt = getopt(argc, argv, "Vs:")) != -1)
    {
        switch (opt)
        {
        case 's':
            signum = strtol(optarg, &end, 0);
            if (*end != '\0' || signum <= 0)
                err_error("invalid signal number %s\n", optarg);
            break;
        case 'V':
            err_version("SUICIDE", &"@(#)$Revision: 1.2 $ ($Date: 2008/12/28 03:45:18 $)"[4]);
            break;
        default:
            err_usage(usestr);
            break;
        }
    }
    if (optind != argc)
        err_usage(usestr);
    kill(getpid(), signum);
    return(0);
}

А вот и exitstatus.c:

/*
@(#)File:           $RCSfile: exitstatus.c,v $
@(#)Version:        $Revision: 1.2 $
@(#)Last changed:   $Date: 2008/12/28 03:45:18 $
@(#)Purpose:        Run command and report 16-bit exit status
@(#)Author:         J Leffler
@(#)Copyright:      (C) JLSS 2008
@(#)Product:        :PRODUCT:
*/

/*TABSTOP=4*/

#if __STDC_VERSION__ >= 199901L
#define _XOPEN_SOURCE 600
#else
#define _XOPEN_SOURCE 500
#endif /* __STDC_VERSION__ */

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "stderr.h"

#ifndef lint
/* Prevent over-aggressive optimizers from eliminating ID string */
extern const char jlss_id_exitstatus_c[];
const char jlss_id_exitstatus_c[] = "@(#)$Id: exitstatus.c,v 1.2 2008/12/28 03:45:18 jleffler Exp $";
#endif /* lint */

int main(int argc, char **argv)
{
    pid_t pid;

    err_setarg0(argv[0]);

    if (argc < 2)
        err_usage("cmd [args...]");

    if ((pid = fork()) < 0)
        err_syserr("fork() failed: ");
    else if (pid == 0)
    {
        /* Child */
        execvp(argv[1], &argv[1]);
        return(1);
    }
    else
    {
        pid_t corpse;
        int status;
        corpse = waitpid(pid, &status, 0);
        if (corpse != pid)
            err_syserr("waitpid() failed: ");
        printf("0x%04X\n", status);
    }
    return(0);
}

Отсутствующий код stderr.c и stderr.h можно легко найти практически в любой из моих опубликованных программ. Если вам это нужно срочно, получите его из программы SQLCMD в IIUG Software Archive ; Вы также можете связаться со мной по электронной почте (см. мой профиль).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...