Newer
Older
/*
* node_scheduler.c - Allocated nodes to jobs
* See slurm.h for documentation on external functions and data structures
*
* NOTE: DEBUG_MODULE mode test with execution line
* node_scheduler ../../etc/SLURM.conf2 ../../etc/SLURM.jobs
*
* Author: Moe Jette, jette@llnl.gov
*/
#define DEBUG_SYSTEM 1
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
#include "slurm.h"
#define BUF_SIZE 1024
#define NO_VAL (-99)
int Is_Key_Valid(int Key);
int Match_Group(char *AllowGroups, char *UserGroups);
int Parse_Job_Specs(char *Job_Specs, char **Req_Features, char **Req_Node_List, char **Job_Name,
char **Req_Group, char **Req_Partition, int *Contiguous, int *Req_CPUs,
int *Req_Nodes, int *Min_CPUs, int *Min_Memory, int *Min_TmpDisk, int *Key);
int ValidFeatures(char *Requested, char *Available);
#if DEBUG_MODULE
/* main is used here for testing purposes only */
main(int argc, char * argv[]) {
int Error_Code, Line_Num;
FILE *Command_File;
char In_Line[BUF_SIZE], *Node_List;
if (argc < 3) {
printf("Usage: %s <slurm_conf_file> <slurm_job_file>\n", argv[0]);
exit(0);
} /* if */
Error_Code = Init_SLURM_Conf();
if (Error_Code) {
printf("controller: Error %d from Init_SLURM_Conf\n", Error_Code);
exit(Error_Code);
} /* if */
Error_Code = Read_SLURM_Conf(argv[1]);
if (Error_Code) {
printf("controller: Error %d from Read_SLURM_Conf\n", Error_Code);
exit(Error_Code);
} /* if */
Command_File = fopen(argv[2], "r");
if (Command_File == NULL) {
fprintf(stderr, "node_scheduler: error %d opening command file %s\n",
errno, argv[2]);
exit(1);
} /* if */
Line_Num = 0;
while (fgets(In_Line, BUF_SIZE, Command_File)) {
if (In_Line[strlen(In_Line)-1] == '\n') In_Line[strlen(In_Line)-1]=(char)NULL;
Line_Num++;
Error_Code = Allocate_Nodes(In_Line, &Node_List);
if (Error_Code) {
if (strncmp(In_Line, "JobName=FAIL", 12) != 0) printf("ERROR:");
printf("For job: %s\n", In_Line, Node_List);
printf("node_scheduler: Error %d from Allocate_Nodes on line %d\n\n", Error_Code, Line_Num);
} else {
if (strncmp(In_Line, "JobName=FAIL", 12) == 0) printf("ERROR: ");
printf("For job: %s\n Nodes selected %s\n\n", In_Line, Node_List);
free(Node_List);
} /* else */
} /* while */
} /* main */
#endif
/*
* Allocate_Nodes - Allocate nodes to a job with the given specifications
* Input: Job_Specs - Job specifications
* Node_List - Pointer to node list returned
* Output: Node_List - List of allocated nodes
* Returns 0 on success, EINVAL if not possible to satisfy request,
* or EAGAIN if resources are presently busy
* NOTE: The calling program must free the memory pointed to by Node_List
*/
int Allocate_Nodes(char *Job_Specs, char **Node_List) {
char *Req_Features, *Req_Node_List, *Job_Name, *Req_Group, *Req_Partition, *Out_Line;
int Contiguous, Req_CPUs, Req_Nodes, Min_CPUs, Min_Memory, Min_TmpDisk;
int Error_Code, CPU_Tally, Node_Tally, Key;
struct Part_Record *Part_Ptr;
unsigned *Req_BitMap, *Scratch_BitMap;
ListIterator Config_Record_Iterator; /* For iterating through Config_List */
struct Config_Record *Config_Record_Point; /* Pointer to Config_Record */
int i;
struct Node_Set { /* Set of jobs with same weight that could be allocated */
int CPUs_Per_Node;
int Nodes;
unsigned *My_BitMap;
} *Node_Set_Ptr;
int Node_Set_Index, Node_Set_Size;
Req_Features = Req_Node_List = Req_Group = Req_Partition = NULL;
Req_BitMap = Scratch_BitMap = NULL;
Contiguous = Req_CPUs = Req_Nodes = Min_CPUs = Min_Memory = Min_TmpDisk = Key = NO_VAL;
Node_Set_Ptr = NULL;
Config_Record_Iterator = NULL;
Node_List[0] = NULL;
/* Setup and basic parsing */
Error_Code = Parse_Job_Specs(Job_Specs, &Req_Features, &Req_Node_List, &Job_Name, &Req_Group,
&Req_Partition, &Contiguous, &Req_CPUs, &Req_Nodes, &Min_CPUs,
&Min_Memory, &Min_TmpDisk, &Key);
if (Error_Code == ENOMEM) {
Error_Code = EAGAIN; /* Don't want to kill the job off */
goto cleanup;
} /* if */
if (Error_Code != 0) {
Error_Code = EINVAL; /* Permanent error, invalid parsing */
#if DEBUG_SYSTEM
fprintf(stderr, "Allocate_Nodes: Parsing failure on %s\n", Job_Specs);
#else
syslog(LOG_NOTICE, "Allocate_Nodes: Parsing failure on %s\n", Job_Specs);
#endif
goto cleanup;
} /* if */
if ((Req_CPUs == NO_VAL) && (Req_Nodes == NO_VAL) && (Req_Node_List == NULL)) {
#if DEBUG_SYSTEM
fprintf(stderr, "Allocate_Nodes: Job failed to specify NodeList, CPU or Node count\n");
#else
syslog(LOG_NOTICE, "Allocate_Nodes: Job failed to specify NodeList, CPU or Node count\n");
#endif
Error_Code = EINVAL;
goto cleanup;
} /* if */
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/* Find selected partition */
if (Req_Partition) {
Part_Ptr = list_find_first(Part_List, &List_Find_Part, Req_Partition);
if (Part_Ptr == NULL) {
#if DEBUG_SYSTEM
fprintf(stderr, "Allocate_Nodes: Invalid partition specified: %s\n", Req_Partition);
#else
syslog(LOG_NOTICE, "Allocate_Nodes: Invalid partition specified: %s\n", Req_Partition);
#endif
Error_Code = EINVAL;
goto cleanup;
} /* if */
} else {
if (Default_Part_Loc == NULL) {
#if DEBUG_SYSTEM
fprintf(stderr, "Allocate_Nodes: Default partition not set.\n");
#else
syslog(LOG_ERR, "Allocate_Nodes: Default partition not set.\n");
#endif
Error_Code = EINVAL;
goto cleanup;
} /* if */
Part_Ptr = Default_Part_Loc;
} /* if */
/* Can this user access this partition */
if (Part_Ptr->Key && (Is_Key_Valid(Key) == 0)) {
#if DEBUG_SYSTEM
fprintf(stderr, "Allocate_Nodes: Job lacks key required of partition %s\n",
Part_Ptr->Name);
#else
syslog(LOG_NOTICE, "Allocate_Nodes: Job lacks key required of partition %s\n",
Part_Ptr->Name);
#endif
Error_Code = EINVAL;
goto cleanup;
} /* if */
if (Match_Group(Part_Ptr->AllowGroups, Req_Group) == 0) {
#if DEBUG_SYSTEM
fprintf(stderr, "Allocate_Nodes: Job lacks group required of partition %s\n",
Part_Ptr->Name);
#else
syslog(LOG_NOTICE, "Allocate_Nodes: Job lacks group required of partition %s\n",
Part_Ptr->Name);
#endif
Error_Code = EINVAL;
goto cleanup;
} /* if */
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
/* Check if select partition has sufficient resources to satisfy request */
if ((Req_CPUs != NO_VAL) && (Req_CPUs > Part_Ptr->TotalCPUs)) {
#if DEBUG_SYSTEM
fprintf(stderr, "Allocate_Nodes: Too many CPUs (%d) requested of partition %s(%d)\n",
Req_CPUs, Part_Ptr->Name, Part_Ptr->TotalCPUs);
#else
syslog(LOG_NOTICE, "Allocate_Nodes: Too many CPUs (%d) requested of partition %s(%d)\n",
Req_CPUs, Part_Ptr->Name, Part_Ptr->TotalCPUs);
#endif
Error_Code = EINVAL;
goto cleanup;
} /* if */
if ((Req_Nodes != NO_VAL) && (Req_Nodes > Part_Ptr->TotalNodes)) {
#if DEBUG_SYSTEM
fprintf(stderr, "Allocate_Nodes: Too many nodes (%d) requested of partition %s(%d)\n",
Req_Nodes, Part_Ptr->Name, Part_Ptr->TotalNodes);
#else
syslog(LOG_NOTICE, "Allocate_Nodes: Too many nodes (%d) requested of partition %s(%d)\n",
Req_Nodes, Part_Ptr->Name, Part_Ptr->TotalNodes);
#endif
Error_Code = EINVAL;
goto cleanup;
} /* if */
if (Req_Node_List) { /* Insure that selected nodes are in this partition */
Error_Code = NodeName2BitMap(Req_Node_List, &Req_BitMap);
if (Error_Code == EINVAL) goto cleanup;
if (Error_Code != 0) {
Error_Code = EAGAIN; /* No memory */
goto cleanup;
} /* if */
if (Contiguous != NO_VAL) BitMapFill(Req_BitMap);
if (BitMapIsSuper(Req_BitMap, Part_Ptr->NodeBitMap) != 1) {
#if DEBUG_SYSTEM
fprintf(stderr, "Allocate_Nodes: Requested nodes %s not in partition %s\n",
Req_Node_List, Part_Ptr->Name);
#else
syslog(LOG_NOTICE, "Allocate_Nodes: Requested nodes %s not in partition %s\n",
Req_Node_List, Part_Ptr->Name);
#endif
Error_Code = EINVAL;
goto cleanup;
} /* if */
} else
Req_BitMap = (unsigned *)NULL;
/* Pick up nodes from the Weight ordered configuration list */
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
Node_Set_Index = 0;
Node_Set_Size = 10;
Node_Set_Ptr = (struct Node_Set *)malloc(sizeof(struct Node_Set *)*Node_Set_Size);
if (Node_Set_Ptr == 0) {
#if DEBUG_SYSTEM
fprintf(stderr, "Allocate_Nodes: Unable to allocate memory\n");
#else
syslog(LOG_ALERT, "Allocate_Nodes: Unable to allocate memory\n");
#endif
Error_Code = EAGAIN;
goto cleanup;
} /* if */
Config_Record_Iterator = list_iterator_create(Config_List);
if (Config_Record_Iterator == NULL) {
#if DEBUG_SYSTEM
fprintf(stderr, "Allocate_Nodes: list_iterator_create unable to allocate memory\n");
#else
syslog(LOG_ALERT, "Allocate_Nodes: list_iterator_create unable to allocate memory\n");
#endif
Error_Code = EAGAIN;
goto cleanup;
} /* if */
while (Config_Record_Point = (struct Config_Record *)list_next(Config_Record_Iterator)) {
if ((Min_CPUs != NO_VAL) && (Min_CPUs > Config_Record_Point->CPUs)) continue;
if ((Min_Memory != NO_VAL) && (Min_Memory > Config_Record_Point->RealMemory)) continue;
if ((Min_TmpDisk != NO_VAL) && (Min_TmpDisk > Config_Record_Point->TmpDisk)) continue;
if (ValidFeatures(Req_Features,Config_Record_Point->Feature) == 0) continue;
Node_Set_Ptr[Node_Set_Index].My_BitMap = BitMapCopy(Config_Record_Point->NodeBitMap);
if (Node_Set_Ptr[Node_Set_Index].My_BitMap == NULL) {
Error_Code = EAGAIN; /* No memory */
list_iterator_destroy(Config_Record_Iterator);
goto cleanup;
} /* if */
BitMapAND(Node_Set_Ptr[Node_Set_Index].My_BitMap, Part_Ptr->NodeBitMap);
Node_Set_Ptr[Node_Set_Index].Nodes = BitMapCount(Node_Set_Ptr[Node_Set_Index].My_BitMap);
if (Node_Set_Ptr[Node_Set_Index].Nodes == 0)
free(Node_Set_Ptr[Node_Set_Index].My_BitMap);
else {
if (Req_BitMap) {
if (Node_Set_Index == 0)
Scratch_BitMap = BitMapCopy(Node_Set_Ptr[Node_Set_Index].My_BitMap);
else
BitMapOR(Scratch_BitMap, Node_Set_Ptr[Node_Set_Index].My_BitMap);
} /* if */
Node_Set_Ptr[Node_Set_Index].CPUs_Per_Node = Config_Record_Point->CPUs;
#if DEBUG_MODULE
printf("Found %d usable nodes from %s\n",
Node_Set_Ptr[Node_Set_Index].Nodes, Config_Record_Point->Nodes);
#endif
Node_Set_Index++;
if (Node_Set_Index++ >= Node_Set_Size) {
Node_Set_Size += 10;
Node_Set_Ptr = (struct Node_Set *)realloc(Node_Set_Ptr,
sizeof(struct Node_Set *)*Node_Set_Size);
if (Node_Set_Ptr == 0) {
#if DEBUG_SYSTEM
fprintf(stderr, "Allocate_Nodes: Unable to allocate memory\n");
#else
syslog(LOG_ALERT, "Allocate_Nodes: Unable to allocate memory\n");
#endif
list_iterator_destroy(Config_Record_Iterator);
Error_Code = EAGAIN; /* No memory */
goto cleanup;
} /* if */
} /* if */
} /* else */
} /* while */
list_iterator_destroy(Config_Record_Iterator);
if (Node_Set_Index == 0) {
#if DEBUG_SYSTEM
fprintf(stderr, "Allocate_Nodes: No node configurations satisfy requirements %d:%d:%d:%s\n",
Min_CPUs, Min_Memory, Min_TmpDisk, Req_Features);
#else
syslog(LOG_NOTICE, "Allocate_Nodes: No node configurations satisfy requirements %d:%d:%d:%s\n",
Min_CPUs, Min_Memory, Min_TmpDisk, Req_Features);
#endif
Error_Code = EINVAL;
goto cleanup;
} /* if */
Node_Set_Size = Node_Set_Index - 1;
if (Req_BitMap) {
if (BitMapIsSuper(Req_BitMap, Scratch_BitMap) != 1) {
#if DEBUG_SYSTEM
fprintf(stderr, "Allocate_Nodes: Requested nodes do not satisfy configurations requirements %d:%d:%d:%s\n",
Min_CPUs, Min_Memory, Min_TmpDisk, Req_Features);
#else
syslog(LOG_NOTICE, "Allocate_Nodes: Requested nodes do not satisfy configurations requirements %d:%d:%d:%s\n",
Min_CPUs, Min_Memory, Min_TmpDisk, Req_Features);
#endif
Error_Code = EINVAL;
goto cleanup;
} /* if */
} /* if */
if (Scratch_BitMap) {
free(Scratch_BitMap);
Scratch_BitMap = NULL;
} /* if */
/* Insure nodes are up and available */
/* Pick the nodes providing a best-fit */
/* Mark the selected nodes as STATE_STAGING */
Error_Code = BitMap2NodeName(Req_BitMap, Node_List);
if (Error_Code) printf("BitMap2NodeName error %d\n", Error_Code);
cleanup:
if (Req_Features) free(Req_Features);
if (Req_Node_List) free(Req_Node_List);
if (Req_Group) free(Req_Group);
if (Req_Partition) free(Req_Partition);
if (Req_BitMap) free(Req_BitMap);
if (Scratch_BitMap) free(Scratch_BitMap);
if (Node_Set_Ptr) free(Node_Set_Ptr);
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
return Error_Code;
} /* Allocate_Nodes */
/*
* Is_Key_Valid - Determine if supplied key is valid
* Input: Key - A SLURM key acquired by user root
* Output: Returns 1 if key is valid, 0 otherwise
* NOTE: This is only a placeholder for a future function
*/
int Is_Key_Valid(int Key) {
if (Key == NO_VAL) return 0;
return 1;
} /* Is_Key_Valid */
/*
* Match_Group - Determine if the user is a member of any groups permitted to use this partition
* Input: AllowGroups - Comma delimited list of groups permitted to use the partition,
* NULL is for ALL groups
* UserGroups - Comma delimited list of groups the user belongs to
* Output: Returns 1 if user is member, 0 otherwise
*/
int Match_Group(char *AllowGroups, char *UserGroups) {
char *Tmp_Allow_Group, *str_ptr1, *str_ptr2;
char *Tmp_User_Group, *str_ptr3, *str_ptr4;
if (AllowGroups == NULL) return 1; /* Anybody can use it */
if (UserGroups == NULL) return 0; /* Empty group list */
Tmp_Allow_Group = malloc(strlen(AllowGroups)+1);
if (Tmp_Allow_Group == NULL) {
#if DEBUG_SYSTEM
fprintf(stderr, "Match_Group: unable to allocate memory\n");
#else
syslog(LOG_ALERT, "Match_Group: unable to allocate memory\n");
#endif
return 1; /* Assume good for now */
} /* if */
strcpy(Tmp_Allow_Group, AllowGroups);
Tmp_User_Group = malloc(strlen(UserGroups)+1);
if (Tmp_User_Group == NULL) {
#if DEBUG_SYSTEM
fprintf(stderr, "Match_Group: unable to allocate memory\n");
#else
syslog(LOG_ALERT, "Match_Group: unable to allocate memory\n");
#endif
free(Tmp_Allow_Group);
return 1; /* Assume good for now */
} /* if */
str_ptr1 = (char *)strtok_r(Tmp_Allow_Group, ",", &str_ptr2);
while (str_ptr1) {
strcpy(Tmp_User_Group, UserGroups);
str_ptr3 = (char *)strtok_r(Tmp_User_Group, ",", &str_ptr4);
while (str_ptr3) {
if (strcmp(str_ptr1, str_ptr3) == 0) { /* We have a match */
free(Tmp_Allow_Group);
free(Tmp_User_Group);
return 1;
} /* if */
str_ptr3 = (char *)strtok_r(NULL, ",", &str_ptr4);
} /* while (str_ptr3) */
str_ptr1 = (char *)strtok_r(NULL, ",", &str_ptr2);
free(Tmp_Allow_Group);
free(Tmp_User_Group);
return 0; /* No match */
} /* Match_Group */
/*
* Parse_Job_Specs - Pick the appropriate fields out of a job request specification
* Input: Job_Specs - String containing the specification
* Req_Features, etc. - Pointers to storage for the specifications
* Output: Req_Features, etc. - The job's specifications
* Returns 0 if no error, errno otherwise
* NOTE: The calling function must free memory at Req_Features[0], Req_Node_List[0],
Req_Group[0], and Req_Partition[0]
*/
int Parse_Job_Specs(char *Job_Specs, char **Req_Features, char **Req_Node_List, char **Job_Name,
char **Req_Group, char **Req_Partition, int *Contiguous, int *Req_CPUs,
int *Req_Nodes, int *Min_CPUs, int *Min_Memory, int *Min_TmpDisk, int *Key) {
int Bad_Index, Error_Code, i;
char *Temp_Specs;
Req_Features[0] = Req_Node_List[0] = Req_Group[0] = Req_Partition[0] = Job_Name[0] = NULL;
*Contiguous = *Req_CPUs = *Req_Nodes = *Min_CPUs = *Min_Memory = *Min_TmpDisk = NO_VAL;
Temp_Specs = malloc(strlen(Job_Specs)+1);
if (Temp_Specs == NULL) {
#if DEBUG_SYSTEM
fprintf(stderr, "Parse_Job_Specs: unable to allocate memory\n");
#else
syslog(LOG_ALERT, "Parse_Job_Specs: unable to allocate memory\n");
#endif
return ENOMEM;
} /* if */
strcpy(Temp_Specs, Job_Specs);
Error_Code = Load_String (Job_Name, "JobName=", Temp_Specs);
if (Error_Code) goto cleanup;
Error_Code = Load_String (Req_Features, "Features=", Temp_Specs);
if (Error_Code) goto cleanup;
Error_Code = Load_String (Req_Node_List, "NodeList=", Temp_Specs);
if (Error_Code) goto cleanup;
Error_Code = Load_String (Req_Group, "Groups=", Temp_Specs);
if (Error_Code) goto cleanup;
Error_Code = Load_String (Req_Partition, "Partition=", Temp_Specs);
if (Error_Code) goto cleanup;
Error_Code = Load_Integer (Contiguous, "Contiguous", Temp_Specs);
if (Error_Code) goto cleanup;
Error_Code = Load_Integer (Req_CPUs, "TotalCPUs=", Temp_Specs);
if (Error_Code) goto cleanup;
Error_Code = Load_Integer (Req_Nodes, "TotalNodes=", Temp_Specs);
if (Error_Code) goto cleanup;
Error_Code = Load_Integer (Min_CPUs, "MinCPUs=", Temp_Specs);
if (Error_Code) goto cleanup;
Error_Code = Load_Integer (Min_Memory, "MinMemory=", Temp_Specs);
if (Error_Code) goto cleanup;
Error_Code = Load_Integer (Min_TmpDisk, "MinTmpDisk=", Temp_Specs);
if (Error_Code) goto cleanup;
Error_Code = Load_Integer (Key, "Key=", Temp_Specs);
if (Error_Code) {
return Error_Code;
} /* if */
Bad_Index = -1;
for (i=0; i<strlen(Temp_Specs); i++) {
if (Temp_Specs[i] == '\n') Temp_Specs[i]=' ';
if (isspace((int)Temp_Specs[i])) continue;
Bad_Index=i;
break;
} /* if */
if (Bad_Index != -1) {
#if DEBUG_SYSTEM
fprintf(stderr, "Parse_Job_Specs: Bad job specification input: %s\n",
&Temp_Specs[Bad_Index]);
syslog(LOG_ERR, "Parse_Job_Specs: Bad job specification input: %s\n",
&Temp_Specs[Bad_Index]);
#endif
Error_Code = EINVAL;
} /* if */
free(Temp_Specs);
return Error_Code;
cleanup:
free(Temp_Specs);
if (Job_Name[0]) free(Job_Name[0]);
if (Req_Features[0]) free(Req_Features[0]);
if (Req_Node_List[0]) free(Req_Node_List[0]);
if (Req_Group[0]) free(Req_Group[0]);
if (Req_Partition[0]) free(Req_Partition[0]);
} /* Parse_Job_Specs */
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
/* ValidFeatures - Determine if the Requested features are satisfied by those Available
* Input: Requested - Requested features (by a job)
* Available - Available features (on a node)
* Output: Returns 0 if request is not satisfied, 1 otherwise
* NOTE: This is only checking comma separated features (Interpretted as AND),
* this should be expanded to support AND, OR, and parentheses "(&|)"
*/
int ValidFeatures(char *Requested, char *Available) {
char *Tmp_Requested, *str_ptr1, *str_ptr2;
char *Tmp_Available, *str_ptr3, *str_ptr4;
int found;
if (Requested == NULL) return 1; /* No constraints */
if (Available == NULL) return 0; /* No features */
Tmp_Requested = malloc(strlen(Requested)+1);
if (Tmp_Requested == NULL) {
#if DEBUG_SYSTEM
fprintf(stderr, "ValidFeatures: unable to allocate memory\n");
#else
syslog(LOG_ALERT, "ValidFeatures: unable to allocate memory\n");
#endif
return 1; /* Assume good for now */
} /* if */
strcpy(Tmp_Requested, Requested);
Tmp_Available = malloc(strlen(Available)+1);
if (Tmp_Available == NULL) {
#if DEBUG_SYSTEM
fprintf(stderr, "ValidFeatures: unable to allocate memory\n");
#else
syslog(LOG_ALERT, "ValidFeatures: unable to allocate memory\n");
#endif
free(Tmp_Requested);
return 1; /* Assume good for now */
} /* if */
found = 1;
str_ptr1 = (char *)strtok_r(Tmp_Requested, ",", &str_ptr2);
while (str_ptr1) {
found = 0;
strcpy(Tmp_Available, Available);
str_ptr3 = (char *)strtok_r(Tmp_Available, ",", &str_ptr4);
while (str_ptr3) {
if (strcmp(str_ptr1, str_ptr3) == 0) { /* We have a match */
found = 1;
break;
} /* if */
str_ptr3 = (char *)strtok_r(NULL, ",", &str_ptr4);
} /* while (str_ptr3) */
if (found == 0) break;
str_ptr1 = (char *)strtok_r(NULL, ",", &str_ptr2);
} /* while (str_ptr1) */
free(Tmp_Requested);
free(Tmp_Available);
return found; /* No match */
} /* ValidFeatures */