1 #include <sys/types.h> 2 #include <sys/stat.h> 3 #include <fcntl.h> 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include <string.h> 7 #include <errno.h> 8 #include <locale.h> 9 #include <stddef.h> 10 #include <limits.h> 11 #include <pwd.h> 12 #include <grp.h> 13 #include <unistd.h> 14 #include <rctl.h> 15 #include <regex.h> 16 #include <ctype.h> 17 18 #include "projent.h" 19 #include "attrib.h" 20 #include "util.h" 21 22 23 #define BOSTR_REG_EXP "^" 24 #define EOSTR_REG_EXP "$" 25 #define IDENT_REG_EXP "[[:alpha:]][[:alnum:]_.-]*" 26 #define PRJID_REG_EXP "[[:digit:]]+" 27 #define USERN_REG_EXP "!?[[:alpha:]][[:alnum:]_.-]*" 28 #define GRUPN_REG_EXP "!?[[:alnum:]][[:alnum:]]*" 29 30 #define TO_EXP(X) BOSTR_REG_EXP X EOSTR_REG_EXP 31 32 #define PROJN_EXP TO_EXP(IDENT_REG_EXP) 33 #define PRJID_EXP TO_EXP(PRJID_REG_EXP) 34 #define USERN_EXP TO_EXP(USERN_REG_EXP) 35 #define GRUPN_EXP TO_EXP(GRUPN_REG_EXP) 36 37 /*ARGSUSED*/ 38 int 39 projent_validate_name(char *pname, lst_t *errlst) 40 { 41 /* Do nothing, as any parse-able project name is valid */ 42 return (0); 43 } 44 45 /*ARGSUSED*/ 46 int 47 projent_validate_comment(char *comment, lst_t *errlst) 48 { 49 /* Do nothing, as any parse-able project name is valid */ 50 return (0); 51 } 52 53 int 54 projent_validate_users(char *users, lst_t *errlst) 55 { 56 char *susrs, *usrs, *usr; 57 char *u, **ulast, **ulist; 58 int ret = 0; 59 int i; 60 61 susrs = usrs = util_safe_strdup(users); 62 ulast = ulist = util_safe_zmalloc( 63 (strlen(users) + 1) * sizeof (char *)); 64 while ((usr = strsep(&usrs, ",")) != NULL) { 65 if (*usr == '!') 66 usr++; 67 if ((*usr == '\0') || (strcmp(usr, "*") == 0)) 68 continue; 69 70 if (getpwnam(usr) == NULL) { 71 util_add_errmsg(errlst, gettext( 72 "User \"%s\" does not exist"), usr); 73 ret = 1; 74 } 75 for (i = 0; (u = ulist[i]) != NULL; i++) { 76 if (strcmp(u, usr) == 0) { 77 util_add_errmsg(errlst, gettext( 78 "Duplicate user names \"%s\""), usr); 79 ret = 1; 80 } 81 } 82 /* Add the user to the temporary list if not found */ 83 if (u == NULL) { 84 *ulast++ = usr; 85 } 86 } 87 free(ulist); 88 free(susrs); 89 return (ret); 90 } 91 92 int 93 projent_validate_groups(char *groups, lst_t *errlst) 94 { 95 char *sgrps, *grps, *grp; 96 char *g, **glast, **glist; 97 int ret = 0; 98 int i; 99 100 sgrps = grps = util_safe_strdup(groups); 101 glast = glist = util_safe_zmalloc( 102 (strlen(groups) + 1) * sizeof (char *)); 103 while ((grp = strsep(&grps, ",")) != NULL) { 104 if (*grp == '!') 105 grp++; 106 if ((*grp == '\0') || (strcmp(grp, "*") == 0)) 107 continue; 108 109 if (getgrnam(grp) == NULL) { 110 util_add_errmsg(errlst, gettext( 111 "Group \"%s\" does not exist"), grp); 112 ret = 1; 113 } 114 for (i = 0; (g = glist[i]) != NULL; i++) { 115 if (strcmp(g, grp) == 0) { 116 util_add_errmsg(errlst, gettext( 117 "Duplicate group names \"%s\""), grp); 118 ret = 1; 119 } 120 } 121 /* Add the group to the temporary list if not found */ 122 if (g == NULL) { 123 *glast++ = grp; 124 } 125 } 126 free(glist); 127 free(sgrps); 128 return (ret); 129 } 130 131 int 132 projent_validate_attributes(lst_t *attrs, lst_t *errlst) 133 { 134 return (attrib_validate_lst(attrs, errlst)); 135 } 136 137 char * 138 projent_tostring(projent_t *ent) 139 { 140 char *attrs; 141 char *ret = NULL; 142 if ((attrs = attrib_lst_tostring(ent->attrs)) != NULL) { 143 (void) asprintf(&ret, "%s:%ld:%s:%s:%s:%s", 144 ent->projname, 145 ent->projid, 146 ent->comment, 147 ent->userlist, 148 ent->grouplist, 149 attrs); 150 free(attrs); 151 } 152 return (ret); 153 } 154 155 int 156 projent_validate(projent_t *pent, int flags, lst_t *errlst) 157 { 158 char *str; 159 160 (void) projent_validate_name(pent->projname, errlst); 161 (void) projent_validate_projid(pent->projid, flags, errlst); 162 (void) projent_validate_comment(pent->comment, errlst); 163 (void) projent_validate_users(pent->userlist, errlst); 164 (void) projent_validate_groups(pent->grouplist, errlst); 165 (void) projent_validate_attributes(pent->attrs, errlst); 166 167 if ((str = projent_tostring(pent)) == NULL) { 168 util_add_errmsg(errlst, gettext("error allocating memory")); 169 } else { 170 if (strlen(str) > (PROJECT_BUFSZ - 2)) { 171 util_add_errmsg(errlst, gettext( 172 "projent line too long")); 173 } 174 free(str); 175 } 176 return (lst_is_empty(errlst) == 0); 177 } 178 179 int 180 projent_validate_lst(lst_t *plst, int flags, lst_t *errlst) 181 { 182 int e, i, idx; 183 projent_t *ent; 184 char *pnames = NULL; 185 projid_t *pids = NULL; 186 int ret = 0; 187 188 idx = 0; 189 for (e = 0; e < lst_size(plst); e++) { 190 ent = lst_at(plst, e); 191 /* Check for duplicate projname */ 192 if (pnames != NULL && strstr(pnames, ent->projname) != NULL) { 193 util_add_errmsg(errlst, gettext( 194 "Duplicate project name %s"), ent->projname); 195 ret++; 196 } 197 198 /* Check for duplicate projid if DUP is not allowed */ 199 if (!(flags & F_PAR_DUP) && pids != NULL) { 200 for (i = 0; i < idx; i++) { 201 if (ent->projid == pids[i]) { 202 util_add_errmsg(errlst, gettext( 203 "Duplicate proid %d"), ent->projid); 204 ret++; 205 break; 206 } 207 } 208 } 209 210 /* Add the projname an projid to out temp list */ 211 pnames = UTIL_STR_APPEND2(pnames, "|", ent->projname); 212 pids = util_safe_realloc(pids, (idx + 1) * sizeof (projid_t)); 213 pids[idx] = ent->projid; 214 idx++; 215 216 /* Validate the projet */ 217 ret += projent_validate(ent, flags, errlst); 218 } 219 220 free(pnames); 221 free(pids); 222 223 return (ret); 224 } 225 226 void 227 projent_free_attributes(lst_t *attribs) 228 { 229 attrib_free_lst(attribs); 230 } 231 232 void 233 projent_sort_attributes(lst_t *attribs) 234 { 235 attrib_sort_lst(attribs); 236 } 237 238 char * 239 projent_attrib_tostring(void *attrib) 240 { 241 return (attrib_tostring(attrib)); 242 } 243 244 char * 245 projent_attrib_lst_tostring(lst_t *lst) 246 { 247 return (attrib_lst_tostring(lst)); 248 } 249 250 void 251 projent_merge_attributes(lst_t **eattrs, lst_t *nattrs, int flags, 252 lst_t *errlst) 253 { 254 attrib_merge_attrib_lst(eattrs, nattrs, flags, errlst); 255 } 256 257 lst_t * 258 projent_parse_attributes(char *attribs, int flags, lst_t *errlst) 259 { 260 return (attrib_parse_attributes(attribs, flags, errlst)); 261 } 262 263 void 264 projent_merge_usrgrp(char *usrgrp, char **elist, char *nlist, 265 int flags, lst_t *errlst) 266 { 267 char *res = NULL; 268 char *seusrs, *eusrs, *eusr; 269 char *snusrs, *nusrs, *nusr; 270 char *sn1usrs, *n1usrs, *n1usr; 271 char *sep; 272 int i, j; 273 274 sep = (flags & F_PAR_SPC) ? " ," : ","; 275 276 if (flags & F_MOD_ADD) { 277 res = util_safe_strdup(*elist); 278 279 snusrs = nusrs = util_safe_strdup(nlist); 280 while ((nusr = strsep(&nusrs, sep)) != NULL) { 281 if (*nusr == '\0') 282 continue; 283 seusrs = eusrs = util_safe_strdup(*elist); 284 while ((eusr = strsep(&eusrs, sep)) != NULL) { 285 if (*eusr == '\0') 286 continue; 287 if (strcmp(eusr, nusr) == 0) { 288 util_add_errmsg(errlst, gettext( 289 "Project already contains" 290 " %s \"%s\""), usrgrp, nusr); 291 UTIL_FREE_SNULL(res); 292 free(seusrs); 293 free(snusrs); 294 goto out; 295 } 296 } 297 free(seusrs); 298 /* Append nusr to the result */ 299 if (*res != '\0') 300 res = UTIL_STR_APPEND1(res, ","); 301 res = UTIL_STR_APPEND1(res, nusr); 302 } 303 free(snusrs); 304 } else if (flags & F_MOD_REM) { 305 306 snusrs = nusrs = util_safe_strdup(nlist); 307 for (i = 0; (nusr = strsep(&nusrs, sep)) != NULL; i++) { 308 if (*nusr == '\0') 309 continue; 310 sn1usrs = n1usrs = util_safe_strdup(nlist); 311 for (j = 0; (n1usr = strsep(&n1usrs, sep)) != NULL; 312 j++) { 313 if (i != j && strcmp(nusr, n1usr) == 0) { 314 util_add_errmsg(errlst, gettext( 315 "Duplicate %s name \"%s\""), 316 usrgrp, nusr); 317 free(sn1usrs); 318 free(snusrs); 319 goto out; 320 } 321 } 322 free(sn1usrs); 323 324 seusrs = eusrs = util_safe_strdup(*elist); 325 while ((eusr = strsep(&eusrs, sep)) != NULL) { 326 if (strcmp(nusr, eusr) == 0) { 327 break; 328 } 329 } 330 free(seusrs); 331 332 if (eusr == NULL) { 333 util_add_errmsg(errlst, gettext( 334 "Project does not contain %s name \"%s\""), 335 usrgrp, nusr); 336 free(snusrs); 337 goto out; 338 } 339 } 340 free(snusrs); 341 342 343 res = util_safe_zmalloc(1); 344 seusrs = eusrs = util_safe_strdup(*elist); 345 while ((eusr = strsep(&eusrs, sep)) != NULL) { 346 if (*eusr == '\0') 347 continue; 348 snusrs = nusrs = util_safe_strdup(nlist); 349 while ((nusr = strsep(&nusrs, sep)) != NULL) { 350 if (strcmp(eusr, nusr) == 0) { 351 break; 352 } 353 } 354 free(snusrs); 355 356 if (nusr == NULL) { 357 if (*res != '\0') 358 res = UTIL_STR_APPEND1(res, ","); 359 res = UTIL_STR_APPEND1(res, eusr); 360 } 361 } 362 free(seusrs); 363 } else if (flags & F_MOD_SUB || flags & F_MOD_REP) { 364 res = util_safe_strdup(nlist); 365 } 366 367 out: 368 if (res != NULL) { 369 free(*elist); 370 *elist = res; 371 } 372 } 373 374 char * 375 projent_parse_users(char *nlist, int flags, lst_t *errlst) 376 { 377 char *ulist = NULL; 378 char *susrs, *usrs, *usr; 379 regex_t usernexp; 380 char *sep; 381 382 if (regcomp(&usernexp, USERN_EXP, REG_EXTENDED) != 0) { 383 util_add_errmsg(errlst, gettext( 384 "Failed to compile regular expression: \"%s\""), 385 USERN_EXP); 386 goto out; 387 } 388 389 sep = (flags & F_PAR_SPC) ? " ," : ","; 390 susrs = usrs = util_safe_strdup(nlist); 391 ulist = util_safe_zmalloc(1); 392 393 while ((usr = strsep(&usrs, sep)) != NULL) { 394 if (*usr == '\0') 395 continue; 396 397 if (regexec(&usernexp, usr, 0, NULL, 0) != 0 && 398 strcmp(usr, "*") != 0 && 399 strcmp(usr, "!*") != 0) { 400 util_add_errmsg(errlst, gettext( 401 "Invalid user name \"%s\""), usr); 402 UTIL_FREE_SNULL(ulist); 403 break; 404 } 405 /* Append ',' first if required */ 406 if (*ulist != '\0') 407 ulist = UTIL_STR_APPEND1(ulist, ","); 408 ulist = UTIL_STR_APPEND1(ulist, usr); 409 } 410 411 free(susrs); 412 regfree(&usernexp); 413 out: 414 return (ulist); 415 } 416 417 418 char * 419 projent_parse_groups(char *nlist, int flags, lst_t *errlst) 420 { 421 char *glist = NULL; 422 char *sgrps, *grps, *grp; 423 regex_t groupnexp; 424 char *sep; 425 426 if (regcomp(&groupnexp, GRUPN_EXP, REG_EXTENDED) != 0) { 427 util_add_errmsg(errlst, gettext( 428 "Failed to compile regular expression: \"%s\""), 429 GRUPN_EXP); 430 goto out; 431 } 432 433 sep = (flags & F_PAR_SPC) ? " ," : ","; 434 sgrps = grps = util_safe_strdup(nlist); 435 glist = util_safe_zmalloc(1); 436 437 while ((grp = strsep(&grps, sep)) != NULL) { 438 if (*grp == '\0') 439 continue; 440 441 if (regexec(&groupnexp, grp, 0, NULL, 0) != 0 && 442 strcmp(grp, "*") != 0 && 443 strcmp(grp, "!*") != 0) { 444 util_add_errmsg(errlst, gettext( 445 "Invalid group name \"%s\""), grp); 446 UTIL_FREE_SNULL(glist); 447 break; 448 } 449 /* Append ',' first if required */ 450 if (*glist != '\0') 451 glist = UTIL_STR_APPEND1(glist, ","); 452 glist = UTIL_STR_APPEND1(glist, grp); 453 } 454 455 free(sgrps); 456 regfree(&groupnexp); 457 out: 458 return (glist); 459 } 460 461 int 462 projent_parse_comment(char *comment, lst_t *errlst) 463 { 464 int ret = 0; 465 if (strchr(comment, ':') != NULL) { 466 util_add_errmsg(errlst, gettext( 467 "Invalid Comment \"%s\": should not contain ':'"), 468 comment); 469 ret = 1; 470 } 471 return (ret); 472 } 473 474 int 475 projent_validate_unique_id(lst_t *plst, projid_t projid, lst_t *errlst) 476 { 477 int e; 478 projent_t *ent; 479 for (e = 0; e < lst_size(plst); e++) { 480 ent = lst_at(plst, e); 481 if (ent->projid == projid) { 482 util_add_errmsg(errlst, gettext( 483 "Duplicate projid \"%d\""), projid); 484 return (1); 485 } 486 } 487 return (0); 488 } 489 int 490 projent_validate_projid(projid_t projid, int flags, lst_t *errlst) 491 { 492 projid_t maxprojid; 493 494 maxprojid = (flags & F_PAR_RES) ? 0 : 100; 495 496 if (projid < maxprojid) { 497 util_add_errmsg(errlst, gettext( 498 "Invalid projid \"%d\": " 499 "must be >= 100"), 500 projid); 501 return (1); 502 } 503 return (0); 504 } 505 506 int 507 projent_parse_projid(char *projidstr, projid_t *pprojid, lst_t *errlst) 508 { 509 char *ptr; 510 long long llid; 511 regex_t prjidexp; 512 int ret = 0; 513 514 if (regcomp(&prjidexp, PRJID_EXP, REG_EXTENDED) != 0) { 515 util_add_errmsg(errlst, gettext( 516 "Failed to compile regular expression: \"%s\""), PRJID_EXP); 517 return (1); 518 } 519 520 521 if (regexec(&prjidexp, projidstr, 0, NULL, 0) != 0) { 522 util_add_errmsg(errlst, gettext("Invalid project id: \"%s\""), 523 projidstr); 524 ret = 1; 525 goto out; 526 } 527 528 llid = strtoll(projidstr, &ptr, 10); 529 530 /* projid should be a positive number */ 531 if (llid == 0 && errno == ERANGE && *ptr != '\0') { 532 util_add_errmsg(errlst, gettext("Invalid project id: \"%s\""), 533 projidstr); 534 ret = 1; 535 goto out; 536 } 537 538 /* projid should be a positive number >= 0 */ 539 if (llid < 0) { 540 util_add_errmsg(errlst, gettext( 541 "Invalid projid \"%lld\": must be >= 0"), llid); 542 ret = 1; 543 goto out; 544 } 545 546 /* projid should be less than UID_MAX */ 547 if (llid > INT_MAX) { 548 util_add_errmsg(errlst, gettext( 549 "Invalid projid \"%lld\": must be <= %d"), 550 llid, INT_MAX); 551 ret = 1; 552 goto out; 553 } 554 555 if (pprojid != NULL) 556 *pprojid = llid; 557 out: 558 regfree(&prjidexp); 559 return (ret); 560 } 561 562 int 563 projent_validate_unique_name(lst_t *plst, char *pname, lst_t *errlst) 564 { 565 int e; 566 projent_t *ent; 567 for (e = 0; e < lst_size(plst); e++) { 568 ent = lst_at(plst, e); 569 if (strcmp(ent->projname, pname) == 0) { 570 util_add_errmsg(errlst, gettext( 571 "Duplicate project name \"%s\""), pname); 572 return (1); 573 } 574 } 575 return (0); 576 } 577 578 int 579 projent_parse_name(char *pname, lst_t *errlst) 580 { 581 int ret = 1; 582 regex_t projnexp; 583 if (regcomp(&projnexp, PROJN_EXP, REG_EXTENDED) != 0) { 584 util_add_errmsg(errlst, gettext( 585 "Failed to compile regular expression: \"%s\""), 586 PROJN_EXP); 587 goto out; 588 } 589 590 if (regexec(&projnexp, pname, 0, NULL, 0) != 0) { 591 util_add_errmsg(errlst, gettext( 592 "Invalid project name \"%s\", " 593 "contains invalid characters"), pname); 594 } else if (strlen(pname) > PROJNAME_MAX) { 595 util_add_errmsg(errlst, gettext( 596 "Invalid project name \"%s\", " 597 "name too long"), pname); 598 } else { 599 ret = 0; 600 } 601 602 regfree(&projnexp); 603 out: 604 return (ret); 605 } 606 607 void 608 projent_free(projent_t *ent) 609 { 610 free(ent->projname); 611 free(ent->comment); 612 free(ent->userlist); 613 free(ent->grouplist); 614 attrib_free_lst(ent->attrs); 615 free(ent->attrs); 616 } 617 618 projent_t * 619 projent_parse_components(char *projname, char *idstr, char *comment, 620 char *users, char *groups, char *attr, int flags, lst_t *errlst) 621 { 622 projent_t *ent; 623 int reterr = 0; 624 625 ent = util_safe_zmalloc(sizeof (projent_t)); 626 627 628 ent->projname = util_safe_strdup(projname); 629 ent->comment = util_safe_strdup(comment); 630 631 reterr += projent_parse_name(ent->projname, errlst); 632 reterr += projent_parse_projid(idstr, &ent->projid, errlst); 633 reterr += projent_parse_comment(ent->comment, errlst); 634 ent->userlist = projent_parse_users(users, flags, errlst); 635 ent->grouplist = projent_parse_groups(groups, flags, errlst); 636 ent->attrs = projent_parse_attributes(attr, flags, errlst); 637 638 if (reterr > 0 || ent->userlist == NULL || 639 ent->grouplist == NULL || ent->attrs == NULL) { 640 projent_free(ent); 641 UTIL_FREE_SNULL(ent); 642 } 643 644 return (ent); 645 } 646 projent_t * 647 projent_parse(char *projstr, int flags, lst_t *errlst) 648 { 649 char *str, *sstr; 650 char *projname, *idstr, *comment, *users, *groups, *attrstr; 651 projent_t *ent; 652 653 if (projstr == NULL) 654 return (NULL); 655 656 projname = idstr = comment = users = groups = attrstr = NULL; 657 ent = NULL; 658 659 sstr = str = util_safe_strdup(projstr); 660 661 if ((projname = util_safe_strdup(strsep(&str, ":"))) == NULL || 662 (idstr = util_safe_strdup(strsep(&str, ":"))) == NULL || 663 (comment = util_safe_strdup(strsep(&str, ":"))) == NULL || 664 (users = util_safe_strdup(strsep(&str, ":"))) == NULL || 665 (groups = util_safe_strdup(strsep(&str, ":"))) == NULL || 666 (attrstr = util_safe_strdup(strsep(&str, ":"))) == NULL || 667 strsep(&str, ":") != NULL) { 668 util_add_errmsg(errlst, gettext( 669 "Incorrect number of fields. Should have 5 \":\"'s.")); 670 goto out; 671 } 672 673 ent = projent_parse_components(projname, idstr, comment, users, groups, 674 attrstr, flags, errlst); 675 out: 676 free(sstr); 677 free(projname); free(idstr); free(comment); 678 free(users); free(groups); free(attrstr); 679 return (ent); 680 } 681 682 683 void 684 projent_free_lst(lst_t *plst) 685 { 686 projent_t *ent; 687 688 if (plst == NULL) 689 return; 690 691 while (!lst_is_empty(plst)) { 692 ent = lst_at(plst, 0); 693 (void) lst_remove(plst, ent); 694 projent_free(ent); 695 free(ent); 696 } 697 } 698 699 700 void 701 projent_put_lst(char *projfile, lst_t *plst, lst_t *errlst) 702 { 703 char *tmpprojfile, *attrs; 704 FILE *fp; 705 projent_t *ent; 706 struct stat statbuf; 707 int e, ret; 708 709 tmpprojfile = NULL; 710 if (asprintf(&tmpprojfile, "%s.%ld_tmp", projfile, getpid()) == -1) { 711 util_add_errmsg(errlst, gettext( 712 "Failed to allocate memory")); 713 goto out; 714 } 715 716 if (stat(projfile, &statbuf) != 0) { 717 util_add_errmsg(errlst, gettext( 718 "Failed to access %s: %s"), 719 projfile, strerror(errno)); 720 goto out; 721 } 722 if ((fp = fopen(tmpprojfile, "wx")) == NULL) { 723 util_add_errmsg(errlst, gettext( 724 "Cannot create %s: %s"), 725 tmpprojfile, strerror(errno)); 726 goto out; 727 } 728 729 for (e = 0; e < lst_size(plst); e++) { 730 ent = lst_at(plst, e); 731 attrs = attrib_lst_tostring(ent->attrs); 732 ret = fprintf(fp, "%s:%ld:%s:%s:%s:%s\n", ent->projname, 733 ent->projid, ent->comment, ent->userlist, ent->grouplist, 734 attrs); 735 free(attrs); 736 if (ret < 0) { 737 util_add_errmsg(errlst, gettext( 738 "Failed to write to %s: %s"), 739 tmpprojfile, strerror(errno)); 740 /* Remove the temporary file and exit */ 741 (void) unlink(tmpprojfile); 742 goto out1; 743 } 744 } 745 746 if (chown(tmpprojfile, statbuf.st_uid, statbuf.st_gid) != 0) { 747 util_add_errmsg(errlst, gettext( 748 "Cannot set ownership of %s: %s"), 749 tmpprojfile, strerror(errno)); 750 (void) unlink(tmpprojfile); 751 goto out1; 752 } 753 754 if (rename(tmpprojfile, projfile) != 0) { 755 util_add_errmsg(errlst, gettext( 756 "Cannot rename %s to %s : %s"), 757 tmpprojfile, projfile, strerror(errno)); 758 (void) unlink(tmpprojfile); 759 goto out1; 760 } 761 762 out1: 763 (void) fclose(fp); 764 out: 765 free(tmpprojfile); 766 } 767 768 lst_t * 769 projent_get_lst(char *projfile, int flags, lst_t *errlst) 770 { 771 FILE *fp; 772 lst_t *plst; 773 int line = 0; 774 char *buf = NULL, *nlp; 775 size_t cap = 0; 776 projent_t *ent; 777 778 plst = util_safe_malloc(sizeof (lst_t)); 779 lst_create(plst); 780 781 if ((fp = fopen(projfile, "r")) == NULL) { 782 if (errno == ENOENT) { 783 /* 784 * There is no project file, 785 * return an empty lst 786 */ 787 return (plst); 788 } else { 789 /* Report the error unable to open the file */ 790 util_add_errmsg(errlst, gettext( 791 "Cannot open %s: %s"), 792 projfile, strerror(errno)); 793 794 free(plst); 795 return (NULL); 796 } 797 } 798 799 while ((getline(&buf, &cap, fp)) != -1 && ++line) { 800 801 if ((nlp = strchr(buf, '\n')) != NULL) 802 *nlp = '\0'; 803 804 if ((ent = projent_parse(buf, flags, errlst)) != NULL) { 805 lst_insert_tail(plst, ent); 806 } else { 807 /* Report the error */ 808 util_add_errmsg(errlst, gettext( 809 "Error parsing: %s line: %d: \"%s\""), 810 projfile, line, buf); 811 812 /* free the allocated resources */ 813 projent_free_lst(plst); 814 UTIL_FREE_SNULL(plst); 815 goto out; 816 } 817 } 818 819 if (flags & F_PAR_VLD && plst != NULL) { 820 if (projent_validate_lst(plst, flags, errlst) != 0) { 821 projent_free_lst(plst); 822 UTIL_FREE_SNULL(plst); 823 } 824 } 825 826 out: 827 (void) fclose(fp); 828 free(buf); 829 return (plst); 830 }