1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #ifndef lint 30 static char sccsid[] = "@(#)setfacl.c 1.10 05/06/16 SMI"; 31 #endif 32 33 /* 34 * setfacl [-r] -f aclfile file ... 35 * setfacl [-r] -d acl_entries file ... 36 * setfacl [-r] -m acl_entries file ... 37 * setfacl [-r] -s acl_entries file ... 38 * This command deletes/adds/modifies/sets discretionary information for a file 39 * or files. 40 */ 41 42 #include <stdlib.h> 43 #include <stdio.h> 44 #include <pwd.h> 45 #include <grp.h> 46 #include <string.h> 47 #include <locale.h> 48 #include <sys/acl.h> 49 #include <sys/types.h> 50 #include <unistd.h> 51 52 53 #define ADD 1 54 #define MODIFY 2 55 #define DELETE 3 56 #define SET 4 57 58 static int get_acl_info(char *filep, aclent_t **aclpp); 59 static int mod_entries(aclent_t *, int, char *, char *, char *, int); 60 static int set_file_entries(char *, char *, int); 61 static int set_online_entries(char *, char *, int); 62 static void usage(); 63 static int parse_entry_list(aclent_t **, int *, char *, int); 64 static int convert_to_aclent_t(char *, int *, aclent_t **, int); 65 static int parse_entry(char *, aclent_t *, int); 66 static void err_handle(int, aclent_t *); 67 static int conv_id(char *); 68 69 int 70 main(int argc, char *argv[]) 71 { 72 int c; 73 int dflag = 0; 74 int mflag = 0; 75 int rflag = 0; 76 int sflag = 0; 77 int fflag = 0; 78 int errflag = 0; 79 int aclcnt; /* used by -m -d */ 80 aclent_t *aclp; /* used by -m -d */ 81 char *aclfilep; /* acl file argument */ 82 char *d_entryp = NULL; /* ptr to del entry list */ 83 char *m_entryp = NULL; /* ptr to mod entry list */ 84 char *s_entryp = NULL; /* ptr to set entry list */ 85 char *work_dp = NULL; /* working ptrs for the above */ 86 char *work_mp = NULL; 87 char *work_sp = NULL; 88 89 (void) setlocale(LC_ALL, ""); 90 (void) textdomain(TEXT_DOMAIN); 91 92 if (argc < 3) 93 usage(); 94 95 while ((c = getopt(argc, argv, "rm:d:s:f:")) != EOF) { 96 switch (c) { 97 case 'r': 98 rflag++; 99 break; 100 case 'd': 101 if (dflag || fflag || sflag) 102 usage(); 103 dflag++; 104 d_entryp = optarg; 105 break; 106 case 'm': 107 if (mflag || fflag || sflag) 108 usage(); 109 mflag++; 110 m_entryp = optarg; 111 break; 112 case 's': 113 if (fflag || sflag || mflag || dflag) 114 usage(); 115 sflag++; 116 s_entryp = optarg; 117 break; 118 case 'f': 119 if (fflag || sflag || mflag || dflag) 120 usage(); 121 fflag++; 122 aclfilep = optarg; 123 break; 124 case '?': 125 errflag++; 126 break; 127 } 128 } 129 if (errflag) 130 usage(); 131 132 /* one of these flags should be set */ 133 if (!fflag && !sflag && !mflag && !dflag) 134 usage(); 135 136 /* no file arguments */ 137 if (optind >= argc) 138 usage(); 139 140 for (; optind < argc; optind++) { 141 register char *filep; 142 143 filep = argv[optind]; 144 145 /* modify and delete: we need to get the ACL first */ 146 if (mflag || dflag) { 147 if (m_entryp != NULL) { 148 free(work_mp); 149 work_mp = strdup(m_entryp); 150 if (work_mp == NULL) { 151 fprintf(stderr, 152 gettext("out of memory %s\n"), 153 m_entryp); 154 exit(1); 155 } 156 } 157 158 if (d_entryp != NULL) { 159 free(work_dp); 160 work_dp = strdup(d_entryp); 161 if (work_dp == NULL) { 162 fprintf(stderr, 163 gettext("out of memory %s\n"), 164 d_entryp); 165 exit(1); 166 } 167 } 168 169 aclcnt = get_acl_info(filep, &aclp); 170 if (aclcnt == -1) 171 exit(2); 172 if (mod_entries(aclp, aclcnt, work_mp, 173 work_dp, filep, rflag) == -1) 174 exit(2); 175 } else if (fflag) { 176 if (set_file_entries(aclfilep, filep, rflag) == -1) 177 exit(2); 178 } else if (sflag) { 179 if (s_entryp != NULL) { 180 free(work_sp); 181 work_sp = strdup(s_entryp); 182 if (work_sp == NULL) { 183 fprintf(stderr, 184 gettext("out of memory %s\n"), 185 s_entryp); 186 exit(1); 187 } 188 } 189 if (set_online_entries(work_sp, filep, rflag) == -1) 190 exit(2); 191 } 192 } 193 return (0); 194 } 195 196 /* 197 * For add, modify, and delete, we need to get the ACL of the file first. 198 */ 199 static int 200 get_acl_info(char *filep, aclent_t **aclpp) 201 { 202 int aclcnt; 203 204 if ((aclcnt = acl(filep, GETACLCNT, 0, NULL)) < 0) { 205 (void) fprintf(stderr, 206 gettext("%s: failed to get acl count\n"), filep); 207 perror("get acl count error"); 208 return (-1); 209 } 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); 215 } 216 217 if ((*aclpp = (aclent_t *)malloc(sizeof (aclent_t) * aclcnt)) == NULL) { 218 (void) fprintf(stderr, gettext("out of memory\n")); 219 return (-1); 220 } 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); 226 } 227 return (aclcnt); 228 } 229 230 /* 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 237 */ 238 static int 239 mod_entries(aclent_t *aclp, int cnt, char *modp, char *delp, 240 char *fnamep, int rfg) 241 { 242 int rc; /* return code */ 243 244 /* modify and add: from -m option */ 245 if (parse_entry_list(&aclp, &cnt, modp, MODIFY) == -1) 246 return (-1); 247 248 /* deletion: from -d option */ 249 if (parse_entry_list(&aclp, &cnt, delp, DELETE) == -1) 250 return (-1); 251 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); 257 } 258 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); 264 } 265 return (0); 266 } 267 268 /* 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). 273 */ 274 static int 275 set_file_entries(char *acl_fnamep, char *fnamep, int rflag) 276 { 277 int aclcnt = 0; 278 FILE *acl_fp; 279 aclent_t *aclp; 280 char buf[BUFSIZ]; 281 char *tp; 282 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); 290 } 291 } 292 while (fgets(buf, BUFSIZ, acl_fp) != NULL) { 293 if (buf[0] == '#' || buf[0] == '\n') 294 continue; 295 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); 307 } 308 } 309 *(tp+1) = '\0'; 310 } 311 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); 318 } 319 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); 325 } 326 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); 332 } 333 return (0); 334 } 335 336 /* 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). 341 */ 342 static int 343 set_online_entries(char *setp, char *fnamep, int rflag) 344 { 345 char *commap; 346 aclent_t *aclp; 347 int aclcnt = 0; 348 349 if (parse_entry_list(&aclp, &aclcnt, setp, SET) == -1) 350 return (-1); 351 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); 357 } 358 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); 364 } 365 return (0); 366 } 367 368 /* 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. 372 */ 373 static int 374 parse_entry_list(aclent_t **aclpp, int *aclcntp, char *listp, int mode) 375 { 376 char *commap; 377 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; 387 } 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); 393 } 394 return (0); 395 } 396 397 /* 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. 403 */ 404 static int 405 convert_to_aclent_t(char *entryp, int *cntp, aclent_t **aclpp, int mode) 406 { 407 aclent_t *new_aclp; 408 aclent_t tmpacl; 409 aclent_t *taclp; 410 int cur_cnt; 411 int found = 0; 412 int is_obj; 413 414 if (entryp == NULL) 415 return (0); 416 417 if (*cntp > 1) 418 new_aclp = (aclent_t *)realloc(*aclpp, 419 sizeof (aclent_t) * (*cntp)); 420 else 421 new_aclp = (aclent_t *) malloc(sizeof (aclent_t) * (*cntp)); 422 if (new_aclp == NULL) { 423 fprintf(stderr, 424 gettext("Insufficient memory for acl %d\n"), *cntp); 425 return (-1); 426 } 427 428 tmpacl.a_id = 0; /* id field needs to be initialized */ 429 if (entryp[0] == 'u') 430 tmpacl.a_id = getuid(); /* id field for user */ 431 if (entryp[0] == 'g') 432 tmpacl.a_id = getgid(); /* id field for group */ 433 434 tmpacl.a_type = 0; 435 if (parse_entry(entryp, &tmpacl, mode) == -1) 436 return (-1); 437 438 is_obj = ((tmpacl.a_type == USER_OBJ) || 439 (tmpacl.a_type == GROUP_OBJ) || 440 (tmpacl.a_type == DEF_USER_OBJ) || 441 (tmpacl.a_type == DEF_GROUP_OBJ)); 442 443 cur_cnt = *cntp - 1; 444 switch (mode) { 445 case MODIFY: /* and add */ 446 for (taclp = new_aclp; cur_cnt-- > 0; taclp++) { 447 if (taclp->a_type == tmpacl.a_type && 448 ((taclp->a_id == tmpacl.a_id) || is_obj)) { 449 found++; 450 /* cnt is added before it's called */ 451 *cntp -= 1; 452 taclp->a_perm = tmpacl.a_perm; 453 break; 454 } 455 } 456 if (!found) /* Add it to the end: no need to change cntp */ 457 memcpy(new_aclp + *cntp -1, &tmpacl, sizeof (aclent_t)); 458 break; 459 460 case DELETE: 461 for (taclp = new_aclp; cur_cnt-- > 0; taclp++) { 462 if (taclp->a_type == tmpacl.a_type && 463 ((taclp->a_id == tmpacl.a_id) || is_obj)) { 464 found++; 465 /* move up the rest */ 466 while (cur_cnt-- > 0) { 467 memcpy(taclp, taclp+1, 468 sizeof (aclent_t)); 469 taclp++; 470 } 471 *cntp = *cntp - 2; 472 break; 473 } 474 } 475 if (!found) 476 *cntp -= 1; 477 break; 478 479 case SET: 480 /* we may check duplicate before copying over?? */ 481 memcpy(new_aclp + *cntp -1, &tmpacl, sizeof (aclent_t)); 482 break; 483 484 default: 485 fprintf(stderr, 486 gettext("Unrecognized mode: internal error\n")); 487 break; 488 } 489 490 *aclpp = new_aclp; /* return new acl entries */ 491 return (0); 492 } 493 494 static void 495 usage() 496 { 497 (void) fprintf(stderr, gettext("usage:\n")); 498 (void) fprintf(stderr, 499 gettext("\tsetfacl [-r] -f aclfile file ...\n")); 500 (void) fprintf(stderr, 501 gettext("\tsetfacl [-r] -d acl_entries file ...\n")); 502 (void) fprintf(stderr, 503 gettext("\tsetfacl [-r] -m acl_entries file ...\n")); 504 (void) fprintf(stderr, 505 gettext("\tsetfacl [-r] -s acl_entries file ...\n")); 506 exit(1); 507 } 508 509 static void 510 err_handle(int cnt, aclent_t *aclentp) 511 { 512 int rc; 513 int which; 514 515 rc = aclcheck(aclentp, cnt, &which); 516 switch (rc) { 517 case USER_ERROR: 518 fprintf(stderr, 519 gettext("There is more than one user owner entry")); 520 fprintf(stderr, 521 gettext(" -- error found at entry index %d\n"), which); 522 break; 523 case GRP_ERROR: 524 fprintf(stderr, 525 gettext("There is more than one group owner entry")); 526 fprintf(stderr, 527 gettext(" -- error found at entry index %d\n"), which); 528 break; 529 case CLASS_ERROR: 530 fprintf(stderr, 531 gettext("There is more than one mask entry")); 532 fprintf(stderr, 533 gettext(" -- error found at entry index %d\n"), which); 534 break; 535 case OTHER_ERROR: 536 fprintf(stderr, 537 gettext("There is more than one other entry")); 538 fprintf(stderr, 539 gettext(" -- error found at entry index %d\n"), which); 540 break; 541 case DUPLICATE_ERROR: 542 fprintf(stderr, 543 gettext("Duplicate user or group entries")); 544 fprintf(stderr, 545 gettext(" -- error found at entry index %d\n"), which); 546 break; 547 case MISS_ERROR: 548 fprintf(stderr, 549 gettext("Missing user/group owner, other, mask entry\n")); 550 break; 551 case MEM_ERROR: 552 fprintf(stderr, 553 gettext("Insufficient memory\n")); 554 break; 555 case ENTRY_ERROR: 556 fprintf(stderr, 557 gettext("Unrecognized entry type")); 558 fprintf(stderr, 559 gettext(" -- error found at entry index %d\n"), which); 560 break; 561 default: 562 /* error is not from aclcheck */ 563 fprintf(stderr, 564 gettext("aclsort error\n")); 565 break; 566 } 567 } 568 569 static int 570 parse_entry(char *fieldp, aclent_t *aclentp, int mode) 571 { 572 char *colonp; 573 int def_flag = 0, mo_flag = 0; 574 int id; 575 struct passwd *pwp; 576 struct group *grp; 577 578 colonp = (char *)strchr(fieldp, ':'); 579 if (colonp == NULL) { 580 fprintf(stderr, 581 gettext("Can't find colon delimiter %s\n"), fieldp); 582 return (-1); 583 } 584 *colonp = '\0'; 585 if ((strcmp(fieldp, "default") == 0) || (strcmp(fieldp, "d") == 0)) { 586 def_flag++; 587 fieldp = ++colonp; 588 colonp = (char *)strchr(fieldp, ':'); 589 if (colonp == NULL) { 590 fprintf(stderr, 591 gettext("Can't find colon delimiter %s\n"), fieldp); 592 return (-1); 593 } 594 *colonp = '\0'; 595 } 596 597 /* process entry type */ 598 if ((strcmp(fieldp, "user") == 0) || (strcmp(fieldp, "u") == 0)) { 599 if (def_flag) 600 aclentp->a_type = DEF_USER; 601 else 602 aclentp->a_type = USER; 603 } 604 if ((strcmp(fieldp, "group") == 0) || (strcmp(fieldp, "g") == 0)) { 605 if (def_flag) 606 aclentp->a_type = DEF_GROUP; 607 else 608 aclentp->a_type = GROUP; 609 } 610 if ((strcmp(fieldp, "mask") == 0) || (strcmp(fieldp, "m") == 0)) { 611 if (def_flag) 612 aclentp->a_type = DEF_CLASS_OBJ; 613 else 614 aclentp->a_type = CLASS_OBJ; 615 } 616 if ((strcmp(fieldp, "other") == 0) || (strcmp(fieldp, "o") == 0)) { 617 if (def_flag) 618 aclentp->a_type = DEF_OTHER_OBJ; 619 else 620 aclentp->a_type = OTHER_OBJ; 621 } 622 623 /* still can't determine entry type */ 624 if (aclentp->a_type == 0) { 625 fprintf(stderr, 626 gettext("Unrecognized entry type %s \n"), fieldp); 627 return (-1); 628 } 629 630 /* mask and other entries dont have id field */ 631 if (aclentp->a_type != CLASS_OBJ && aclentp->a_type != OTHER_OBJ && 632 aclentp->a_type != DEF_CLASS_OBJ && 633 aclentp->a_type != DEF_OTHER_OBJ) { 634 /* process id: */ 635 fieldp = ++colonp; 636 colonp = (char *)strchr(fieldp, ':'); 637 if (colonp == NULL) { 638 if (mode != DELETE) { 639 fprintf(stderr, 640 gettext("Can't find colon delimiter %s\n"), 641 fieldp); 642 return (-1); 643 } 644 } else 645 *colonp = '\0'; 646 647 if (*fieldp == '\0') { 648 /* empty uid */ 649 if (aclentp->a_type == USER) 650 aclentp->a_type = USER_OBJ; 651 if (aclentp->a_type == DEF_USER) 652 aclentp->a_type = DEF_USER_OBJ; 653 if (aclentp->a_type == GROUP) 654 aclentp->a_type = GROUP_OBJ; 655 if (aclentp->a_type == DEF_GROUP) 656 aclentp->a_type = DEF_GROUP_OBJ; 657 } else { 658 /* see if it's a user/group name */ 659 if (aclentp->a_type == USER || 660 aclentp->a_type == USER_OBJ || 661 aclentp->a_type == DEF_USER || 662 aclentp->a_type == DEF_USER_OBJ) { 663 if ((pwp = getpwnam(fieldp)) != NULL) 664 aclentp->a_id = pwp->pw_uid; 665 else { 666 /* treat it as numeric id */ 667 id = conv_id(fieldp); 668 if (id == -1) 669 return (-1); 670 aclentp->a_id = id; 671 } 672 } else { 673 /* group name */ 674 if ((grp = getgrnam(fieldp)) != NULL) 675 aclentp->a_id = grp->gr_gid; 676 else { 677 id = conv_id(fieldp); 678 if (id == -1) 679 return (-1); 680 aclentp->a_id = id; 681 } 682 } 683 } 684 } else { 685 /* it is mask/other entry */ 686 mo_flag = 1; 687 } 688 689 /* process permission: rwx and [0]n format */ 690 if (mode == DELETE) 691 /* delete format: no permission field */ 692 return (0); 693 fieldp = ++colonp; 694 colonp = (char *)strchr(fieldp, ':'); 695 if (colonp != NULL) { 696 if (mo_flag == 1) { 697 /* Use only single : on mask/other entry */ 698 (void) fprintf(stderr, gettext("use only 1 colon for " 699 "mask and other entries.\n")); 700 return (-1); 701 } else { 702 /* it's ok to have extra colon */ 703 *colonp = '\0'; 704 } 705 } 706 707 if ((int)strlen(fieldp) > 3) { 708 fprintf(stderr, 709 gettext("only rwx or [0]n format is allowed\n")); 710 return (-1); 711 } 712 if (strlen(fieldp) == 3) { 713 aclentp->a_perm = 0; 714 /* treat it as rwx */ 715 if (*fieldp == 'r') 716 aclentp->a_perm += 4; 717 else 718 if (*fieldp != '-') { 719 fprintf(stderr, 720 gettext("Unrecognized character ")); 721 fprintf(stderr, 722 gettext("found in mode field\n")); 723 return (-1); 724 } 725 fieldp++; 726 if (*fieldp == 'w') 727 aclentp->a_perm += 2; 728 else 729 if (*fieldp != '-') { 730 fprintf(stderr, 731 gettext("Unrecognized character ")); 732 fprintf(stderr, 733 gettext("found in mode field\n")); 734 return (-1); 735 } 736 fieldp++; 737 if (*fieldp == 'x') 738 aclentp->a_perm += 1; 739 else 740 if (*fieldp != '-') { 741 fprintf(stderr, 742 gettext("Unrecognized character ")); 743 fprintf(stderr, 744 gettext("found in mode field\n")); 745 return (-1); 746 } 747 return (0); 748 } 749 750 if (*fieldp == '\0') 751 return (0); 752 753 if (*fieldp >= '0' && *fieldp <= '7') 754 aclentp->a_perm = *fieldp - '0'; 755 else { 756 fprintf(stderr, gettext("Unrecognized character ")); 757 fprintf(stderr, gettext("found in mode field\n")); 758 return (-1); 759 } 760 if (aclentp->a_perm == 0 && *++fieldp != '\0') { 761 /* look at next char */ 762 if (*fieldp >= '0' && *fieldp <= '7') 763 aclentp->a_perm = *fieldp - '0'; 764 else { 765 fprintf(stderr, gettext("Unrecognized character ")); 766 fprintf(stderr, gettext("found in mode field\n")); 767 fprintf(stderr, 768 gettext("Check also the number of fields ")); 769 fprintf(stderr, 770 gettext("(default) mask and other entries\n")); 771 return (-1); 772 } 773 } 774 /* check for junk at the end ??? */ 775 return (0); 776 } 777 778 /* 779 * This function is different from atoi() in that it checks for 780 * valid digit in the id field whereas atoi() won't report any 781 * error. 782 */ 783 static int 784 conv_id(char *fieldp) 785 { 786 int a_id = 0; 787 788 for (; *fieldp != '\0'; fieldp++) { 789 if (!isdigit(*fieldp)) { 790 fprintf(stderr, gettext("non-digit in id field\n")); 791 return (-1); 792 } 793 a_id = a_id * 10 + (*fieldp - '0'); 794 } 795 return (a_id); 796 } 797