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