1// SPDX-License-Identifier: GPL-2.0-or-later
2
3/*
4 *  Copyright (c) International Business Machines  Corp., 2002
5 */
6
7/* 12/03/2002	Port to LTP     robbiew@us.ibm.com */
8/* 06/30/2001	Port to Linux	nsharoff@us.ibm.com */
9
10/*\
11 * [DOCUMENTATION]
12 * Verify that acct() returns proper errno on failure.
13 */
14
15#include <sys/types.h>
16#include <sys/stat.h>
17#include <errno.h>
18#include <fcntl.h>
19#include <pwd.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <unistd.h>
23#include <sys/mount.h>
24
25#include "tst_test.h"
26
27#define DIR_MODE	(S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP| \
28			 S_IXGRP|S_IROTH|S_IXOTH)
29#define FILE_EISDIR		"."
30#define FILE_EACCESS		"/dev/null"
31#define FILE_ENOENT		"/tmp/does/not/exist"
32#define FILE_ENOTDIR		"./tmpfile/"
33#define FILE_TMPFILE		"./tmpfile"
34#define FILE_ELOOP		"test_file_eloop1"
35#define FILE_EROFS		"ro_mntpoint/file"
36
37static struct passwd *ltpuser;
38
39static char *file_eisdir;
40static char *file_eaccess;
41static char *file_enoent;
42static char *file_enotdir;
43static char *file_tmpfile;
44static char *file_eloop;
45static char *file_enametoolong;
46static char *file_erofs;
47static char *file_null;
48
49static void setup_euid(void)
50{
51	SAFE_SETEUID(ltpuser->pw_uid);
52}
53
54static void cleanup_euid(void)
55{
56	SAFE_SETEUID(0);
57}
58
59static struct test_case {
60	char **filename;
61	char *desc;
62	int exp_errno;
63	void (*setupfunc) ();
64	void (*cleanfunc) ();
65} tcases[] = {
66	{&file_eisdir,  FILE_EISDIR,  EISDIR,  NULL,   NULL},
67	{&file_eaccess, FILE_EACCESS, EACCES,  NULL,   NULL},
68	{&file_enoent,  FILE_ENOENT,  ENOENT,  NULL,   NULL},
69	{&file_enotdir, FILE_ENOTDIR, ENOTDIR, NULL,   NULL},
70	{&file_tmpfile, FILE_TMPFILE, EPERM,   setup_euid, cleanup_euid},
71	{&file_null,    "NULL",       EPERM,   setup_euid, cleanup_euid},
72	{&file_eloop,   FILE_ELOOP,   ELOOP,        NULL, NULL},
73	{&file_enametoolong, "aaaa...", ENAMETOOLONG, NULL, NULL},
74	{&file_erofs,   FILE_EROFS,   EROFS,        NULL, NULL},
75};
76
77static void setup(void)
78{
79	int fd;
80
81	TEST(acct(NULL));
82	if (TST_RET == -1 && TST_ERR == ENOSYS)
83		tst_brk(TCONF, "acct() system call isn't configured in kernel");
84
85	ltpuser = SAFE_GETPWNAM("nobody");
86
87	fd = SAFE_CREAT(FILE_TMPFILE, 0777);
88	SAFE_CLOSE(fd);
89
90	TEST(acct(FILE_TMPFILE));
91	if (TST_RET == -1)
92		tst_brk(TBROK | TTERRNO, "acct failed unexpectedly");
93
94	/* turn off acct, so we are in a known state */
95	TEST(acct(NULL));
96	if (TST_RET == -1)
97		tst_brk(TBROK | TTERRNO, "acct(NULL) failed");
98
99	/* ELOOP SETTING */
100	SAFE_SYMLINK(FILE_ELOOP, "test_file_eloop2");
101	SAFE_SYMLINK("test_file_eloop2", FILE_ELOOP);
102
103	memset(file_enametoolong, 'a', PATH_MAX+1);
104	file_enametoolong[PATH_MAX+1] = 0;
105}
106
107static void verify_acct(unsigned int nr)
108{
109	struct test_case *tcase = &tcases[nr];
110
111	if (tcase->setupfunc)
112		tcase->setupfunc();
113
114	TST_EXP_FAIL(acct(*tcase->filename), tcase->exp_errno,
115	             "acct(%s)", tcase->desc);
116
117	if (tcase->cleanfunc)
118		tcase->cleanfunc();
119}
120
121static struct tst_test test = {
122	.needs_root = 1,
123	.mntpoint = "ro_mntpoint",
124	.needs_rofs = 1,
125	.tcnt = ARRAY_SIZE(tcases),
126	.setup = setup,
127	.test = verify_acct,
128	.bufs = (struct tst_buffers []) {
129		{&file_eisdir, .str = FILE_EISDIR},
130		{&file_eaccess, .str = FILE_EACCESS},
131		{&file_enoent, .str = FILE_ENOENT},
132		{&file_enotdir, .str = FILE_ENOTDIR},
133		{&file_tmpfile, .str = FILE_TMPFILE},
134		{&file_eloop, .str = FILE_ELOOP},
135		{&file_enametoolong, .size = PATH_MAX+2},
136		{&file_erofs, .str = FILE_EROFS},
137		{}
138	}
139};
140