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