2 * test-save.c: test various aspects of saving
4 * Copyright (C) 2009-2016 David Lutterkort
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * Author: David Lutterkort <lutter@redhat.com>
30 #include <sys/types.h>
34 const char *abs_top_srcdir;
35 const char *abs_top_builddir;
36 char *root = NULL, *src_root = NULL;
37 struct augeas *aug = NULL;
41 fprintf(stderr, "%s:%d: Fatal error: %s\n", __FILE__, __LINE__, msg); \
45 static void setup(CuTest *tc) {
48 if (asprintf(&root, "%s/build/test-save/%s",
49 abs_top_builddir, tc->name) < 0) {
50 CuFail(tc, "failed to set root");
53 if (asprintf(&lensdir, "%s/lenses", abs_top_srcdir) < 0)
54 CuFail(tc, "asprintf lensdir failed");
57 run(tc, "test -d %s && chmod -R u+w %s || :", root, root);
58 run(tc, "rm -rf %s", root);
59 run(tc, "mkdir -p %s", root);
60 run(tc, "cp -pr %s/* %s", src_root, root);
61 run(tc, "chmod -R u+w %s", root);
63 aug = aug_init(root, lensdir, AUG_NO_STDINC);
65 CuAssertPtrNotNull(tc, aug);
68 static void teardown(ATTRIBUTE_UNUSED CuTest *tc) {
69 /* testRemovePermission makes <root>/etc nonwritable. That leads
70 to an error from 'make distcheck' make sure that directory is
71 writable by the user after the test */
72 run(tc, "chmod u+w %s/etc", root);
80 static void testRemoveNoPermission(CuTest *tc) {
82 puts("pending (testRemoveNoPermission): can't test permissions under root account");
89 // Prevent deletion of files
90 run(tc, "chmod 0500 %s/etc", root);
92 r = aug_rm(aug, "/files/etc/hosts");
93 CuAssertTrue(tc, r > 0);
96 CuAssertIntEquals(tc, -1, r);
98 r = aug_get(aug, "/augeas/files/etc/hosts/error", &errmsg);
99 CuAssertIntEquals(tc, 1, r);
100 CuAssertPtrNotNull(tc, errmsg);
101 CuAssertStrEquals(tc, "unlink_orig", errmsg);
104 static void testSaveNewFile(CuTest *tc) {
107 r = aug_match(aug, "/augeas/files/etc/yum.repos.d/new.repo/path", NULL);
108 CuAssertIntEquals(tc, 0, r);
110 r = aug_set(aug, "/files/etc/yum.repos.d/new.repo/newrepo/baseurl",
112 CuAssertIntEquals(tc, 0, r);
115 CuAssertIntEquals(tc, 0, r);
117 r = aug_match(aug, "/augeas/files/etc/yum.repos.d/new.repo/path", NULL);
118 CuAssertIntEquals(tc, 1, r);
121 static void testNonExistentLens(CuTest *tc) {
124 r = aug_rm(aug, "/augeas/load/*");
125 CuAssertTrue(tc, r >= 0);
127 r = aug_set(aug, "/augeas/load/Fake/lens", "Fake.lns");
128 CuAssertIntEquals(tc, 0, r);
129 r = aug_set(aug, "/augeas/load/Fake/incl", "/fake");
130 CuAssertIntEquals(tc, 0, r);
131 r = aug_set(aug, "/files/fake/entry", "value");
132 CuAssertIntEquals(tc, 0, r);
135 CuAssertIntEquals(tc, -1, r);
137 CuAssertIntEquals(tc, AUG_ENOLENS, r);
140 static void testMultipleXfm(CuTest *tc) {
143 r = aug_set(aug, "/augeas/load/Yum2/lens", "Yum.lns");
144 CuAssertIntEquals(tc, 0, r);
145 r = aug_set(aug, "/augeas/load/Yum2/incl", "/etc/yum.repos.d/*");
146 CuAssertIntEquals(tc, 0, r);
148 r = aug_set(aug, "/files/etc/yum.repos.d/fedora.repo/fedora/enabled", "0");
149 CuAssertIntEquals(tc, 0, r);
150 /* What we have set up is fine: two ways to save the same file with the
153 CuAssertIntEquals(tc, 0, r);
155 /* Now we make it bad: a different lens for the same file */
156 r = aug_set(aug, "/augeas/load/Yum2/lens", "@Subversion");
157 CuAssertIntEquals(tc, 0, r);
159 r = aug_set(aug, "/files/etc/yum.repos.d/fedora.repo/fedora/enabled", "1");
160 CuAssertIntEquals(tc, 0, r);
163 CuAssertIntEquals(tc, -1, r);
166 CuAssertIntEquals(tc, AUG_EMXFM, r);
169 static void testMtime(CuTest *tc) {
170 const char *s, *mtime2;
174 r = aug_set(aug, "/files/etc/hosts/1/alias[last() + 1]", "new");
175 CuAssertIntEquals(tc, 0, r);
177 r = aug_get(aug, "/augeas/files/etc/hosts/mtime", &s);
178 CuAssertIntEquals(tc, 1, r);
180 CuAssertPtrNotNull(tc, mtime1);
184 CuAssertIntEquals(tc, 0, r);
186 r = aug_get(aug, "/augeas/files/etc/hosts/mtime", &mtime2);
187 CuAssertIntEquals(tc, 1, r);
189 CuAssertStrNotEqual(tc, mtime1, mtime2);
190 CuAssertStrNotEqual(tc, "0", mtime2);
194 /* Check that loading and saving a file given with a relative path
197 static void testRelPath(CuTest *tc) {
200 r = aug_rm(aug, "/augeas/load/*");
201 CuAssertPositive(tc, r);
203 r = aug_set(aug, "/augeas/load/Hosts/lens", "Hosts.lns");
204 CuAssertRetSuccess(tc, r);
205 r = aug_set(aug, "/augeas/load/Hosts/incl", "etc/hosts");
206 CuAssertRetSuccess(tc, r);
208 CuAssertRetSuccess(tc, r);
210 r = aug_match(aug, "/files/etc/hosts/1/alias[ . = 'new']", NULL);
211 CuAssertIntEquals(tc, 0, r);
213 r = aug_set(aug, "/files/etc/hosts/1/alias[last() + 1]", "new");
214 CuAssertRetSuccess(tc, r);
217 CuAssertRetSuccess(tc, r);
218 r = aug_match(aug, "/augeas//error", NULL);
219 CuAssertIntEquals(tc, 0, r);
221 /* Force reloading the file */
222 r = aug_rm(aug, "/augeas/files//mtime");
223 CuAssertPositive(tc, r);
226 CuAssertRetSuccess(tc, r);
228 r = aug_match(aug, "/files/etc/hosts/1/alias[. = 'new']", NULL);
229 CuAssertIntEquals(tc, 1, r);
232 /* Check that loading and saving a file with // in the incl pattern works.
235 static void testDoubleSlashPath(CuTest *tc) {
238 r = aug_rm(aug, "/augeas/load/*");
239 CuAssertPositive(tc, r);
241 r = aug_set(aug, "/augeas/load/Hosts/lens", "Hosts.lns");
242 CuAssertRetSuccess(tc, r);
243 r = aug_set(aug, "/augeas/load/Hosts/incl", "/etc//hosts");
244 CuAssertRetSuccess(tc, r);
246 CuAssertRetSuccess(tc, r);
248 r = aug_match(aug, "/files/etc/hosts/1/alias[ . = 'new']", NULL);
249 CuAssertIntEquals(tc, 0, r);
251 r = aug_set(aug, "/files/etc/hosts/1/alias[last() + 1]", "new");
252 CuAssertRetSuccess(tc, r);
255 CuAssertRetSuccess(tc, r);
256 r = aug_match(aug, "/augeas//error", NULL);
257 CuAssertIntEquals(tc, 0, r);
259 /* Force reloading the file */
260 r = aug_rm(aug, "/augeas/files//mtime");
261 CuAssertPositive(tc, r);
264 CuAssertRetSuccess(tc, r);
266 r = aug_match(aug, "/files/etc/hosts/1/alias[. = 'new']", NULL);
267 CuAssertIntEquals(tc, 1, r);
270 /* Check the umask is followed when creating files
272 static void testUmask(CuTest *tc, int tumask, mode_t expected_mode) {
277 if (asprintf(&fpath, "%s/etc/test", root) < 0) {
278 CuFail(tc, "failed to set root");
283 r = aug_rm(aug, "/augeas/load/*");
284 CuAssertPositive(tc, r);
286 r = aug_set(aug, "/augeas/load/Test/lens", "Simplelines.lns");
287 CuAssertRetSuccess(tc, r);
288 r = aug_set(aug, "/augeas/load/Test/incl", "/etc/test");
289 CuAssertRetSuccess(tc, r);
291 CuAssertRetSuccess(tc, r);
292 r = aug_set(aug, "/files/etc/test/1", "test");
293 CuAssertRetSuccess(tc, r);
296 CuAssertRetSuccess(tc, r);
297 r = aug_match(aug, "/augeas//error", NULL);
298 CuAssertIntEquals(tc, 0, r);
300 CuAssertIntEquals(tc, 0, stat(fpath, &buf));
301 CuAssertIntEquals(tc, expected_mode, buf.st_mode & 0777);
304 static void testUmask077(CuTest *tc) {
305 testUmask(tc, 0077, 0600);
307 static void testUmask027(CuTest *tc) {
308 testUmask(tc, 0027, 0640);
310 static void testUmask022(CuTest *tc) {
311 testUmask(tc, 0022, 0644);
314 /* Test that handling of 'strange' characters in path names works as
315 * expected. In particular, that paths with characters that have special
316 * meaning in path expressions are escaped properly.
318 * This test isn't all that specific to save, but since these tests set up
319 * a copy of tests/root/ that is modifiable, it was convenient to put this
322 static void testPathEscaping(CuTest *tc) {
323 /* Path expression with characters escaped */
324 static const char *const weird =
325 "/files/etc/sysconfig/network-scripts/ifcfg-weird\\ \\[\\!\\]\\ \\(used\\ to\\ fail\\)";
326 /* Path without any escaping */
327 static const char *const weird_no_escape =
328 "/files/etc/sysconfig/network-scripts/ifcfg-weird [!] (used to fail)";
330 char *fname = NULL, *s = NULL;
334 /* Construct the file name in the file system and check the file is there */
335 r = asprintf(&fname, "%s%s", root, weird_no_escape + strlen("/files"));
336 CuAssertPositive(tc, r);
338 r = access(fname, R_OK);
339 CuAssertIntEquals(tc, 0, r);
341 /* Make sure weird is in the tree */
342 r = aug_match(aug, weird, NULL);
343 CuAssertIntEquals(tc, 1, r);
345 /* Make sure we can get to the metadata about weird */
346 r = asprintf(&s, "/augeas%s/path", weird);
347 CuAssertPositive(tc, r);
349 r = aug_get(aug, s, &v);
350 CuAssertIntEquals(tc, 1, r);
351 CuAssertStrEquals(tc, weird_no_escape, v);
353 /* Delete it from the tree and save it; make sure it gets removed
354 from the file system */
355 r = aug_rm(aug, weird);
356 CuAssertPositive(tc, r);
359 CuAssertRetSuccess(tc, r);
361 r = access(fname, R_OK);
362 CuAssertIntEquals(tc, -1, r);
363 CuAssertIntEquals(tc, ENOENT, errno);
369 /* Test that we handle failure to save a file because we lack permission on
370 * the target file is handled gracefully.
372 * As reported in https://github.com/hercules-team/augeas/issues/178, this
373 * used to lead to a SEGV
375 static void testSaveNoPermission(CuTest *tc) {
377 puts("pending (testSaveNoPermission): can't test permissions under root account");
385 r = asprintf(&path, "%s/etc/hosts", root);
386 CuAssertPositive(tc, r);
388 r = aug_set(aug, "/files/etc/hosts/1/alias[1]", "othername");
389 CuAssertRetSuccess(tc, r);
392 CuAssertRetSuccess(tc, r);
395 CuAssertIntEquals(tc, -1, r);
397 r = aug_get(aug, "/augeas/files/etc/hosts/error", &v);
398 CuAssertIntEquals(tc, 1, r);
399 CuAssertStrEquals(tc, "replace_from_missing", v);
405 CuSuite* suite = CuSuiteNew();
407 abs_top_srcdir = getenv("abs_top_srcdir");
408 if (abs_top_srcdir == NULL)
409 die("env var abs_top_srcdir must be set");
411 abs_top_builddir = getenv("abs_top_builddir");
412 if (abs_top_builddir == NULL)
413 die("env var abs_top_builddir must be set");
415 if (asprintf(&src_root, "%s/tests/root", abs_top_srcdir) < 0) {
416 die("failed to set src_root");
419 CuSuiteSetup(suite, setup, teardown);
421 SUITE_ADD_TEST(suite, testSaveNoPermission);
422 SUITE_ADD_TEST(suite, testSaveNewFile);
423 SUITE_ADD_TEST(suite, testRemoveNoPermission);
424 SUITE_ADD_TEST(suite, testNonExistentLens);
425 SUITE_ADD_TEST(suite, testMultipleXfm);
426 SUITE_ADD_TEST(suite, testMtime);
427 SUITE_ADD_TEST(suite, testRelPath);
428 SUITE_ADD_TEST(suite, testDoubleSlashPath);
429 SUITE_ADD_TEST(suite, testUmask077);
430 SUITE_ADD_TEST(suite, testUmask027);
431 SUITE_ADD_TEST(suite, testUmask022);
432 SUITE_ADD_TEST(suite, testPathEscaping);
435 CuSuiteSummary(suite, &output);
436 CuSuiteDetails(suite, &output);
437 printf("%s\n", output);
439 int result = suite->failCount;
446 * indent-tabs-mode: nil