LCOV - code coverage report
Current view: top level - nsswitch - stress-nss-libwbclient.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 81 141 57.4 %
Date: 2024-04-21 15:09:00 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    Stress test for parallel NSS & libwbclient calls.
       5             : 
       6             :    Copyright (C) Ralph Wuerthner 2018
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include <stdio.h>
      23             : #include <stdint.h>
      24             : #include <stdbool.h>
      25             : #include <pthread.h>
      26             : #include <string.h>
      27             : #include <unistd.h>
      28             : #include <time.h>
      29             : #include <stdlib.h>
      30             : #include <sys/types.h>
      31             : #include <pwd.h>
      32             : #include <wbclient.h>
      33             : #include <sys/socket.h>
      34             : #include <errno.h>
      35             : #include <assert.h>
      36             : 
      37             : #define RUNTIME 10
      38             : 
      39             : struct thread_state {
      40             :         const char *username;
      41             :         time_t timeout;
      42             :         pthread_mutex_t lock;
      43             :         bool fail;
      44             :         int nss_loop_count;
      45             :         int wbc_loop_count;
      46             : };
      47             : 
      48           2 : static void *query_nss_thread(void *ptr)
      49             : {
      50           2 :         struct thread_state *state = ptr;
      51             :         char buf[1024];
      52             :         ssize_t nread, nwritten;
      53             :         int p[2];
      54             :         int rc;
      55             :         struct passwd pwd, *result;
      56             :         pid_t pid;
      57             : 
      58       47140 :         while (time(NULL) < state->timeout) {
      59       47138 :                 rc = getpwnam_r(state->username,
      60             :                                 &pwd,
      61             :                                 buf,
      62             :                                 sizeof(buf),
      63             :                                 &result);
      64       47138 :                 if (rc != 0 || result == NULL) {
      65           0 :                         pthread_mutex_lock(&state->lock);
      66           0 :                         state->fail = true;
      67           0 :                         pthread_mutex_unlock(&state->lock);
      68           0 :                         fprintf(stderr,
      69             :                                 "getpwnam_r failed with rc='%s' result=%p\n",
      70             :                                 strerror(rc),
      71             :                                 result);
      72           0 :                         break;
      73             :                 }
      74       47138 :                 state->nss_loop_count++;
      75       47138 :                 pthread_mutex_lock(&state->lock);
      76       47138 :                 if (state->fail) {
      77           0 :                         pthread_mutex_unlock(&state->lock);
      78           0 :                         break;
      79             :                 }
      80       47138 :                 pthread_mutex_unlock(&state->lock);
      81             :         }
      82             : 
      83           2 :         rc = socketpair(AF_UNIX, SOCK_STREAM, 0, p);
      84           2 :         if (rc != 0) {
      85           0 :                 state->fail = true;
      86           0 :                 return NULL;
      87             :         }
      88             : 
      89             :         /*
      90             :          * Check getpwnam_r() still works after a fork,
      91             :          * both in parent and child.
      92             :          */
      93             : 
      94           2 :         pid = fork();
      95           4 :         if (pid == -1) {
      96           0 :                 return NULL;
      97             :         }
      98           4 :         if (pid == 0) {
      99             :                 /* Child */
     100           2 :                 rc = getpwnam_r(state->username,
     101             :                                 &pwd,
     102             :                                 buf,
     103             :                                 sizeof(buf),
     104             :                                 &result);
     105           2 :                 if (rc != 0 || result == NULL) {
     106           0 :                         fprintf(stderr,
     107             :                                 "getpwnam_r failed with rc='%s' result=%p\n",
     108             :                                 strerror(rc),
     109             :                                 result);
     110           0 :                         rc = 1;
     111           0 :                         nwritten = write(p[0], &rc, sizeof(int));
     112           0 :                         assert(nwritten == sizeof(int));
     113           0 :                         exit(1);
     114             :                 }
     115           2 :                 printf("child: getpwnam_r in child succeeded\n");
     116           2 :                 rc = 0;
     117           2 :                 nwritten = write(p[0], &rc, sizeof(int));
     118           2 :                 assert(nwritten == sizeof(int));
     119           2 :                 exit(1);
     120             :         }
     121             : 
     122             :         /* Parent */
     123             : 
     124             :         /* Check result from child */
     125           2 :         nread = read(p[1], &rc, sizeof(int));
     126           2 :         if (nread != sizeof(int)) {
     127           0 :                 fprintf(stderr,
     128             :                         "read from child failed with errno='%s' nread=%zd\n",
     129           0 :                         strerror(errno),
     130             :                         nread);
     131           0 :                 state->fail = true;
     132           0 :                 return NULL;
     133             :         }
     134             : 
     135           2 :         if (rc != 0) {
     136           0 :                 fprintf(stderr,
     137             :                         "getpwnam_r failed in the child\n");
     138           0 :                 state->fail = true;
     139           0 :                 return NULL;
     140             :         }
     141           2 :         printf("parent: getpwnam_r in child succeeded\n");
     142             : 
     143             :         /* Verify getpwnam_r() in parent after fork */
     144           2 :         rc = getpwnam_r(state->username,
     145             :                         &pwd,
     146             :                         buf,
     147             :                         sizeof(buf),
     148             :                         &result);
     149           2 :         if (rc != 0 || result == NULL) {
     150           0 :                 fprintf(stderr,
     151             :                         "getpwnam_r failed with rc='%s' result=%p\n",
     152             :                         strerror(rc),
     153             :                         result);
     154           0 :                 state->fail = true;
     155           0 :                 return NULL;
     156             :         }
     157           2 :         printf("parent: getpwnam_r in parent succeeded\n");
     158           2 :         return NULL;
     159             : }
     160             : 
     161           2 : static void *query_wbc_thread(void *ptr)
     162             : {
     163           2 :         struct thread_state *state = ptr;
     164             :         struct passwd *ppwd;
     165             :         wbcErr wbc_status;
     166             :         pid_t pid;
     167             :         ssize_t nread, nwritten;
     168             :         int p[2];
     169             :         int rc;
     170             : 
     171       47176 :         while (time(NULL) < state->timeout) {
     172       47174 :                 wbc_status = wbcGetpwnam(state->username, &ppwd);
     173       47174 :                 if (!WBC_ERROR_IS_OK(wbc_status)) {
     174           0 :                         pthread_mutex_lock(&state->lock);
     175           0 :                         state->fail = true;
     176           0 :                         pthread_mutex_unlock(&state->lock);
     177           0 :                         fprintf(stderr,
     178             :                                 "wbcGetpwnam failed with %s\n",
     179             :                                 wbcErrorString(wbc_status));
     180           0 :                         break;
     181             :                 }
     182       47174 :                 wbcFreeMemory(ppwd);
     183       47174 :                 state->wbc_loop_count++;
     184       47174 :                 pthread_mutex_lock(&state->lock);
     185       47174 :                 if (state->fail) {
     186           0 :                         pthread_mutex_unlock(&state->lock);
     187           0 :                         break;
     188             :                 }
     189       47174 :                 pthread_mutex_unlock(&state->lock);
     190             :         }
     191             : 
     192           2 :         rc = socketpair(AF_UNIX, SOCK_STREAM, 0, p);
     193           2 :         if (rc != 0) {
     194           0 :                 state->fail = true;
     195           0 :                 return NULL;
     196             :         }
     197             : 
     198             :         /*
     199             :          * Check wbcGetpwnam() still works after a fork,
     200             :          * both in parent and child.
     201             :          */
     202             : 
     203           2 :         pid = fork();
     204           4 :         if (pid == -1) {
     205           0 :                 return NULL;
     206             :         }
     207           4 :         if (pid == 0) {
     208             :                 /* Child */
     209           2 :                 wbc_status = wbcGetpwnam(state->username, &ppwd);
     210           2 :                 if (!WBC_ERROR_IS_OK(wbc_status)) {
     211           0 :                         fprintf(stderr,
     212             :                                 "wbcGetpwnam failed with %s\n",
     213             :                                 wbcErrorString(wbc_status));
     214           0 :                         rc = 1;
     215           0 :                         nwritten = write(p[0], &rc, sizeof(int));
     216           0 :                         assert(nwritten == sizeof(int));
     217           0 :                         exit(1);
     218             :                 }
     219           2 :                 wbcFreeMemory(ppwd);
     220           2 :                 printf("child: wbcGetpwnam in child succeeded\n");
     221           2 :                 rc = 0;
     222           2 :                 nwritten = write(p[0], &rc, sizeof(int));
     223           2 :                 assert(nwritten == sizeof(int));
     224           2 :                 exit(1);
     225             :         }
     226             : 
     227             :         /* Parent */
     228             : 
     229             :         /* Check result from child */
     230           2 :         nread = read(p[1], &rc, sizeof(int));
     231           2 :         if (nread != sizeof(int)) {
     232           0 :                 fprintf(stderr,
     233             :                         "read from child failed with errno='%s' nread=%zd\n",
     234           0 :                         strerror(errno),
     235             :                         nread);
     236           0 :                 state->fail = true;
     237           0 :                 return NULL;
     238             :         }
     239             : 
     240           2 :         if (rc != 0) {
     241           0 :                 fprintf(stderr,
     242             :                         "wbcGetpwnam failed in the child\n");
     243           0 :                 state->fail = true;
     244           0 :                 return NULL;
     245             :         }
     246           2 :         printf("parent: wbcGetpwnam in child succeeded\n");
     247             : 
     248             :         /* Verify wbcGetpwnam() in parent after fork */
     249           2 :         wbc_status = wbcGetpwnam(state->username, &ppwd);
     250           2 :         if (!WBC_ERROR_IS_OK(wbc_status)) {
     251           0 :                 fprintf(stderr,
     252             :                         "wbcGetpwnam failed with %s\n",
     253             :                         wbcErrorString(wbc_status));
     254           0 :                 state->fail = true;
     255           0 :                 return NULL;
     256             :         }
     257           2 :         wbcFreeMemory(ppwd);
     258           2 :         printf("parent: wbcGetpwnam in parent succeeded\n");
     259           2 :         return NULL;
     260             : }
     261             : 
     262           2 : int main(int argc, char *argv[])
     263             : {
     264             :         int rc, n;
     265             :         struct thread_state state;
     266             :         pthread_t threads[2];
     267             : 
     268           2 :         if (argc < 2 ) {
     269           0 :                 fprintf(stderr,"%s: missing domain user\n", argv[0]);
     270           0 :                 return 1;
     271             :         }
     272             : 
     273           2 :         state.username = argv[1];
     274           2 :         state.timeout = time(NULL) + RUNTIME;
     275           2 :         rc = pthread_mutex_init(&state.lock, NULL);
     276           2 :         if (rc != 0) {
     277           0 :                 fprintf(stderr,
     278             :                         "pthread_mutex_init failed: %s\n",
     279             :                         strerror(rc));
     280           0 :                 exit(1);
     281             :         }
     282           2 :         state.fail = false;
     283           2 :         state.nss_loop_count = 0;
     284           2 :         state.wbc_loop_count = 0;
     285             : 
     286           2 :         printf("query domain user '%s'\n", state.username);
     287             : 
     288             :         /* create query threads */
     289           2 :         rc = pthread_create(&threads[0], NULL, query_nss_thread, &state);
     290           2 :         if (rc != 0) {
     291           0 :                 fprintf(stderr,
     292             :                         "creating NSS thread failed: %s\n",
     293             :                         strerror(rc));
     294           0 :                 exit(1);
     295             :         }
     296           2 :         rc = pthread_create(&threads[1], NULL, query_wbc_thread, &state);
     297           2 :         if (rc != 0) {
     298           0 :                 fprintf(stderr,
     299             :                         "creating libwbclient thread failed: %s\n",
     300             :                         strerror(rc));
     301           0 :                 exit(1);
     302             :         }
     303             : 
     304             :         /* wait for query threads to terminate */
     305           6 :         for (n = 0; n < 2; n++) {
     306           4 :                 rc = pthread_join(threads[n], NULL);
     307           4 :                 if (rc != 0) {
     308           0 :                         fprintf(stderr,
     309             :                                 "joining query thread %i failed: %s\n",
     310             :                                 n,
     311             :                                 strerror(rc));
     312           0 :                         exit(1);
     313             :                 }
     314             :         }
     315             : 
     316           2 :         fprintf(state.fail ? stderr: stdout,
     317             :                 "test %s with %i NSS and %i libwbclient calls\n",
     318           2 :                 state.fail ? "failed" : "passed",
     319             :                 state.nss_loop_count,
     320             :                 state.wbc_loop_count);
     321             : 
     322           2 :         return state.fail;
     323             : }

Generated by: LCOV version 1.14