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