1 /*
2  * Copyright (c) International Business Machines  Corp., 2001
3  *  03/2001 Written by Wayne Boyer
4  *  11/2016 Modified by Guangwen Feng <fenggw-fnst@cn.fujitsu.com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program 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
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 /*
21  * Verify that setpriority(2) succeeds set the scheduling priority of
22  * the current process, process group or user.
23  */
24 
25 #define _GNU_SOURCE
26 #include <errno.h>
27 #include <pwd.h>
28 #include <stdlib.h>
29 #include <sys/resource.h>
30 
31 #include "tst_test.h"
32 
33 static const char *username = "ltp_setpriority01";
34 static int pid, uid, user_added;
35 
36 static struct tcase {
37 	int which;
38 	int *who;
39 } tcases[] = {
40 	{PRIO_PROCESS, &pid},
41 	{PRIO_PGRP, &pid},
42 	{PRIO_USER, &uid}
43 };
44 
str_which(int which)45 static const char *str_which(int which)
46 {
47 	switch (which) {
48 	case PRIO_PROCESS:
49 		return "PRIO_PROCESS";
50 	case PRIO_PGRP:
51 		return "PRIO_PGRP";
52 	case PRIO_USER:
53 		return "PRIO_USER";
54 	default:
55 		return "???";
56 	}
57 }
58 
setpriority_test(struct tcase * tc)59 static void setpriority_test(struct tcase *tc)
60 {
61 	int new_prio, cur_prio;
62 	int failflag = 0;
63 
64 	for (new_prio = -20; new_prio < 20; new_prio++) {
65 		TEST(setpriority(tc->which, *tc->who, new_prio));
66 
67 		if (TST_RET != 0) {
68 			tst_res(TFAIL | TTERRNO,
69 				"setpriority(%d, %d, %d) failed",
70 				tc->which, *tc->who, new_prio);
71 			failflag = 1;
72 			continue;
73 		}
74 
75 		cur_prio = SAFE_GETPRIORITY(tc->which, *tc->who);
76 
77 		if (cur_prio != new_prio) {
78 			tst_res(TFAIL, "current priority(%d) and "
79 				"new priority(%d) do not match",
80 				cur_prio, new_prio);
81 			failflag = 1;
82 		}
83 	}
84 
85 	if (!failflag) {
86 		tst_res(TPASS, "setpriority(%s(%d), %d, -20..19) succeeded",
87 			str_which(tc->which), tc->which, *tc->who);
88 	}
89 }
90 
verify_setpriority(unsigned int n)91 static void verify_setpriority(unsigned int n)
92 {
93 	struct tcase *tc = &tcases[n];
94 
95 	if (tc->which == PRIO_USER && !user_added) {
96 		tst_res(TCONF, "setpriority(%s(%d), %d, -20..19) skipped - Can't add user",
97 			str_which(tc->which), tc->which, *tc->who);
98 		return;
99 	}
100 
101 	pid = SAFE_FORK();
102 	if (pid == 0) {
103 		if (user_added)
104 			SAFE_SETUID(uid);
105 		SAFE_SETPGID(0, 0);
106 
107 		TST_CHECKPOINT_WAKE_AND_WAIT(0);
108 
109 		exit(0);
110 	}
111 
112 	TST_CHECKPOINT_WAIT(0);
113 
114 	setpriority_test(tc);
115 
116 	TST_CHECKPOINT_WAKE(0);
117 
118 	tst_reap_children();
119 }
120 
setup(void)121 static void setup(void)
122 {
123 	const char *const cmd_useradd[] = {"useradd", username, NULL};
124 	struct passwd *ltpuser;
125 	int rc;
126 
127 	switch ((rc = tst_run_cmd(cmd_useradd, NULL, NULL, 1))) {
128 	case 0:
129 		user_added = 1;
130 		ltpuser = SAFE_GETPWNAM(username);
131 		uid = ltpuser->pw_uid;
132 		return;
133 	case 1:
134 	case 255:
135 		return;
136 	default:
137 		tst_brk(TBROK, "Useradd failed (%d)", rc);
138 	}
139 }
140 
cleanup(void)141 static void cleanup(void)
142 {
143 	if (!user_added)
144 		return;
145 
146 	const char *const cmd_userdel[] = {"userdel", "-r", username, NULL};
147 
148 	if (tst_run_cmd(cmd_userdel, NULL, NULL, 1))
149 		tst_res(TWARN | TERRNO, "'userdel -r %s' failed", username);
150 }
151 
152 static struct tst_test test = {
153 	.tcnt = ARRAY_SIZE(tcases),
154 	.needs_root = 1,
155 	.forks_child = 1,
156 	.needs_checkpoints = 1,
157 	.setup = setup,
158 	.cleanup = cleanup,
159 	.test = verify_setpriority,
160 };
161