~ubuntu-branches/ubuntu/vivid/slurm-llnl/vivid

« back to all changes in this revision

Viewing changes to src/slurmd/slurmd/req.c

  • Committer: Bazaar Package Importer
  • Author(s): Gennaro Oliva
  • Date: 2009-09-24 23:28:15 UTC
  • mfrom: (1.1.11 upstream) (3.2.4 sid)
  • Revision ID: james.westby@ubuntu.com-20090924232815-enh65jn32q1ebg07
Tags: 2.0.5-1
* New upstream release 
* Changed dependecy from lib-mysqlclient15 to lib-mysqlclient 
* Added Default-Start for runlevel 2 and 4 and $remote_fs requirement in
  init.d scripts (Closes: #541252)
* Postinst checks for wrong runlevels 2 and 4 links
* Upgraded to standard version 3.8.3
* Add lintian overrides for missing slurm-llnl-configurator.html in doc
  base registration
* modified postrm scripts to ignore pkill return value in order to avoid
  postrm failure when no slurm process is running
* Checking for slurmctld.pid before cancelling running and pending
  jobs during package removal 

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*****************************************************************************\
2
2
 *  src/slurmd/slurmd/req.c - slurmd request handling
3
3
 *****************************************************************************
4
 
 *  Copyright (C) 2002-2006 The Regents of the University of California.
5
 
 *  Copyright (C) 2008 Lawrence Livermore National Security.
 
4
 *  Copyright (C) 2002-2007 The Regents of the University of California.
 
5
 *  Copyright (C) 2008-2009 Lawrence Livermore National Security.
6
6
 *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
7
7
 *  Written by Mark Grondona <mgrondona@llnl.gov>.
8
 
 *  LLNL-CODE-402394.
 
8
 *  CODE-OCEC-09-009. All rights reserved.
9
9
 *  
10
10
 *  This file is part of SLURM, a resource management program.
11
 
 *  For details, see <http://www.llnl.gov/linux/slurm/>.
 
11
 *  For details, see <https://computing.llnl.gov/linux/slurm/>.
 
12
 *  Please also read the included file: DISCLAIMER.
12
13
 *  
13
14
 *  SLURM is free software; you can redistribute it and/or modify it under
14
15
 *  the terms of the GNU General Public License as published by the Free
101
102
 
102
103
static int  _abort_job(uint32_t job_id);
103
104
static int  _abort_step(uint32_t job_id, uint32_t step_id);
104
 
static char ** _build_env(uint32_t jobid, uid_t uid, char *bg_part_id);
 
105
static char ** _build_env(uint32_t jobid, uid_t uid, char *resv_id);
105
106
static void _delay_rpc(int host_inx, int host_cnt, int usec_per_rpc);
106
107
static void _destroy_env(char **env);
107
108
static bool _slurm_authorized_user(uid_t uid);
132
133
static int  _rpc_step_complete(slurm_msg_t *msg);
133
134
static int  _rpc_stat_jobacct(slurm_msg_t *msg);
134
135
static int  _rpc_daemon_status(slurm_msg_t *msg);
135
 
static int  _run_prolog(uint32_t jobid, uid_t uid, char *bg_part_id);
136
 
static int  _run_epilog(uint32_t jobid, uid_t uid, char *bg_part_id);
 
136
static int  _run_prolog(uint32_t jobid, uid_t uid, char *resv_id);
 
137
static int  _run_epilog(uint32_t jobid, uid_t uid, char *resv_id);
137
138
 
138
139
static bool _pause_for_job_completion(uint32_t jobid, char *nodes, 
139
140
                int maxtime);
543
544
                }
544
545
                if (read(to_slurmd[0], &rc, sizeof(int)) != sizeof(int)) {
545
546
                        error("Error reading return code message "
546
 
                              " from slurmstepd: %m");
 
547
                              "from slurmstepd: %m");
547
548
                        rc = SLURM_FAILURE;
548
549
                }
549
550
 
560
561
                char slurm_stepd_path[MAXPATHLEN];
561
562
                char *const argv[2] = { slurm_stepd_path, NULL};
562
563
                int failed = 0;
563
 
                snprintf(slurm_stepd_path, sizeof(slurm_stepd_path),
564
 
                         "%s/sbin/slurmstepd", SLURM_PREFIX);
 
