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 }