Merge commit 'b1e7e97d3b60469b243b3b2e22c7d8cbd11c7c90'
[unleashed.git] / usr / src / cmd / setfacl / setfacl.c
blobe3af3690718e03778fd72481c70b03ce98e3359d
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright (c) 1993, 2010, Oracle and/or its affiliates. All rights reserved.
26 * setfacl [-r] -f aclfile file ...
27 * setfacl [-r] -d acl_entries file ...
28 * setfacl [-r] -m acl_entries file ...
29 * setfacl [-r] -s acl_entries file ...
30 * This command deletes/adds/modifies/sets discretionary information for a file
31 * or files.
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <pwd.h>
37 #include <grp.h>
38 #include <string.h>
39 #include <locale.h>
40 #include <sys/acl.h>
41 #include <sys/types.h>
42 #include <unistd.h>
43 #include <errno.h>
45 #define ADD 1
46 #define MODIFY 2
47 #define DELETE 3
48 #define SET 4
50 static int get_acl_info(char *filep, aclent_t **aclpp);
51 static int mod_entries(aclent_t *, int, char *, char *, char *, int);
52 static int set_file_entries(char *, char *, int);
53 static int set_online_entries(char *, char *, int);
54 static void usage();
55 static int parse_entry_list(aclent_t **, int *, char *, int);
56 static int convert_to_aclent_t(char *, int *, aclent_t **, int);
57 static int parse_entry(char *, aclent_t *, int);
58 static void err_handle(int, aclent_t *);
59 static int conv_id(char *);
61 int
62 main(int argc, char *argv[])
64 int c;
65 int dflag = 0;
66 int mflag = 0;
67 int rflag = 0;
68 int sflag = 0;
69 int fflag = 0;
70 int errflag = 0;
71 int aclcnt; /* used by -m -d */
72 aclent_t *aclp; /* used by -m -d */
73 char *aclfilep; /* acl file argument */
74 char *d_entryp = NULL; /* ptr to del entry list */
75 char *m_entryp = NULL; /* ptr to mod entry list */
76 char *s_entryp = NULL; /* ptr to set entry list */
77 char *work_dp = NULL; /* working ptrs for the above */
78 char *work_mp = NULL;
79 char *work_sp = NULL;
81 (void) setlocale(LC_ALL, "");
82 (void) textdomain(TEXT_DOMAIN);
84 if (argc < 3)
85 usage();
87 while ((c = getopt(argc, argv, "rm:d:s:f:")) != EOF) {
88 switch (c) {
89 case 'r':
90 rflag++;
91 break;
92 case 'd':
93 if (dflag || fflag || sflag)
94 usage();
95 dflag++;
96 d_entryp = optarg;
97 break;
98 case 'm':
99 if (mflag || fflag || sflag)
100 usage();
101 mflag++;
102 m_entryp = optarg;
103 break;
104 case 's':
105 if (fflag || sflag || mflag || dflag)
106 usage();
107 sflag++;
108 s_entryp = optarg;
109 break;
110 case 'f':
111 if (fflag || sflag || mflag || dflag)
112 usage();
113 fflag++;
114 aclfilep = optarg;
115 break;
116 case '?':
117 errflag++;
118 break;
121 if (errflag)
122 usage();
124 /* one of these flags should be set */
125 if (!fflag && !sflag && !mflag && !dflag)
126 usage();
128 /* no file arguments */
129 if (optind >= argc)
130 usage();
132 for (; optind < argc; optind++) {
133 register char *filep;
135 filep = argv[optind];
137 /* modify and delete: we need to get the ACL first */
138 if (mflag || dflag) {
139 if (m_entryp != NULL) {
140 free(work_mp);
141 work_mp = strdup(m_entryp);
142 if (work_mp == NULL) {
143 fprintf(stderr,
144 gettext("out of memory %s\n"),
145 m_entryp);
146 exit(1);
150 if (d_entryp != NULL) {
151 free(work_dp);
152 work_dp = strdup(d_entryp);
153 if (work_dp == NULL) {
154 fprintf(stderr,
155 gettext("out of memory %s\n"),
156 d_entryp);
157 exit(1);
161 aclcnt = get_acl_info(filep, &aclp);
162 if (aclcnt == -1)
163 exit(2);
164 if (mod_entries(aclp, aclcnt, work_mp,
165 work_dp, filep, rflag) == -1)
166 exit(2);
167 } else if (fflag) {
168 if (set_file_entries(aclfilep, filep, rflag) == -1)
169 exit(2);
170 } else if (sflag) {
171 if (s_entryp != NULL) {
172 free(work_sp);
173 work_sp = strdup(s_entryp);
174 if (work_sp == NULL) {
175 fprintf(stderr,
176 gettext("out of memory %s\n"),
177 s_entryp);
178 exit(1);
181 if (set_online_entries(work_sp, filep, rflag) == -1)
182 exit(2);
185 return (0);
189 * For add, modify, and delete, we need to get the ACL of the file first.
191 static int
192 get_acl_info(char *filep, aclent_t **aclpp)
194 int aclcnt;
196 if ((aclcnt = acl(filep, GETACLCNT, 0, NULL)) < 0) {
197 if (errno == ENOSYS) {
198 (void) fprintf(stderr,
199 gettext("File system doesn't support aclent_t "
200 "style ACL's.\n"
201 "See acl(5) for more information on"
202 " ACL styles support by Solaris.\n"));
203 return (-1);
205 (void) fprintf(stderr,
206 gettext("%s: failed to get acl count\n"), filep);
207 perror("get acl count error");
208 return (-1);
210 if (aclcnt < MIN_ACL_ENTRIES) {
211 (void) fprintf(stderr,
212 gettext("%d: acl count is too small from %s\n"),
213 aclcnt, filep);
214 return (-1);
217 if ((*aclpp = (aclent_t *)malloc(sizeof (aclent_t) * aclcnt)) == NULL) {
218 (void) fprintf(stderr, gettext("out of memory\n"));
219 return (-1);
221 if (acl(filep, GETACL, aclcnt, *aclpp) < 0) {
222 (void) fprintf(stderr,
223 gettext("%s: failed to get acl entries\n"), filep);
224 perror("getacl error");
225 return (-1);
227 return (aclcnt);
231 * mod_entries() handles add, delete, and modify ACL entries of a file.
232 * The real action is in convert_to_aclent_t() called by parse_entry_list().
233 * aclp: points ACL of a file and may be changed by lower level routine.
234 * modp: modify entry list in ascii format
235 * delp: delete entry list in ascii format
236 * fnamep: file of interest
238 static int
239 mod_entries(aclent_t *aclp, int cnt, char *modp, char *delp,
240 char *fnamep, int rfg)
242 int rc; /* return code */
244 /* modify and add: from -m option */
245 if (parse_entry_list(&aclp, &cnt, modp, MODIFY) == -1)
246 return (-1);
248 /* deletion: from -d option */
249 if (parse_entry_list(&aclp, &cnt, delp, DELETE) == -1)
250 return (-1);
252 if (aclsort(cnt, rfg, aclp) == -1) {
253 (void) err_handle(cnt, aclp);
254 (void) fprintf(stderr,
255 gettext("aclcnt %d, file %s\n"), cnt, fnamep);
256 return (-1);
259 if (acl(fnamep, SETACL, cnt, aclp) < 0) {
260 fprintf(stderr,
261 gettext("%s: failed to set acl entries\n"), fnamep);
262 perror("setacl error");
263 return (-1);
265 return (0);
269 * set_file_entries() creates ACL entries from ACL file (acl_fnamep).
270 * It opens the file and converts every line (one line per acl entry)
271 * into aclent_t format. It then recalculates the mask according to rflag.
272 * Finally it sets ACL to the file (fnamep).
274 static int
275 set_file_entries(char *acl_fnamep, char *fnamep, int rflag)
277 int aclcnt = 0;
278 FILE *acl_fp;
279 aclent_t *aclp;
280 char buf[BUFSIZ];
281 char *tp;
283 if (strcmp(acl_fnamep, "-") == 0)
284 acl_fp = stdin;
285 else {
286 if ((acl_fp = fopen(acl_fnamep, "r")) == NULL) {
287 fprintf(stderr, gettext("Can't open acl file %s\n"),
288 acl_fnamep);
289 return (-1);
292 while (fgets(buf, BUFSIZ, acl_fp) != NULL) {
293 if (buf[0] == '#' || buf[0] == '\n')
294 continue;
296 /* check effective permission: add a null after real perm */
297 if ((tp = (char *)strchr(buf, '#')) != NULL) {
298 tp--;
299 while (*tp == ' ' || *tp == '\t') {
300 if (tp != buf)
301 tp--;
302 else {
303 fprintf(stderr,
304 gettext("entry format error %s\n"),
305 buf);
306 exit(1);
309 *(tp+1) = '\0';
312 /* remove <nl> at the end if there is one */
313 if ((tp = (char *)strchr(buf, '\n')) != NULL)
314 *tp = '\0';
315 aclcnt++;
316 if (convert_to_aclent_t(buf, &aclcnt, &aclp, SET) == -1)
317 return (-1);
320 if (aclsort(aclcnt, rflag, aclp) == -1) {
321 (void) err_handle(aclcnt, aclp);
322 (void) fprintf(stderr, gettext("aclcnt %d, aclfile %s\n"),
323 aclcnt, acl_fnamep);
324 return (-1);
327 if (acl(fnamep, SETACL, aclcnt, aclp) < 0) {
328 fprintf(stderr,
329 gettext("%s: failed to set acl entries\n"), fnamep);
330 perror("setacl error");
331 return (-1);
333 return (0);
337 * set_online_entries() parses the acl entries from command line (setp).
338 * It converts the comma separated acl entries into aclent_t format.
339 * It then recalculates the mask according to rflag.
340 * Finally it sets ACL to the file (fnamep).
342 static int
343 set_online_entries(char *setp, char *fnamep, int rflag)
345 char *commap;
346 aclent_t *aclp;
347 int aclcnt = 0;
349 if (parse_entry_list(&aclp, &aclcnt, setp, SET) == -1)
350 return (-1);
352 if (aclsort(aclcnt, rflag, aclp) == -1) {
353 (void) err_handle(aclcnt, aclp);
354 (void) fprintf(stderr,
355 gettext("aclcnt %d, file %s\n"), aclcnt, fnamep);
356 return (-1);
359 if (acl(fnamep, SETACL, aclcnt, aclp) < 0) {
360 fprintf(stderr,
361 gettext("%s: failed to set acl entries\n"), fnamep);
362 perror("setacl error");
363 return (-1);
365 return (0);
369 * parse_entry_list() parses entry list (listp) separated by commas.
370 * Once it gets an ACL entry, it calls convert_to_aclent_t() to convert
371 * to internal format.
373 static int
374 parse_entry_list(aclent_t **aclpp, int *aclcntp, char *listp, int mode)
376 char *commap;
378 if (listp == NULL)
379 return (0);
380 while ((commap = (char *)strchr(listp, ',')) != NULL) {
381 *commap = '\0';
382 *aclcntp += 1;
383 /* aclcnt may be updated after the call: add or modify */
384 if (convert_to_aclent_t(listp, aclcntp, aclpp, mode) == -1)
385 return (-1);
386 listp = ++commap;
388 /* this is for only one entry or last entry */
389 if (*listp != '\0') {
390 *aclcntp += 1;
391 if (convert_to_aclent_t(listp, aclcntp, aclpp, mode) == -1)
392 return (-1);
394 return (0);
398 * convert_to_aclent_t() converts an acl entry in ascii format (fields separated
399 * by colon) into aclent_t and appends it to the current ACL. It also handles
400 * memory allocation/deallocation for acl entries in aclent_t format.
401 * aclpp that contains acl entries in acl format will be returned.
402 * We don't check duplicates.
404 static int
405 convert_to_aclent_t(char *entryp, int *cntp, aclent_t **aclpp, int mode)
407 aclent_t *new_aclp;
408 aclent_t tmpacl;
409 aclent_t *taclp, *centry = NULL, *gentry = NULL;
410 int cur_cnt;
411 int found = 0;
412 int is_obj;
414 if (entryp == NULL)
415 return (0);
417 if (*cntp > 1)
418 new_aclp = reallocarray(*aclpp, *cntp, sizeof (aclent_t));
419 else
420 new_aclp = (aclent_t *) malloc(sizeof (aclent_t) * (*cntp));
421 if (new_aclp == NULL) {
422 fprintf(stderr,
423 gettext("Insufficient memory for acl %d\n"), *cntp);
424 return (-1);
427 tmpacl.a_id = 0; /* id field needs to be initialized */
428 if (entryp[0] == 'u')
429 tmpacl.a_id = getuid(); /* id field for user */
430 if (entryp[0] == 'g')
431 tmpacl.a_id = getgid(); /* id field for group */
433 tmpacl.a_type = 0;
434 if (parse_entry(entryp, &tmpacl, mode) == -1)
435 return (-1);
437 is_obj = ((tmpacl.a_type == USER_OBJ) ||
438 (tmpacl.a_type == GROUP_OBJ) ||
439 (tmpacl.a_type == CLASS_OBJ) ||
440 (tmpacl.a_type == DEF_USER_OBJ) ||
441 (tmpacl.a_type == DEF_GROUP_OBJ) ||
442 (tmpacl.a_type == DEF_OTHER_OBJ));
444 cur_cnt = *cntp - 1;
445 switch (mode) {
446 case MODIFY: /* and add */
447 for (taclp = new_aclp; cur_cnt-- > 0; taclp++) {
448 if (taclp->a_type == tmpacl.a_type &&
449 ((taclp->a_id == tmpacl.a_id) || is_obj)) {
450 found++;
451 /* cnt is added before it's called */
452 *cntp -= 1;
453 taclp->a_perm = tmpacl.a_perm;
454 break;
457 if (!found) /* Add it to the end: no need to change cntp */
458 memcpy(new_aclp + *cntp -1, &tmpacl, sizeof (aclent_t));
459 break;
461 case DELETE:
462 for (taclp = new_aclp; cur_cnt-- > 0; taclp++) {
463 if (taclp->a_type == tmpacl.a_type &&
464 ((taclp->a_id == tmpacl.a_id) || is_obj)) {
465 found++;
466 /* move up the rest */
467 while (cur_cnt-- > 0) {
468 memcpy(taclp, taclp+1,
469 sizeof (aclent_t));
470 taclp++;
472 *cntp = *cntp - 2;
473 break;
476 if (!found)
477 *cntp -= 1;
478 break;
480 case SET:
481 /* we may check duplicate before copying over?? */
482 memcpy(new_aclp + *cntp -1, &tmpacl, sizeof (aclent_t));
483 break;
485 default:
486 fprintf(stderr,
487 gettext("Unrecognized mode: internal error\n"));
488 break;
492 * If converting from non-trivial acl entry to trivial one,
493 * reset CLASS_OBJ's permission with that of GROUP_OBJ.
496 if (mode == DELETE) {
497 boolean_t trivial = B_TRUE; /* assumption */
498 cur_cnt = *cntp;
499 for (taclp = new_aclp; cur_cnt-- > 0; taclp++) {
500 switch (taclp->a_type) {
501 case USER_OBJ:
502 case OTHER_OBJ:
503 break;
504 case CLASS_OBJ:
505 centry = taclp;
506 break;
507 case GROUP_OBJ:
508 gentry = taclp;
509 break;
510 default:
512 * Confirmed that the new acl set is
513 * still a non-trivial acl.
514 * Skip reset.
516 trivial = B_FALSE;
519 if (centry != NULL && gentry != NULL && trivial == B_TRUE)
520 centry->a_perm = gentry->a_perm;
522 *aclpp = new_aclp; /* return new acl entries */
523 return (0);
526 static void
527 usage()
529 (void) fprintf(stderr, gettext("usage:\n"));
530 (void) fprintf(stderr,
531 gettext("\tsetfacl [-r] -f aclfile file ...\n"));
532 (void) fprintf(stderr,
533 gettext("\tsetfacl [-r] -d acl_entries file ...\n"));
534 (void) fprintf(stderr,
535 gettext("\tsetfacl [-r] -m acl_entries file ...\n"));
536 (void) fprintf(stderr,
537 gettext("\tsetfacl [-r] -s acl_entries file ...\n"));
538 exit(1);
541 static void
542 err_handle(int cnt, aclent_t *aclentp)
544 int rc;
545 int which;
547 rc = aclcheck(aclentp, cnt, &which);
548 switch (rc) {
549 case USER_ERROR:
550 fprintf(stderr,
551 gettext("There is more than one user owner entry"));
552 fprintf(stderr,
553 gettext(" -- error found at entry index %d\n"), which);
554 break;
555 case GRP_ERROR:
556 fprintf(stderr,
557 gettext("There is more than one group owner entry"));
558 fprintf(stderr,
559 gettext(" -- error found at entry index %d\n"), which);
560 break;
561 case CLASS_ERROR:
562 fprintf(stderr,
563 gettext("There is more than one mask entry"));
564 fprintf(stderr,
565 gettext(" -- error found at entry index %d\n"), which);
566 break;
567 case OTHER_ERROR:
568 fprintf(stderr,
569 gettext("There is more than one other entry"));
570 fprintf(stderr,
571 gettext(" -- error found at entry index %d\n"), which);
572 break;
573 case DUPLICATE_ERROR:
574 fprintf(stderr,
575 gettext("Duplicate user or group entries"));
576 fprintf(stderr,
577 gettext(" -- error found at entry index %d\n"), which);
578 break;
579 case MISS_ERROR:
580 fprintf(stderr,
581 gettext("Missing user/group owner, other, mask entry\n"));
582 break;
583 case MEM_ERROR:
584 fprintf(stderr,
585 gettext("Insufficient memory\n"));
586 break;
587 case ENTRY_ERROR:
588 fprintf(stderr,
589 gettext("Unrecognized entry type"));
590 fprintf(stderr,
591 gettext(" -- error found at entry index %d\n"), which);
592 break;
593 default:
594 /* error is not from aclcheck */
595 fprintf(stderr,
596 gettext("aclsort error\n"));
597 break;
601 static int
602 parse_entry(char *fieldp, aclent_t *aclentp, int mode)
604 char *colonp;
605 int def_flag = 0, mo_flag = 0;
606 int id;
607 struct passwd *pwp;
608 struct group *grp;
610 colonp = (char *)strchr(fieldp, ':');
611 if (colonp == NULL) {
612 fprintf(stderr,
613 gettext("Can't find colon delimiter %s\n"), fieldp);
614 return (-1);
616 *colonp = '\0';
617 if ((strcmp(fieldp, "default") == 0) || (strcmp(fieldp, "d") == 0)) {
618 def_flag++;
619 fieldp = ++colonp;
620 colonp = (char *)strchr(fieldp, ':');
621 if (colonp == NULL) {
622 fprintf(stderr,
623 gettext("Can't find colon delimiter %s\n"), fieldp);
624 return (-1);
626 *colonp = '\0';
629 /* process entry type */
630 if ((strcmp(fieldp, "user") == 0) || (strcmp(fieldp, "u") == 0)) {
631 if (def_flag)
632 aclentp->a_type = DEF_USER;
633 else
634 aclentp->a_type = USER;
636 if ((strcmp(fieldp, "group") == 0) || (strcmp(fieldp, "g") == 0)) {
637 if (def_flag)
638 aclentp->a_type = DEF_GROUP;
639 else
640 aclentp->a_type = GROUP;
642 if ((strcmp(fieldp, "mask") == 0) || (strcmp(fieldp, "m") == 0)) {
643 if (def_flag)
644 aclentp->a_type = DEF_CLASS_OBJ;
645 else
646 aclentp->a_type = CLASS_OBJ;
648 if ((strcmp(fieldp, "other") == 0) || (strcmp(fieldp, "o") == 0)) {
649 if (def_flag)
650 aclentp->a_type = DEF_OTHER_OBJ;
651 else
652 aclentp->a_type = OTHER_OBJ;
655 /* still can't determine entry type */
656 if (aclentp->a_type == 0) {
657 fprintf(stderr,
658 gettext("Unrecognized entry type %s \n"), fieldp);
659 return (-1);
662 /* mask and other entries dont have id field */
663 if (aclentp->a_type != CLASS_OBJ && aclentp->a_type != OTHER_OBJ &&
664 aclentp->a_type != DEF_CLASS_OBJ &&
665 aclentp->a_type != DEF_OTHER_OBJ) {
666 /* process id: */
667 fieldp = ++colonp;
668 colonp = (char *)strchr(fieldp, ':');
669 if (colonp == NULL) {
670 if (mode != DELETE) {
671 fprintf(stderr,
672 gettext("Can't find colon delimiter %s\n"),
673 fieldp);
674 return (-1);
676 } else
677 *colonp = '\0';
679 if (*fieldp == '\0') {
680 /* empty uid */
681 if (aclentp->a_type == USER)
682 aclentp->a_type = USER_OBJ;
683 if (aclentp->a_type == DEF_USER)
684 aclentp->a_type = DEF_USER_OBJ;
685 if (aclentp->a_type == GROUP)
686 aclentp->a_type = GROUP_OBJ;
687 if (aclentp->a_type == DEF_GROUP)
688 aclentp->a_type = DEF_GROUP_OBJ;
689 } else {
690 /* see if it's a user/group name */
691 if (aclentp->a_type == USER ||
692 aclentp->a_type == USER_OBJ ||
693 aclentp->a_type == DEF_USER ||
694 aclentp->a_type == DEF_USER_OBJ) {
695 if ((pwp = getpwnam(fieldp)) != NULL)
696 aclentp->a_id = pwp->pw_uid;
697 else {
698 /* treat it as numeric id */
699 id = conv_id(fieldp);
700 if (id == -1)
701 return (-1);
702 aclentp->a_id = id;
704 } else {
705 /* group name */
706 if ((grp = getgrnam(fieldp)) != NULL)
707 aclentp->a_id = grp->gr_gid;
708 else {
709 id = conv_id(fieldp);
710 if (id == -1)
711 return (-1);
712 aclentp->a_id = id;
716 } else {
717 /* it is mask/other entry */
718 mo_flag = 1;
721 /* process permission: rwx and [0]n format */
722 if (mode == DELETE)
723 /* delete format: no permission field */
724 return (0);
725 fieldp = ++colonp;
726 colonp = (char *)strchr(fieldp, ':');
727 if (colonp != NULL) {
728 if (mo_flag == 1) {
729 /* Use only single : on mask/other entry */
730 (void) fprintf(stderr, gettext("use only 1 colon for "
731 "mask and other entries.\n"));
732 return (-1);
733 } else {
734 /* it's ok to have extra colon */
735 *colonp = '\0';
739 if ((int)strlen(fieldp) > 3) {
740 fprintf(stderr,
741 gettext("only rwx or [0]n format is allowed\n"));
742 return (-1);
744 if (strlen(fieldp) == 3) {
745 aclentp->a_perm = 0;
746 /* treat it as rwx */
747 if (*fieldp == 'r')
748 aclentp->a_perm += 4;
749 else
750 if (*fieldp != '-') {
751 fprintf(stderr,
752 gettext("Unrecognized character "));
753 fprintf(stderr,
754 gettext("found in mode field\n"));
755 return (-1);
757 fieldp++;
758 if (*fieldp == 'w')
759 aclentp->a_perm += 2;
760 else
761 if (*fieldp != '-') {
762 fprintf(stderr,
763 gettext("Unrecognized character "));
764 fprintf(stderr,
765 gettext("found in mode field\n"));
766 return (-1);
768 fieldp++;
769 if (*fieldp == 'x')
770 aclentp->a_perm += 1;
771 else
772 if (*fieldp != '-') {
773 fprintf(stderr,
774 gettext("Unrecognized character "));
775 fprintf(stderr,
776 gettext("found in mode field\n"));
777 return (-1);
779 return (0);
782 if (*fieldp == '\0')
783 return (0);
785 if (*fieldp >= '0' && *fieldp <= '7')
786 aclentp->a_perm = *fieldp - '0';
787 else {
788 fprintf(stderr, gettext("Unrecognized character "));
789 fprintf(stderr, gettext("found in mode field\n"));
790 return (-1);
792 if (aclentp->a_perm == 0 && *++fieldp != '\0') {
793 /* look at next char */
794 if (*fieldp >= '0' && *fieldp <= '7')
795 aclentp->a_perm = *fieldp - '0';
796 else {
797 fprintf(stderr, gettext("Unrecognized character "));
798 fprintf(stderr, gettext("found in mode field\n"));
799 fprintf(stderr,
800 gettext("Check also the number of fields "));
801 fprintf(stderr,
802 gettext("(default) mask and other entries\n"));
803 return (-1);
806 /* check for junk at the end ??? */
807 return (0);
811 * This function is different from atoi() in that it checks for
812 * valid digit in the id field whereas atoi() won't report any
813 * error.
815 static int
816 conv_id(char *fieldp)
818 int a_id = 0;
820 for (; *fieldp != '\0'; fieldp++) {
821 if (!isdigit(*fieldp)) {
822 fprintf(stderr, gettext("non-digit in id field\n"));
823 return (-1);
825 a_id = a_id * 10 + (*fieldp - '0');
827 return (a_id);