github.com/anonymouse64/snapd@v0.0.0-20210824153203-04c4c42d842d/cmd/libsnap-confine-private/utils-test.c (about)

     1  /*
     2   * Copyright (C) 2015 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  
    18  #include "utils.h"
    19  #include "utils.c"
    20  
    21  #include <glib.h>
    22  
    23  static void test_parse_bool(void)
    24  {
    25  	int err;
    26  	bool value;
    27  
    28  	value = false;
    29  	err = parse_bool("yes", &value, false);
    30  	g_assert_cmpint(err, ==, 0);
    31  	g_assert_true(value);
    32  
    33  	value = false;
    34  	err = parse_bool("1", &value, false);
    35  	g_assert_cmpint(err, ==, 0);
    36  	g_assert_true(value);
    37  
    38  	value = true;
    39  	err = parse_bool("no", &value, false);
    40  	g_assert_cmpint(err, ==, 0);
    41  	g_assert_false(value);
    42  
    43  	value = true;
    44  	err = parse_bool("0", &value, false);
    45  	g_assert_cmpint(err, ==, 0);
    46  	g_assert_false(value);
    47  
    48  	value = true;
    49  	err = parse_bool("", &value, false);
    50  	g_assert_cmpint(err, ==, 0);
    51  	g_assert_false(value);
    52  
    53  	value = true;
    54  	err = parse_bool(NULL, &value, false);
    55  	g_assert_cmpint(err, ==, 0);
    56  	g_assert_false(value);
    57  
    58  	value = false;
    59  	err = parse_bool(NULL, &value, true);
    60  	g_assert_cmpint(err, ==, 0);
    61  	g_assert_true(value);
    62  
    63  	value = true;
    64  	err = parse_bool("flower", &value, false);
    65  	g_assert_cmpint(err, ==, -1);
    66  	g_assert_cmpint(errno, ==, EINVAL);
    67  	g_assert_true(value);
    68  
    69  	err = parse_bool("yes", NULL, false);
    70  	g_assert_cmpint(err, ==, -1);
    71  	g_assert_cmpint(errno, ==, EFAULT);
    72  }
    73  
    74  static void test_die(void)
    75  {
    76  	if (g_test_subprocess()) {
    77  		errno = 0;
    78  		die("death message");
    79  		g_test_message("expected die not to return");
    80  		g_test_fail();
    81  		return;
    82  	}
    83  	g_test_trap_subprocess(NULL, 0, 0);
    84  	g_test_trap_assert_failed();
    85  	g_test_trap_assert_stderr("death message\n");
    86  }
    87  
    88  static void test_die_with_errno(void)
    89  {
    90  	if (g_test_subprocess()) {
    91  		errno = EPERM;
    92  		die("death message");
    93  		g_test_message("expected die not to return");
    94  		g_test_fail();
    95  		return;
    96  	}
    97  	g_test_trap_subprocess(NULL, 0, 0);
    98  	g_test_trap_assert_failed();
    99  	g_test_trap_assert_stderr("death message: Operation not permitted\n");
   100  }
   101  
   102  // A variant of rmdir that is compatible with GDestroyNotify
   103  static void my_rmdir(const char *path)
   104  {
   105  	if (rmdir(path) != 0) {
   106  		die("cannot rmdir %s", path);
   107  	}
   108  }
   109  
   110  // A variant of chdir that is compatible with GDestroyNotify
   111  static void my_chdir(const char *path)
   112  {
   113  	if (chdir(path) != 0) {
   114  		die("cannot change dir to %s", path);
   115  	}
   116  }
   117  
   118  /**
   119   * Perform the rest of testing in a ephemeral directory.
   120   *
   121   * Create a temporary directory, move the current process there and undo those
   122   * operations at the end of the test.  If any additional directories or files
   123   * are created in this directory they must be removed by the caller.
   124   **/
   125  static void g_test_in_ephemeral_dir(void)
   126  {
   127  	gchar *temp_dir = g_dir_make_tmp(NULL, NULL);
   128  	gchar *orig_dir = g_get_current_dir();
   129  	int err = chdir(temp_dir);
   130  	g_assert_cmpint(err, ==, 0);
   131  
   132  	g_test_queue_free(temp_dir);
   133  	g_test_queue_destroy((GDestroyNotify) my_rmdir, temp_dir);
   134  	g_test_queue_free(orig_dir);
   135  	g_test_queue_destroy((GDestroyNotify) my_chdir, orig_dir);
   136  }
   137  
   138  /**
   139   * Test sc_nonfatal_mkpath() given two directories.
   140   **/
   141  static void _test_sc_nonfatal_mkpath(const gchar * dirname,
   142  				     const gchar * subdirname)
   143  {
   144  	// Check that directory does not exist.
   145  	g_assert_false(g_file_test(dirname, G_FILE_TEST_EXISTS |
   146  				   G_FILE_TEST_IS_DIR));
   147  	// Use sc_nonfatal_mkpath to create the directory and ensure that it worked
   148  	// as expected.
   149  	g_test_queue_destroy((GDestroyNotify) my_rmdir, (char *)dirname);
   150  	int err = sc_nonfatal_mkpath(dirname, 0755);
   151  	g_assert_cmpint(err, ==, 0);
   152  	g_assert_cmpint(errno, ==, 0);
   153  	g_assert_true(g_file_test(dirname, G_FILE_TEST_EXISTS |
   154  				  G_FILE_TEST_IS_REGULAR));
   155  	// Use same function again to try to create the same directory and ensure
   156  	// that it didn't fail and properly retained EEXIST in errno.
   157  	err = sc_nonfatal_mkpath(dirname, 0755);
   158  	g_assert_cmpint(err, ==, 0);
   159  	g_assert_cmpint(errno, ==, EEXIST);
   160  	// Now create a sub-directory of the original directory and observe the
   161  	// results. We should no longer see errno of EEXIST!
   162  	g_test_queue_destroy((GDestroyNotify) my_rmdir, (char *)subdirname);
   163  	err = sc_nonfatal_mkpath(subdirname, 0755);
   164  	g_assert_cmpint(err, ==, 0);
   165  	g_assert_cmpint(errno, ==, 0);
   166  }
   167  
   168  /**
   169   * Test that sc_nonfatal_mkpath behaves when using relative paths.
   170   **/
   171  static void test_sc_nonfatal_mkpath__relative(void)
   172  {
   173  	g_test_in_ephemeral_dir();
   174  	gchar *current_dir = g_get_current_dir();
   175  	g_test_queue_free(current_dir);
   176  	gchar *dirname = g_build_path("/", current_dir, "foo", NULL);
   177  	g_test_queue_free(dirname);
   178  	gchar *subdirname = g_build_path("/", current_dir, "foo", "bar", NULL);
   179  	g_test_queue_free(subdirname);
   180  	_test_sc_nonfatal_mkpath(dirname, subdirname);
   181  }
   182  
   183  /**
   184   * Test that sc_nonfatal_mkpath behaves when using absolute paths.
   185   **/
   186  static void test_sc_nonfatal_mkpath__absolute(void)
   187  {
   188  	g_test_in_ephemeral_dir();
   189  	const char *dirname = "foo";
   190  	const char *subdirname = "foo/bar";
   191  	_test_sc_nonfatal_mkpath(dirname, subdirname);
   192  }
   193  
   194  static void __attribute__((constructor)) init(void)
   195  {
   196  	g_test_add_func("/utils/parse_bool", test_parse_bool);
   197  	g_test_add_func("/utils/die", test_die);
   198  	g_test_add_func("/utils/die_with_errno", test_die_with_errno);
   199  	g_test_add_func("/utils/sc_nonfatal_mkpath/relative",
   200  			test_sc_nonfatal_mkpath__relative);
   201  	g_test_add_func("/utils/sc_nonfatal_mkpath/absolute",
   202  			test_sc_nonfatal_mkpath__absolute);
   203  }