Home | History | Annotate | Line # | Download | only in sys
t_link.c revision 1.2.6.1
      1 /* $NetBSD: t_link.c,v 1.2.6.1 2017/03/20 06:57:59 pgoyette Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2011 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Jukka Ruohonen.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 #include <sys/cdefs.h>
     32 __RCSID("$NetBSD: t_link.c,v 1.2.6.1 2017/03/20 06:57:59 pgoyette Exp $");
     33 
     34 #include <sys/param.h>
     35 #include <sys/stat.h>
     36 
     37 #include <atf-c.h>
     38 #include <errno.h>
     39 #include <fcntl.h>
     40 #include <limits.h>
     41 #include <stdio.h>
     42 #include <string.h>
     43 #include <unistd.h>
     44 
     45 static const char	*getpath(void);
     46 static char		 path[] = "link";
     47 static const char	*pathl;
     48 
     49 static const char *
     50 getpath(void)
     51 {
     52 	static char buf[LINE_MAX];
     53 
     54 	(void)memset(buf, '\0', sizeof(buf));
     55 
     56 	if (getcwd(buf, sizeof(buf)) == NULL)
     57 		return NULL;
     58 
     59 	(void)strlcat(buf, path, sizeof(buf));
     60 	(void)strlcat(buf, ".link", sizeof(buf));
     61 
     62 	return buf;
     63 }
     64 
     65 ATF_TC_WITH_CLEANUP(link_count);
     66 ATF_TC_HEAD(link_count, tc)
     67 {
     68 	atf_tc_set_md_var(tc, "descr", "link(2) counts are incremented?");
     69 }
     70 
     71 ATF_TC_BODY(link_count, tc)
     72 {
     73 	struct stat sa, sb;
     74 	int fd;
     75 
     76 	(void)memset(&sa, 0, sizeof(struct stat));
     77 	(void)memset(&sb, 0, sizeof(struct stat));
     78 
     79 	pathl = getpath();
     80 	fd = open(path, O_RDWR | O_CREAT, 0600);
     81 
     82 	ATF_REQUIRE(fd >= 0);
     83 	ATF_REQUIRE(pathl != NULL);
     84 
     85 	ATF_REQUIRE(stat(path, &sa) == 0);
     86 	ATF_REQUIRE(link(path, pathl) == 0);
     87 	ATF_REQUIRE(stat(path, &sb) == 0);
     88 
     89 	if (sa.st_nlink != sb.st_nlink - 1)
     90 		atf_tc_fail("incorrect link(2) count");
     91 
     92 	ATF_REQUIRE(close(fd) == 0);
     93 	ATF_REQUIRE(unlink(path) == 0);
     94 	ATF_REQUIRE(unlink(pathl) == 0);
     95 }
     96 
     97 ATF_TC_CLEANUP(link_count, tc)
     98 {
     99 	(void)unlink(path);
    100 	(void)unlink(pathl);
    101 }
    102 
    103 ATF_TC_WITH_CLEANUP(link_err);
    104 ATF_TC_HEAD(link_err, tc)
    105 {
    106 	atf_tc_set_md_var(tc, "descr", "Test error conditions of link(2)");
    107 }
    108 
    109 ATF_TC_BODY(link_err, tc)
    110 {
    111 	char buf[MAXPATHLEN + 1];
    112 	int fd;
    113 
    114 	(void)memset(buf, 'x', sizeof(buf));
    115 
    116 	pathl = getpath();
    117 	fd = open(path, O_RDWR | O_CREAT, 0600);
    118 
    119 	ATF_REQUIRE(fd >= 0);
    120 	ATF_REQUIRE(pathl != NULL);
    121 
    122 	errno = 0;
    123 	ATF_REQUIRE(link(path, pathl) == 0);
    124 	ATF_REQUIRE_ERRNO(EEXIST, link(path, pathl) == -1);
    125 
    126 	errno = 0;
    127 	ATF_REQUIRE_ERRNO(ENAMETOOLONG, link(buf, "xxx") == -1);
    128 
    129 	errno = 0;
    130 	ATF_REQUIRE_ERRNO(ENOENT, link(path, "/d/c/b/a") == -1);
    131 
    132 	errno = 0;
    133 	ATF_REQUIRE_ERRNO(ENOENT, link("/a/b/c/d", path) == -1);
    134 
    135 	errno = 0;
    136 	ATF_REQUIRE_ERRNO(ENOENT, link("/a/b/c/d", "/d/c/b/a") == -1);
    137 
    138 	errno = 0;
    139 	ATF_REQUIRE_ERRNO(EFAULT, link(path, (const char *)-1) == -1);
    140 
    141 	errno = 0;
    142 	ATF_REQUIRE_ERRNO(EFAULT, link((const char *)-1, "xxx") == -1);
    143 
    144 	ATF_REQUIRE(close(fd) == 0);
    145 	ATF_REQUIRE(unlink(path) == 0);
    146 	ATF_REQUIRE(unlink(pathl) == 0);
    147 }
    148 
    149 ATF_TC_CLEANUP(link_err, tc)
    150 {
    151 	(void)unlink(path);
    152 	(void)unlink(pathl);
    153 }
    154 
    155 ATF_TC(link_perm);
    156 ATF_TC_HEAD(link_perm, tc)
    157 {
    158 	atf_tc_set_md_var(tc, "descr", "Test permissions with link(2)");
    159 	atf_tc_set_md_var(tc, "require.user", "unprivileged");
    160 }
    161 
    162 ATF_TC_BODY(link_perm, tc)
    163 {
    164 	int rv;
    165 
    166 	errno = 0;
    167 	rv = link("/root", "/root.link");
    168 	ATF_REQUIRE_MSG(rv == -1 && (errno == EACCES || errno == EPERM),
    169 	    "link to a directory did not fail with EPERM or EACCESS; link() "
    170 	    "returned %d, errno %d", rv, errno);
    171 
    172 	errno = 0;
    173 	ATF_REQUIRE_ERRNO(EACCES,
    174 	    link("/root/.profile", "/root/.profile.link") == -1);
    175 }
    176 
    177 ATF_TC_WITH_CLEANUP(link_stat);
    178 ATF_TC_HEAD(link_stat, tc)
    179 {
    180 	atf_tc_set_md_var(tc, "descr", "Check stat(2) of a linked file");
    181 }
    182 
    183 ATF_TC_BODY(link_stat, tc)
    184 {
    185 	struct stat sa, sb;
    186 	int fd;
    187 
    188 	(void)memset(&sa, 0, sizeof(struct stat));
    189 	(void)memset(&sb, 0, sizeof(struct stat));
    190 
    191 	pathl = getpath();
    192 	fd = open(path, O_RDWR | O_CREAT, 0600);
    193 
    194 	ATF_REQUIRE(fd >= 0);
    195 	ATF_REQUIRE(pathl != NULL);
    196 
    197 	ATF_REQUIRE(link(path, pathl) == 0);
    198 	ATF_REQUIRE(stat(path, &sa) == 0);
    199 	ATF_REQUIRE(lstat(pathl, &sb) == 0);
    200 
    201 	if (sa.st_uid != sb.st_uid)
    202 		atf_tc_fail("unequal UIDs");
    203 
    204 	if (sa.st_mode != sb.st_mode)
    205 		atf_tc_fail("unequal modes");
    206 
    207 	if (sa.st_ino != sb.st_ino)
    208 		atf_tc_fail("unequal inodes");
    209 
    210 	ATF_REQUIRE(close(fd) == 0);
    211 	ATF_REQUIRE(unlink(path) == 0);
    212 	ATF_REQUIRE(unlink(pathl) == 0);
    213 }
    214 
    215 ATF_TC_CLEANUP(link_stat, tc)
    216 {
    217 	(void)unlink(path);
    218 	(void)unlink(pathl);
    219 }
    220 
    221 ATF_TP_ADD_TCS(tp)
    222 {
    223 
    224 	ATF_TP_ADD_TC(tp, link_count);
    225 	ATF_TP_ADD_TC(tp, link_err);
    226 	ATF_TP_ADD_TC(tp, link_perm);
    227 	ATF_TP_ADD_TC(tp, link_stat);
    228 
    229 	return atf_no_error();
    230 }
    231