github.com/meulengracht/snapd@v0.0.0-20210719210640-8bde69bcc84e/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  	// Set errno in case we die.
    33  	errno = 0;
    34  	sc_error *err = calloc(1, sizeof *err);
    35  	if (err == NULL) {
    36  		die("cannot allocate memory for error object");
    37  	}
    38  	err->domain = domain;
    39  	err->code = code;
    40  	if (vasprintf(&err->msg, msgfmt, ap) == -1) {
    41  		die("cannot format error message");
    42  	}
    43  	return err;
    44  }
    45  
    46  sc_error *sc_error_init(const char *domain, int code, const char *msgfmt, ...)
    47  {
    48  	va_list ap;
    49  	va_start(ap, msgfmt);
    50  	sc_error *err = sc_error_initv(domain, code, msgfmt, ap);
    51  	va_end(ap);
    52  	return err;
    53  }
    54  
    55  sc_error *sc_error_init_from_errno(int errno_copy, const char *msgfmt, ...)
    56  {
    57  	va_list ap;
    58  	va_start(ap, msgfmt);
    59  	sc_error *err = sc_error_initv(SC_ERRNO_DOMAIN, errno_copy, msgfmt, ap);
    60  	va_end(ap);
    61  	return err;
    62  }
    63  
    64  sc_error *sc_error_init_simple(const char *msgfmt, ...)
    65  {
    66  	va_list ap;
    67  	va_start(ap, msgfmt);
    68  	sc_error *err = sc_error_initv(SC_LIBSNAP_DOMAIN,
    69  				       SC_UNSPECIFIED_ERROR, msgfmt, ap);
    70  	va_end(ap);
    71  	return err;
    72  }
    73  
    74  sc_error *sc_error_init_api_misuse(const char *msgfmt, ...)
    75  {
    76  	va_list ap;
    77  	va_start(ap, msgfmt);
    78  	sc_error *err = sc_error_initv(SC_LIBSNAP_DOMAIN,
    79  				       SC_API_MISUSE, msgfmt, ap);
    80  	va_end(ap);
    81  	return err;
    82  }
    83  
    84  const char *sc_error_domain(sc_error * err)
    85  {
    86  	// Set errno in case we die.
    87  	errno = 0;
    88  	if (err == NULL) {
    89  		die("cannot obtain error domain from NULL error");
    90  	}
    91  	return err->domain;
    92  }
    93  
    94  int sc_error_code(sc_error * err)
    95  {
    96  	// Set errno in case we die.
    97  	errno = 0;
    98  	if (err == NULL) {
    99  		die("cannot obtain error code from NULL error");
   100  	}
   101  	return err->code;
   102  }
   103  
   104  const char *sc_error_msg(sc_error * err)
   105  {
   106  	// Set errno in case we die.
   107  	errno = 0;
   108  	if (err == NULL) {
   109  		die("cannot obtain error message from NULL error");
   110  	}
   111  	return err->msg;
   112  }
   113  
   114  void sc_error_free(sc_error * err)
   115  {
   116  	if (err != NULL) {
   117  		free(err->msg);
   118  		err->msg = NULL;
   119  		free(err);
   120  	}
   121  }
   122  
   123  void sc_cleanup_error(sc_error ** ptr)
   124  {
   125  	sc_error_free(*ptr);
   126  	*ptr = NULL;
   127  }
   128  
   129  void sc_die_on_error(sc_error * error)
   130  {
   131  	if (error != NULL) {
   132  		if (strcmp(sc_error_domain(error), SC_ERRNO_DOMAIN) == 0) {
   133  			fprintf(stderr, "%s: %s\n", sc_error_msg(error), strerror(sc_error_code(error)));
   134  		} else {
   135  			fprintf(stderr, "%s\n", sc_error_msg(error));
   136  		}
   137  		sc_error_free(error);
   138  		exit(1);
   139  	}
   140  }
   141  
   142  int sc_error_forward(sc_error ** recipient, sc_error * error)
   143  {
   144  	if (recipient != NULL) {
   145  		*recipient = error;
   146  	} else {
   147  		sc_die_on_error(error);
   148  	}
   149  	return error != NULL ? -1 : 0;
   150  }
   151  
   152  bool sc_error_match(sc_error * error, const char *domain, int code)
   153  {
   154  	// Set errno in case we die.
   155  	errno = 0;
   156  	if (domain == NULL) {
   157  		die("cannot match error to a NULL domain");
   158  	}
   159  	if (error == NULL) {
   160  		return false;
   161  	}
   162  	return strcmp(sc_error_domain(error), domain) == 0
   163  	    && sc_error_code(error) == code;
   164  }