564
                if (conf->stepd_loc) {
 
565
                        snprintf(slurm_stepd_path, sizeof(slurm_stepd_path),
 
566
                                 "%s", conf->stepd_loc);
 
567
                } else {
 
568
                        snprintf(slurm_stepd_path, sizeof(slurm_stepd_path),
 
569
                                 "%s/sbin/slurmstepd", SLURM_PREFIX);
 
570
                }
 
571
 
565
572
                /*
566
573
                 * Child forks and exits
567
574
                 */
615
622
 * The job(step) credential is the only place to get a definitive
616
623
 * list of the nodes allocated to a job step.  We need to return
617
624
 * a hostset_t of the nodes. Validate the incoming RPC, updating 
618
 
 * job_mem and task_mem as needed.
 
625
 * job_mem needed.
619
626
 */
620
627
static int
621
628
_check_job_credential(launch_tasks_request_msg_t *req, uid_t uid,
631
638
        uint32_t         jobid = req->job_id;
632
639
        uint32_t         stepid = req->job_step_id;
633
640
        int              tasks_to_launch = req->tasks_to_launch[node_id];
 
641
        uint32_t         alloc_lps = 0;
 
642
 
634
643
        /*
635
644
         * First call slurm_cred_verify() so that all valid
636
645
         * credentials are checked
684
693
                goto fail;
685
694
        }
686
695
 
687
 
        if ((arg.alloc_lps_cnt > 0) && (tasks_to_launch > 0)) {
688
 
                host_index = hostset_find(hset, conf->node_name);
689
 
 
690
 
#if(0)
691
 
                /* Left for debugging purposes */
692
 
                if (host_index >= 0)
693
 
                  info(" cons_res %u alloc_lps_cnt %u "
694
 
                        "task[%d] = %u = task_to_launch %d host %s ", 
695
 
                        arg.jobid, arg.alloc_lps_cnt, host_index, 
696
 
                        arg.alloc_lps[host_index], 
697
 
                        tasks_to_launch, conf->node_name);
698
 
#endif
699
 
 
700
 
                if (host_index < 0) { 
 
696
        if ((arg.job_nhosts > 0) && (tasks_to_launch > 0)) {
 
697
                uint32_t i, i_first_bit=0, i_last_bit=0;
 
698
                host_index = hostset_find(hset, conf->node_name);
 
699
                if ((host_index < 0) || (host_index >= arg.job_nhosts)) { 
701
700
                        error("job cr credential invalid host_index %d for "
702
701
                              "job %u", host_index, arg.jobid);
703
702
                        goto fail; 
704
703
                }
705
 
                if (host_index > arg.alloc_lps_cnt)
706
 
                        error("host_index > alloc_lps_cnt in credential");
707
 
                else if (arg.alloc_lps[host_index] == 0)
 
704
                host_index++;   /* change from 0-origin to 1-origin */
 
705
                for (i=0; host_index; i++) {
 
706
                        if (host_index > arg.sock_core_rep_count[i]) {
 
707
                                i_first_bit += arg.sockets_per_node[i] *
 
708
                                               arg.cores_per_socket[i] *
 
709
                                               arg.sock_core_rep_count[i];
 
710
                                host_index -= arg.sock_core_rep_count[i];
 
711
                        } else {
 
712
                                i_first_bit += arg.sockets_per_node[i] *
 
713
                                               arg.cores_per_socket[i] *
 
714
                                               (host_index - 1);
 
715
                                i_last_bit = i_first_bit +
 
716
                                             arg.sockets_per_node[i] *
 
717
                                             arg.cores_per_socket[i];
 
718
                                break;
 
719
                        }
 
720
                }
 
721
                /* Now count the allocated processors */
 
722
                for (i = i_first_bit; i < i_last_bit; i++) {
 
723
                        if (bit_test(arg.core_bitmap, i))
 
724
                                alloc_lps++;
 
725
                }
 
726
                if (alloc_lps == 0) {
708
727
                        error("cons_res: zero processors allocated to step");
709
 
                if (tasks_to_launch > arg.alloc_lps[host_index]) {
710
 
                        /* This is expected with the --overcommit option */
711
 
                        verbose("cons_res: More than one tasks per logical "
712
 
                                "processor (%d > %u) on host [%u.%u %ld %s] ",
713
 
                                tasks_to_launch, arg.alloc_lps[host_index], 
714
 
                                arg.jobid, arg.stepid, (long) arg.uid, 
715
 
                                arg.hostlist);
716
 
                        verbose("cons_res: Use task/affinity plug-in to bind "
717
 
                                "the tasks to the allocated resources");
718
 
                }
719
 
        }
 
728
                        alloc_lps = 1;
 
729
                }
 
730
                if (tasks_to_launch > alloc_lps) {
 
731
                        /* This is expected with the --overcommit option
 
732
                         * or hyperthreads */
 
733
                        debug("cons_res: More than one tasks per logical "
 
734
                              "processor (%d > %u) on host [%u.%u %ld %s] ",
 
735
                              tasks_to_launch, alloc_lps, arg.jobid,
 
736
                              arg.stepid, (long) arg.uid, arg.hostlist);
 
737
                }
 
738
                /* NOTE: alloc_lps is the count of allocated resources
 
739
                 * (typically cores). Convert to CPU count as needed */
 
740
                if (i_last_bit <= i_first_bit)
 
741
                        error("step credential has no CPUs selected");
 
742
                else {
 
743
                        i = conf->cpus / (i_last_bit - i_first_bit);
 
744
                        if (i > 1)
 
745
                                alloc_lps *= i;
 
746
                }
 
747
        } else
 
748
                alloc_lps = 1;
720
749
 
721
750
        /* Overwrite any memory limits in the RPC with contents of the 
722
751
         * memory limit within the credential. 
723
752
         * Reset the CPU count on this node to correct value. */
724
753
        if (arg.job_mem & MEM_PER_CPU) {
725
754
                req->job_mem = arg.job_mem & (~MEM_PER_CPU);
726
 
                if ((host_index >= 0) && (host_index < arg.alloc_lps_cnt) &&
727
 
                    (arg.alloc_lps[host_index] > 0))
728
 
                        req->job_mem *= arg.alloc_lps[host_index];
 
755
                req->job_mem *= alloc_lps;
729
756
        } else
730
757
                req->job_mem = arg.job_mem;
731
 
        req->task_mem = arg.task_mem;   /* Defunct */
732
 
        if ((host_index >= 0) && (host_index < arg.alloc_lps_cnt))
733
 
                req->cpus_allocated[node_id] = arg.alloc_lps[host_index];
 
758
        req->cpus_allocated[node_id] = alloc_lps;
734
759
#if 0
735
760
        info("mem orig:%u cpus:%u limit:%u", 
736
 
             arg.job_mem, arg.alloc_lps[host_index], req->job_mem);
 
761
             arg.job_mem, alloc_lps, req->job_mem);
