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