github.com/rigado/snapd@v2.42.5-go-mod+incompatible/cmd/libsnap-confine-private/error.c (about)

     1  /*
     2   * Copyright (C) 2016 Canonical Ltd
     3   *
     4   * This program is free software: you can redistribute it and/or modify
     5   * it under the terms of the GNU General Public License version 3 as
     6   * published by the Free Software Foundation.
     7   *
     8   * This program is distributed in the hope that it will be useful,
     9   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    10   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11   * GNU General Public License for more details.
    12   *
    13   * You should have received a copy of the GNU General Public License
    14   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15   *
    16   */
    17  #include "error.h"
    18  
    19  // To get vasprintf
    20  #define _GNU_SOURCE
    21  
    22  #include "utils.h"
    23  
    24  #include <errno.h>
    25  #include <stdarg.h>
    26  #include <stdio.h>
    27  #include <string.h>
    28  
    29  static sc_error *sc_error_initv(const char *domain, int code,
    30  				const char *msgfmt, va_list ap)
    31  {
    32  	sc_error *err = calloc(1, sizeof *err);
    33  	if (err == NULL) {
    34  		die("cannot allocate memory for error object");
    35  	}
    36  	err->domain = domain;
    37  	err->code = code;
    38  	if (vasprintf(&err->msg, msgfmt, ap) == -1) {
    39  		die("cannot format error message");
    40  	}
    41  	return err;
    42  }
    43  
    44  sc_error *sc_error_init(const char *domain, int code, const char *msgfmt, ...)
    45  {
    46  	va_list ap;
    47  	va_start(ap, msgfmt);
    48  	sc_error *err = sc_error_initv(domain, code, msgfmt, ap);
    49  	va_end(ap);
    50  	return err;
    51  }
    52  
    53  sc_error *sc_error_init_from_errno(int errno_copy, const char *msgfmt, ...)
    54  {
    55  	va_list ap;
    56  	va_start(ap, msgfmt);
    57  	sc_error *err = sc_error_initv(SC_ERRNO_DOMAIN, errno_copy, msgfmt, ap);
    58  	va_end(ap);
    59  	return err;
    60  }
    61  
    62  sc_error *sc_error_init_simple(const char *msgfmt, ...)
    63  {
    64  	va_list ap;
    65  	va_start(ap, msgfmt);
    66  	sc_error *err = sc_error_initv(SC_LIBSNAP_DOMAIN,
    67  				       SC_UNSPECIFIED_ERROR, msgfmt, ap);
    68  	va_end(ap);
    69  	return err;
    70  }
    71  
    72  sc_error *sc_error_init_api_misuse(const char *msgfmt, ...)
    73  {
    74  	va_list ap;
    75  	va_start(ap, msgfmt);
    76  	sc_error *err = sc_error_initv(SC_LIBSNAP_DOMAIN,
    77  				       SC_API_MISUSE, msgfmt, ap);
    78  	va_end(ap);
    79  	return err;
    80  }
    81  
    82  const char *sc_error_domain(sc_error * err)
    83  {
    84  	if (err == NULL) {
    85  		die("cannot obtain error domain from NULL error");
    86  	}
    87  	return err->domain;
    88  }
    89  
    90  int sc_error_code(sc_error * err)
    91  {
    92  	if (err == NULL) {
    93  		die("cannot obtain error code from NULL error");
    94  	}
    95  	return err->code;
    96  }
    97  
    98  const char *sc_error_msg(sc_error * err)
    99  {
   100  	if (err == NULL) {
   101  		die("cannot obtain error message from NULL error");
   102  	}
   103  	return err->msg;
   104  }
   105  
   106  void sc_error_free(sc_error * err)
   107  {
   108  	if (err != NULL) {
   109  		free(err->msg);
   110  		err->msg = NULL;
   111  		free(err);
   112  	}
   113  }
   114  
   115  void sc_cleanup_error(sc_error ** ptr)
   116  {
   117  	sc_error_free(*ptr);
   118  	*ptr = NULL;
   119  }
   120  
   121  void sc_die_on_error(sc_error * error)
   122  {
   123  	if (error != NULL) {
   124  		if (strcmp(sc_error_domain(error), SC_ERRNO_DOMAIN) == 0) {
   125  			fprintf(stderr, "%s: %s\n", sc_error_msg(error), strerror(sc_error_code(error)));
   126  		} else {
   127  			fprintf(stderr, "%s\n", sc_error_msg(error));
   128  		}
   129  		sc_error_free(error);
   130  		exit(1);
   131  	}
   132  }
   133  
   134  int sc_error_forward(sc_error ** recipient, sc_error * error)
   135  {
   136  	if (recipient != NULL) {
   137  		*recipient = error;
   138  	} else {
   139  		sc_die_on_error(error);
   140  	}
   141  	return error != NULL ? -1 : 0;
   142  }
   143  
   144  bool sc_error_match(sc_error * error, const char *domain, int code)
   145  {
   146  	if (domain == NULL) {
   147  		die("cannot match error to a NULL domain");
   148  	}
   149  	if (error == NULL) {
   150  		return false;
   151  	}
   152  	return strcmp(sc_error_domain(error), domain) == 0
   153  	    && sc_error_code(error) == code;
   154  }