737
762
#endif
738
763
 
739
764
        *step_hset = hset;
893
918
        }
894
919
        snprintf(err_name, 128, "Error running slurm prolog: %d\n", 
895
920
                WEXITSTATUS(rc));
896
 
        write(fd, err_name, strlen(err_name));
897
 
        fchown(fd, (uid_t) req->uid, (gid_t) req->gid);
 
921
        safe_write(fd, err_name, strlen(err_name));
 
922
        if(fchown(fd, (uid_t) req->uid, (gid_t) req->gid) == -1)
 
923
                snprintf(err_name, 128,
 
924
                         "Couldn't change fd owner to %u:%u: %m\n", 
 
925
                         req->uid, req->gid);
 
926
rwfail:
898
927
        close(fd);
899
928
}
900
929
 
949
978
 
950
979
        if (slurm_cred_get_args(req->cred, &arg) != SLURM_SUCCESS)
951
980
                return;
952
 
 
 
981
                
953
982
        if (arg.job_mem & MEM_PER_CPU) {
 
983
                int i;
 
984
                uint32_t alloc_lps = 0, last_bit = 0;   
 
985
                if (arg.job_nhosts > 0) {
 
986
                        last_bit = arg.sockets_per_node[0] * 
 
987
                                   arg.cores_per_socket[0];
 
988
                        for (i=0; i<last_bit; i++) {
 
989
                                if (bit_test(arg.core_bitmap, i))
 
990
                                        alloc_lps++;
 
991
                        }
 
992
                }
 
993
                if (alloc_lps == 0) {
 
994
                        error("_set_batch_job_limit: alloc_lps is zero");
 
995
                        alloc_lps = 1;
 
996
                }
 
997
 
 
998
                /* NOTE: alloc_lps is the count of allocated resources
 
999
                 * (typically cores). Convert to CPU count as needed */
 
1000
                if (last_bit < 1)
 
1001
                        error("Batch job credential allocates no CPUs");
 
1002
                else {
 
1003
                        i = conf->cpus / last_bit;
 
1004
                        if (i > 1)
 
1005
                                alloc_lps *= i;
 
1006
                }
 
1007
 
954
1008
                req->job_mem = arg.job_mem & (~MEM_PER_CPU);
955
 
                if (arg.alloc_lps_cnt > 1)
956
 
                        req->job_mem *= arg.alloc_lps_cnt;
 
1009
                req->job_mem *= alloc_lps;
957
1010
        } else
