dc1c5193d880df5cfab0582fd3ebcd4348c132c6
[xfstests-dev.git] / dmapi / src / common / lib / find_session.c
1 /*
2  * Copyright (c) 2000-2001 Silicon Graphics, Inc.
3  * All Rights Reserved.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it would be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write the Free Software Foundation,
16  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18
19 #include <lib/hsm.h>
20
21 #include <string.h>
22
23 /*******************************************************************************
24 *
25 * NAME
26 *       find_test_session - find or create a test DMAPI session.
27 *
28 * DESCRIPTION
29 *       find_test_session() is used to find a test DMAPI session to
30 *       use.  There is only one test session per host; all test processes
31 *       share the same session.  If the session does not already exist,
32 *       then the first process to call find_test_session() causes
33 *       the session to be created.
34 *
35 *       Note: It is possible for N different programs to call this routine
36 *       at the same time.  Each would find that a test session does not
37 *       exist, and each one would then create a new test session.  Since
38 *       excess test sessions are not automatically released on death of
39 *       process, we need to make sure that we don't leave such excess
40 *       sessions around.  So, after creating a session we go back and find
41 *       the test session with the lowest session number.  If it is ours,
42 *       great; we are done.  If not, then we must destroy our session
43 *       and use the one with the lower session ID.  There is still a risk
44 *       here of creating a session and crashing before it can be removed
45 *       again.  To deal with this, the daemon will periodically remove all
46 *       test sessions except for the one with the lowest ID value.
47 *
48 * RETURN VALUE
49 *       None.
50 *
51 *******************************************************************************/
52
53 #define TEST_MSG        "DMAPI test session"
54
55 static int
56 session_compare(
57 const   void    *a,
58 const   void    *b)
59 {
60         return(*((dm_sessid_t *)a) - *((dm_sessid_t *)b));
61 }
62
63 extern void
64 find_test_session(
65         dm_sessid_t     *session)
66 {
67         char            buffer[DM_SESSION_INFO_LEN];
68         dm_sessid_t     *sidbuf = NULL;
69         dm_sessid_t     new_session;
70         u_int           allocelem = 0;
71         u_int           nelem;
72         size_t          rlen;
73         int             error;
74         u_int           i;
75
76         /* Retrieve the list of all active sessions on the host. */
77
78         nelem = 100;            /* a reasonable first guess */
79         do {
80                 if (allocelem < nelem) {
81                         allocelem = nelem;
82                         sidbuf = realloc(sidbuf, nelem * sizeof(*sidbuf));
83                         if (sidbuf == NULL) {
84                                 fprintf(stderr, "realloc of %d bytes failed\n",
85                                         nelem * sizeof(*sidbuf));
86                                 exit(1);
87                         }
88                 }
89                 error = dm_getall_sessions(allocelem, sidbuf, &nelem);
90         } while (error < 0 && errno == E2BIG);
91
92         /* If an error occurred, translate it into something meaningful. */
93
94         if (error < 0) {
95                 fprintf(stderr, "unexpected dm_getall_sessions failure, %s\n",
96                         strerror(errno));
97                 free(sidbuf);
98                 exit(1);
99         }
100
101         /* We have the list of all active sessions.  Scan the list looking
102            for an existing "test" session that we can use.  The list must
103            first be sorted in case other processes happen to be creating test
104            sessions at the same time; we need to make sure that we pick the one
105            with the lowest session ID.
106         */
107
108         qsort(sidbuf, nelem, sizeof(sidbuf[0]), session_compare);
109
110         for (i = 0; i < nelem; i++) {
111                 error = dm_query_session(sidbuf[i], sizeof(buffer),
112                                 buffer, &rlen);
113                 if (error < 0) {
114                         fprintf(stderr, "unexpected dm_query_session "
115                                 "failure, %s\n", strerror(errno));
116                         free(sidbuf);
117                         exit(1);
118                 }
119
120                 if (!strncmp(buffer, TEST_MSG, strlen(TEST_MSG)))
121                         break;
122         }
123         if (i < nelem) {
124                 *session = (dm_sessid_t)sidbuf[i];
125                 free(sidbuf);
126                 return;
127         }
128
129         /* No test session exists, so we have to create one ourselves. */
130
131         if (dm_create_session(DM_NO_SESSION, TEST_MSG, &new_session) != 0) {
132                 fprintf(stderr, "dm_create_session failed, %s\n",
133                         strerror(errno));
134                 free(sidbuf);
135                 exit(1);
136         }
137
138         /* Now re-retrieve the list of active sessions. */
139
140         do {
141                 if (allocelem < nelem) {
142                         allocelem = nelem;
143                         sidbuf = realloc(sidbuf, nelem * sizeof(*sidbuf));
144                         if (sidbuf == NULL) {
145                                 fprintf(stderr, "realloc of %d bytes failed\n",
146                                         nelem * sizeof(*sidbuf));
147                                 exit(1);
148                         }
149                 }
150                 error = dm_getall_sessions(allocelem, sidbuf, &nelem);
151         } while (error < 0 && errno == E2BIG);
152
153         if (error < 0) {
154                 fprintf(stderr, "dm_getall_sessions failed, %s\n",
155                         strerror(errno));
156                 free(sidbuf);
157                 exit(1);
158         }
159
160         /* Sort the session ID list into ascending ID order, then find the
161            test session with the lowest session ID.  We better find at
162            least one since we created one!
163         */
164
165         qsort(sidbuf, nelem, sizeof(sidbuf[0]), session_compare);
166
167         for (i = 0; i < nelem; i++) {
168                 error = dm_query_session(sidbuf[i], sizeof(buffer),
169                                 buffer, &rlen);
170                 if (error < 0) {
171                         fprintf(stderr, "dm_query_session failed, %s\n",
172                                 strerror(errno));
173                         free(sidbuf);
174                         exit(1);
175                 }
176                 if (!strncmp(buffer, TEST_MSG, strlen(TEST_MSG)))
177                         break;
178         }
179         if (i == nelem) {
180                 fprintf(stderr, "can't find the session we created\n");
181                 free(sidbuf);
182                 exit(1);
183         }
184         *session = (dm_sessid_t)sidbuf[i];
185         free(sidbuf);
186
187         /* If the session we are going to use is not the one we created,
188            then we need to get rid of the created one.
189         */
190
191         if (*session != new_session) {
192                 if ((new_session) != 0) {
193                         fprintf(stderr, "dm_destroy_session failed, %s\n",
194                                 strerror(errno));
195                         exit(1);
196                 }
197         }
198 }