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