1 /*
2  *
3  *   Copyright (c) International Business Machines  Corp., 2001
4  *
5  *   This program is free software;  you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation; either version 2 of the License, or
8  *   (at your option) any later version.
9  *
10  *   This program is distributed in the hope that it will be useful,
11  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
13  *   the GNU General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program;  if not, write to the Free Software
17  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 /*
21  * NAME
22  *	libmsg.c
23  *
24  * DESCRIPTION
25  *	common routines for the IPC system call tests.
26  *
27  *	The library contains the following routines:
28  *
29  *	getipckey()
30  *	rm_queue()
31  *	init_buf()
32  *	rm_sema()
33  *	getuserid()
34  *	rm_shm()
35  */
36 
37 #define LIBIPC
38 #include "ipcmsg.h"
39 #include "ipcsem.h"
40 
41 #include <pwd.h>
42 #include <sys/timeb.h>
43 #include <sys/ipc.h>
44 #include <sys/shm.h>
45 
46 /*
47  * getipckey() - generates and returns a message key used by the "get"
48  *		 calls to create an IPC resource.
49  */
getipckey(void)50 key_t getipckey(void)
51 {
52 	const char a = 'a';
53 	int ascii_a = (int)a;
54 	char *curdir = NULL;
55 	size_t size = 0;
56 	key_t ipc_key;
57 	int proj_id;
58 	static int count = 0;
59 
60 	if (NULL == (curdir = getcwd(curdir, size))) {
61 		tst_brkm(TBROK, cleanup, "Can't get current directory "
62 			 "in getipckey()");
63 	}
64 
65 	/*
66 	 * Get a Sys V IPC key
67 	 *
68 	 * ftok() requires a character as a second argument.  This is
69 	 * refered to as a "project identifier" in the man page.
70 	 */
71 	proj_id = count % 26 + ascii_a;
72 	count++;
73 
74 	if ((ipc_key = ftok(curdir, proj_id)) == -1) {
75 		tst_brkm(TBROK, cleanup, "Can't get msgkey from ftok()");
76 	}
77 
78 	return (ipc_key);
79 }
80 
81 /*
82  * rm_queue() - removes a message queue.
83  */
rm_queue(int queue_id)84 void rm_queue(int queue_id)
85 {
86 	if (queue_id == -1) {	/* no queue to remove */
87 		return;
88 	}
89 
90 	if (msgctl(queue_id, IPC_RMID, NULL) == -1) {
91 		tst_resm(TINFO, "WARNING: message queue deletion failed.");
92 		tst_resm(TINFO, "This could lead to IPC resource problems.");
93 		tst_resm(TINFO, "id = %d", queue_id);
94 	}
95 }
96 
97 /*
98  * init_buf() - initialize the message buffer with some text and a type.
99  */
init_buf(MSGBUF * m_buf,int type,int size)100 void init_buf(MSGBUF * m_buf, int type, int size)
101 {
102 	int i;
103 	int ascii_a = (int)'a';	/* the ascii value for 'a' */
104 
105 	/* this fills the message with a repeating alphabet string */
106 	for (i = 0; i < size; i++) {
107 		m_buf->mtext[i] = ascii_a + (i % 26);
108 	}
109 
110 	/* terminate the message */
111 	m_buf->mtext[i] = '\0';
112 
113 	/* if the type isn't valid, set it to 1 */
114 	if (type < 1) {
115 		m_buf->mtype = 1;
116 	} else {
117 		m_buf->mtype = type;
118 	}
119 }
120 
121 /*
122  * rm_sema() - removes a semaphore.
123  */
rm_sema(int sem_id)124 void rm_sema(int sem_id)
125 {
126 	union semun arr;
127 
128 	if (sem_id == -1) {	/* no semaphore to remove */
129 		return;
130 	}
131 
132 	if (semctl(sem_id, 0, IPC_RMID, arr) == -1) {
133 		tst_resm(TINFO, "WARNING: semaphore deletion failed.");
134 		tst_resm(TINFO, "This could lead to IPC resource problems.");
135 		tst_resm(TINFO, "id = %d", sem_id);
136 	}
137 }
138 
139 /*
140  * getuserid() - return the integer value for the "user" id
141  */
getuserid(char * user)142 int getuserid(char *user)
143 {
144 	struct passwd *ent;
145 
146 	/* get the uid value for the user */
147 	if ((ent = getpwnam(user)) == NULL) {
148 		tst_brkm(TBROK, cleanup, "Couldn't get password entry for %s",
149 			 user);
150 	}
151 
152 	return (ent->pw_uid);
153 }
154 
155 /*
156  * rm_shm() - removes a shared memory segment.
157  */
rm_shm(int shm_id)158 void rm_shm(int shm_id)
159 {
160 	if (shm_id == -1) {	/* no segment to remove */
161 		return;
162 	}
163 
164 	/*
165 	 * check for # of attaches ?
166 	 */
167 
168 	if (shmctl(shm_id, IPC_RMID, NULL) == -1) {
169 		tst_resm(TINFO, "WARNING: shared memory deletion failed.");
170 		tst_resm(TINFO, "This could lead to IPC resource problems.");
171 		tst_resm(TINFO, "id = %d", shm_id);
172 	}
173 }
174 
175 #define BUFSIZE 512
176 
177 /*
178  * Get the number of message queues already in use
179  */
get_used_msgqueues(void)180 int get_used_msgqueues(void)
181 {
182 	FILE *f;
183 	int used_queues;
184 	char buff[BUFSIZE];
185 
186 	f = popen("ipcs -q", "r");
187 	if (!f) {
188 		tst_brkm(TBROK | TERRNO, NULL, "pipe failed");
189 	}
190 	/* FIXME: Start at -4 because ipcs prints four lines of header */
191 	for (used_queues = -4; fgets(buff, BUFSIZE, f); used_queues++) ;
192 	pclose(f);
193 	if (used_queues < 0) {
194 		tst_brkm(TBROK, NULL, "Could not read output of 'ipcs' to "
195 			 "calculate used message queues");
196 	}
197 	return used_queues;
198 }
199 
200 /*
201  * Get the max number of message queues allowed on system
202  */
get_max_msgqueues(void)203 int get_max_msgqueues(void)
204 {
205 	FILE *f;
206 	char buff[BUFSIZE];
207 
208 	/* Get the max number of message queues allowed on system */
209 	f = fopen("/proc/sys/kernel/msgmni", "r");
210 	if (!f) {
211 		tst_resm(TBROK, "Could not open /proc/sys/kernel/msgmni");
212 		return -1;
213 	}
214 	if (!fgets(buff, BUFSIZE, f)) {
215 		fclose(f);
216 		tst_resm(TBROK, "Could not read /proc/sys/kernel/msgmni");
217 		return -1;
218 	}
219 	fclose(f);
220 	return atoi(buff);
221 }
222