958
1011
                req->job_mem = arg.job_mem;
959
1012
 
967
1020
        bool     first_job_run = true;
968
1021
        int      rc = SLURM_SUCCESS;
969
1022
        uid_t    req_uid = g_slurm_auth_get_uid(msg->auth_cred, NULL);
970
 
        char    *bg_part_id = NULL;
 
1023
        char    *resv_id = NULL;
971
1024
        bool     replied = false;
972
1025
        slurm_addr *cli = &msg->orig_addr;
973
1026
        
985
1038
                goto done;
986
1039
        }
987
1040
 
 
1041
        slurmd_batch_request(req->job_id, req); /* determine task affinity */
 
1042
 
988
1043
        if ((req->step_id != SLURM_BATCH_SCRIPT) && (req->step_id != 0))
989
1044
                first_job_run = false;
990
1045
 
1015
1070
                /* 
1016
1071
                 * Run job prolog on this node
1017
1072
                 */
1018
 
                select_g_get_jobinfo(req->select_jobinfo, 
1019
 
                                     SELECT_DATA_BLOCK_ID, 
1020
 
                                     &bg_part_id);
1021
 
 
1022
 
                rc = _run_prolog(req->job_id, req->uid, bg_part_id);
1023
 
                xfree(bg_part_id);
 
1073
#ifdef HAVE_BG
 
1074
                select_g_get_jobinfo(req->select_jobinfo, 
 
1075
                                     SELECT_DATA_BLOCK_ID, &resv_id);
 
1076
#endif
 
1077
#ifdef HAVE_CRAY_XT
 
1078
                select_g_get_jobinfo(req->select_jobinfo, 
 
1079
                                     SELECT_DATA_RESV_ID, &resv_id);
 
1080
#endif
 
1081
                rc = _run_prolog(req->job_id, req->uid, resv_id);
 
1082
                xfree(resv_id);
