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 }