1024
1083
                if (rc) {
1025
1084
                        int term_sig, exit_status;
1026
1085
                        if (WIFSIGNALED(rc)) {
1356
1415
{
1357
1416
        int        rc = SLURM_SUCCESS;
1358
1417
        uid_t req_uid = g_slurm_auth_get_uid(msg->auth_cred, NULL);
 
1418
        static bool first_msg = true;
1359
1419
 
1360
1420
        if (!_slurm_authorized_user(req_uid)) {
1361
1421
                error("Security violation, ping RPC from uid %u",
1362
1422
                      (unsigned int) req_uid);
 
1423
                if (first_msg) {
 
1424
                        error("Do you have SlurmUser configured as uid %u?",
 
1425
                             (unsigned int) req_uid);
 
1426
                }
1363
1427
                rc = ESLURM_USER_ID_MISSING;    /* or bad in this case */
1364
1428
        }
 
1429
        first_msg = false;
1365
1430
 
1366
1431
        /* Return result. If the reply can't be sent this indicates that
1367
1432
         * 1. The network is broken OR
1387
1452
        uid_t req_uid = g_slurm_auth_get_uid(msg->auth_cred, NULL);
1388
1453
 
1389
1454
        if (!_slurm_authorized_user(req_uid)) {
1390
 
                error("Security violation, ping RPC from uid %u",
 
1455
                error("Security violation, health check RPC from uid %u",
1391
1456
                      (unsigned int) req_uid);
1392
1457
                rc = ESLURM_USER_ID_MISSING;    /* or bad in this case */
1393
1458
        }
1513
1578
                goto done3;
1514
1579
        }
1515
1580
 
1516
 
        rc = stepd_checkpoint(fd, req->signal, req->timestamp);
 
1581
        rc = stepd_checkpoint(fd, req->timestamp, req->image_dir);
1517
1582
        if (rc == -1)
1518
1583
                rc = ESLURMD_JOB_NOTRUNNING;
1519
1584
 
2565
2630
                while ((stepd = list_next(i))) {
2566
2631
                        if (stepd->jobid != req->job_id) {
2567
2632
                                /* multiple jobs expected on shared nodes */
2568
 
                                debug3("Step from other job: jobid=%u (this jobid=%u)",
 
2633
                                debug3("Step from other job: jobid=%u "
 
2634
                                       "(this jobid=%u)",
2569
2635
                                      stepd->jobid, req->job_id);
2570
2636
                                continue;
2571
2637
                        }
2625
2691
{
2626
2692
        kill_job_msg_t *req    = msg->data;
2627
2693
        uid_t           uid    = g_slurm_auth_get_uid(msg->auth_cred, NULL);
2628
 
        char           *bg_part_id = NULL;
 
2694
        char           *resv_id = NULL;
2629
2695
 
2630
2696
        debug("_rpc_abort_job, uid = %d", uid);
2631
2697
        /* 
2682
2748
        }
2683
2749
 
2684
2750
        save_cred_state(conf->vctx);
2685
 
 
 
2751
#ifdef HAVE_BG
2686
2752
        select_g_get_jobinfo(req->select_jobinfo, SELECT_DATA_BLOCK_ID,
2687
 
                &bg_part_id);
2688
 
        _run_epilog(req->job_id, req->job_uid, bg_part_id);
2689
 
        xfree(bg_part_id);
 
2753
                             &resv_id);
 
2754
#endif
 
2755
#ifdef HAVE_CRAY_XT
 
2756
        select_g_get_jobinfo(req->select_jobinfo, SELECT_DATA_RESV_ID,
 
2757
                             &resv_id);
 
2758
#endif
 
2759
        _run_epilog(req->job_id, req->job_uid, resv_id);
 
2760
        xfree(resv_id);
2690
2761
}
2691
2762
 
2692
2763
static void 
2697
2768
        uid_t           uid    = g_slurm_auth_get_uid(msg->auth_cred, NULL);
2698
2769
        int             nsteps = 0;
2699
2770
        int             delay;
2700
 
        char           *bg_part_id = NULL;
 
2771
        char           *resv_id = NULL;
2701
2772
        uint16_t        base_job_state = req->job_state & (~JOB_COMPLETING);
2702
2773
        slurm_ctl_conf_t *cf;
2703
2774
 
2779
2850
                        slurm_send_rc_msg(msg,
2780
2851
                                          ESLURMD_KILL_JOB_ALREADY_COMPLETE);
2781
2852
                slurm_cred_begin_expiration(conf->vctx, req->job_id);
 
2853
                save_cred_state(conf->vctx);
2782
2854
                _waiter_complete(req->job_id);
 
2855
 
 
2856
                /* 
 
2857
                 * The controller needs to get MESSAGE_EPILOG_COMPLETE to bring
 
2858
                 * the job out of "completing" state.  Otherwise, the job
 
2859
                 * could remain "completing" unnecessarily, until the request 
 
2860
                 * to terminate is resent.
 
2861
                 */
 
2862
                _sync_messages_kill(req);
 
2863
                _epilog_complete(req->job_id, rc);
2783
2864
                return;
2784
2865
        }
2785
2866
#endif
2824
2905
 
2825
2906
        save_cred_state(conf->vctx);
2826
2907
 
 
2908
#ifdef HAVE_BG
2827
2909
        select_g_get_jobinfo(req->select_jobinfo, SELECT_DATA_BLOCK_ID,
2828
 
                &bg_part_id);
2829
 
        rc = _run_epilog(req->job_id, req->job_uid, bg_part_id);
2830
 
        xfree(bg_part_id);
 
2910
                             &resv_id);
 
2911
#endif
 
2912
#ifdef HAVE_CRAY_XT
 
2913
        select_g_get_jobinfo(req->select_jobinfo, SELECT_DATA_RESV_ID,
 
2914
                             &resv_id);
 
2915
#endif
 
2916
        rc = _run_epilog(req->job_id, req->job_uid, resv_id);
 
2917
        xfree(resv_id);
2831
2918
        
2832
2919
        if (rc) {
2833
2920
                int term_sig, exit_status;
3035
3122
        slurm_send_rc_msg(msg, rc);
3036
3123
}
3037
3124
 
3038
 
/* NOTE: xfree returned value */
 
3125
/* NOTE: call _destroy_env() to free returned value */
3039
3126
static char **
3040
 
_build_env(uint32_t jobid, uid_t uid, char *bg_part_id)
 
3127
_build_env(uint32_t jobid, uid_t uid, char *resv_id)
3041
3128
{
 
3129
        char *name;
3042
3130
        char **env = xmalloc(sizeof(char *));
 
3131
 
3043
3132
        env[0]  = NULL;
 
3133
        setenvf(&env, "SLURM_JOB_ID", "%u", jobid);
 
3134
        setenvf(&env, "SLURM_JOB_UID",   "%u", uid);
 
3135
        name = uid_to_string(uid);
 
3136
        setenvf(&env, "SLURM_JOB_USER", "%s", name);
 
3137
        xfree(name);
3044
3138
        setenvf(&env, "SLURM_JOBID", "%u", jobid);
3045
3139
        setenvf(&env, "SLURM_UID",   "%u", uid);
3046
 
        if (bg_part_id) {
3047
 
                setenvf(&env, "MPIRUN_PARTITION",
3048
 
                        "%s", bg_part_id);
 
3140
        if (resv_id) {
 
3141
#ifdef HAVE_BG
 
3142
                setenvf(&env, "MPIRUN_PARTITION", "%s", resv_id);
 
3143
#endif
 
3144
#ifdef HAVE_CRAY_XT
 
3145
                setenvf(&env, "BASIL_RESERVATION_ID", "%s", resv_id);
 
3146
#endif
3049
3147
        }
3050
3148
        return env;
3051
3149
}
3066
3164
}
3067
3165
 
3068
3166
static int 
3069
 
_run_prolog(uint32_t jobid, uid_t uid, char *bg_part_id)
 
3167
_run_prolog(uint32_t jobid, uid_t uid, char *resv_id)
3070
3168
{
3071
3169
        int error_code;
3072
3170
        char *my_prolog;
3073
 
        char **my_env = _build_env(jobid, uid, bg_part_id);
 
3171
        char **my_env = _build_env(jobid, uid, resv_id);
 
3172
        time_t start_time = time(NULL), diff_time;
 
3173
        static uint16_t msg_timeout = 0;
3074
3174
 
3075
3175
        slurm_mutex_lock(&conf->config_mutex);
3076
3176
        my_prolog = xstrdup(conf->prolog);
3080
3180
        xfree(my_prolog);
3081
3181
        _destroy_env(my_env);
3082
3182
 
 
3183
        diff_time = difftime(time(NULL), start_time);
 
3184
        if (msg_timeout == 0)
 
3185
                msg_timeout = slurm_get_msg_timeout();
 
3186
        if (diff_time >= msg_timeout) {
 
3187
                error("prolog for job %u ran for %d seconds", 
 
3188
                      jobid, diff_time);
 
3189
        }
 
3190
 
3083
3191
        return error_code;
3084
3192
}
3085
3193
 
3086
3194
static int 
3087
 
_run_epilog(uint32_t jobid, uid_t uid, char *bg_part_id)
 
3195
_run_epilog(uint32_t jobid, uid_t uid, char *resv_id)
3088
3196
{
3089
3197
        int error_code;
3090
3198
        char *my_epilog;
3091
 
        char **my_env = _build_env(jobid, uid, bg_part_id);
 
3199
        char **my_env = _build_env(jobid, uid, resv_id);
3092
3200
 
3093
3201
        slurm_mutex_lock(&conf->config_mutex);
3094
3202
        my_epilog = xstrdup(conf->epilog);
3228
3336
                return NULL;
3229
3337
        }
3230
3338
        gg = (gid_t *)xmalloc(n * sizeof(gid_t));
3231
 
        getgroups(n, gg);
 
3339
        if(getgroups(n, gg) == -1) {
 
3340
                error("_getgroups: couldn't get %d groups: %m", n);
 
3341
                xfree(gg);
 
3342
                return NULL;
 
3343
        }
3232
3344
        return _alloc_gids(n, gg);
3233
3345
}
3234
3346
 
3255
3367
                return;
3256
3368
        }
3257
3369
        orig_gids = (gid_t *)xmalloc(ngids * sizeof(gid_t));
3258
 
        getgroups(ngids, orig_gids);
 
3370
        if(getgroups(ngids, orig_gids) == -1) {
 
3371
                error("init_gids_cache: couldn't get %d groups: %m", ngids);
 
3372
                xfree(orig_gids);
 
3373
                return;
 
3374
        }
3259
3375
 
3260
3376
#ifdef HAVE_AIX
3261
3377
        setpwent_r(&fp);