]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - repair/attr_repair.c
Allow swab.h to be used in -pedantic c++ build environments.
[thirdparty/xfsprogs-dev.git] / repair / attr_repair.c
CommitLineData
2bd0ea18 1/*
33a4da69 2 * Copyright (c) 2000-2002,2004 Silicon Graphics, Inc. All Rights Reserved.
dfc130f3 3 *
2bd0ea18
NS
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
dfc130f3 7 *
2bd0ea18
NS
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
dfc130f3 11 *
2bd0ea18
NS
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
dfc130f3 18 *
2bd0ea18
NS
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc., 59
21 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
dfc130f3 22 *
2bd0ea18
NS
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
dfc130f3
RC
25 *
26 * http://www.sgi.com
27 *
28 * For further information regarding this notice, see:
29 *
2bd0ea18
NS
30 * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
31 */
32
33#include <libxfs.h>
2bd0ea18
NS
34#include "globals.h"
35#include "err_protos.h"
fc49813f 36#include "attr_repair.h"
2bd0ea18
NS
37#include "dir.h"
38#include "dinode.h"
39#include "bmap.h"
40
43533211 41static int xfs_acl_valid(xfs_acl_t *aclp);
14290264 42static int xfs_mac_valid(xfs_mac_label_t *lp);
2bd0ea18
NS
43
44
45/*
dfc130f3 46 * For attribute repair, there are 3 formats to worry about. First, is
2bd0ea18
NS
47 * shortform attributes which reside in the inode. Second is the leaf
48 * form, and lastly the btree. Much of this models after the directory
dfc130f3 49 * structure so code resembles the directory repair cases.
2bd0ea18 50 * For shortform case, if an attribute looks corrupt, it is removed.
dfc130f3 51 * If that leaves the shortform down to 0 attributes, it's okay and
2bd0ea18
NS
52 * will appear to just have a null attribute fork. Some checks are done
53 * for validity of the value field based on what the security needs are.
43533211
NS
54 * Calls will be made to xfs_mac_valid or xfs_acl_valid routines if the
55 * security attributes exist. They will be cleared if invalid.
56 * No other values will be checked. The DMF folks do not have current
2bd0ea18
NS
57 * requirements, but may in the future.
58 *
59 * For leaf block attributes, it requires more processing. One sticky
dfc130f3 60 * point is that the attributes can be local (within the leaf) or
2bd0ea18
NS
61 * remote (outside the leaf in other blocks). Thinking of local only
62 * if you get a bad attribute, and want to delete just one, its a-okay
63 * if it remains large enough to still be a leaf block attribute. Otherwise,
64 * it may have to be converted to shortform. How to convert this and when
65 * is an issue. This call is happening in Phase3. Phase5 will capture empty
66 * blocks, but Phase6 allows you to use the simulation library which knows
67 * how to handle attributes in the kernel for converting formats. What we
68 * could do is mark an attribute to be cleared now, but in phase6 somehow
69 * have it cleared for real and then the format changed to shortform if
70 * applicable. Since this requires more work than I anticipate can be
71 * accomplished for the next release, we will instead just say any bad
72 * attribute in the leaf block will make the entire attribute fork be
73 * cleared. The simplest way to do that is to ignore the leaf format, and
74 * call clear_dinode_attr to just make a shortform attribute fork with
dfc130f3 75 * zero entries.
2bd0ea18
NS
76 *
77 * Another issue with handling repair on leaf attributes is the remote
78 * blocks. To make sure that they look good and are not used multiple times
79 * by the attribute fork, some mechanism to keep track of all them is necessary.
80 * Do this in the future, time permitting. For now, note that there is no
81 * check for remote blocks and their allocations.
82 *
83 * For btree formatted attributes, the model can follow directories. That
84 * would mean go down the tree to the leftmost leaf. From there moving down
85 * the links and processing each. They would call back up the tree, to verify
86 * that the tree structure is okay. Any problems will result in the attribute
87 * fork being emptied and put in shortform format.
88 */
89
90/*
91 * This routine just checks what security needs are for attribute values
92 * only called when root flag is set, otherwise these names could exist in
93 * in user attribute land without a conflict.
94 * If value is non-zero, then a remote attribute is being passed in
95 */
96
97int
98valuecheck(char *namevalue, char *value, int namelen, int valuelen)
99{
100 /* for proper alignment issues, get the structs and bcopy the values */
14290264 101 xfs_mac_label_t macl;
43533211 102 xfs_acl_t thisacl;
2bd0ea18
NS
103 void *valuep;
104 int clearit = 0;
105
dfc130f3
RC
106 if ((strncmp(namevalue, SGI_ACL_FILE, SGI_ACL_FILE_SIZE) == 0) ||
107 (strncmp(namevalue, SGI_ACL_DEFAULT,
2bd0ea18 108 SGI_ACL_DEFAULT_SIZE) == 0)) {
dfc130f3 109 if (value == NULL) {
43533211 110 bzero(&thisacl, sizeof(xfs_acl_t));
2bd0ea18
NS
111 bcopy(namevalue+namelen, &thisacl, valuelen);
112 valuep = &thisacl;
113 } else
114 valuep = value;
115
43533211 116 if (xfs_acl_valid((xfs_acl_t *) valuep) != 0) { /* 0 is valid */
2bd0ea18 117 clearit = 1;
507f4e33
NS
118 do_warn(
119 _("entry contains illegal value in attribute named SGI_ACL_FILE "
120 "or SGI_ACL_DEFAULT\n"));
2bd0ea18
NS
121 }
122 } else if (strncmp(namevalue, SGI_MAC_FILE, SGI_MAC_FILE_SIZE) == 0) {
123 if (value == NULL) {
14290264 124 bzero(&macl, sizeof(xfs_mac_label_t));
2bd0ea18
NS
125 bcopy(namevalue+namelen, &macl, valuelen);
126 valuep = &macl;
dfc130f3 127 } else
2bd0ea18
NS
128 valuep = value;
129
14290264 130 if (xfs_mac_valid((xfs_mac_label_t *)valuep) != 1) { /* 1 is valid */
2bd0ea18 131 /*
dfc130f3 132 * if sysconf says MAC enabled,
2bd0ea18
NS
133 * temp = mac_from_text("msenhigh/mintlow", NULL)
134 * copy it to value, update valuelen, totsize
135 * This causes pushing up or down of all following
136 * attributes, forcing a attribute format change!!
137 * else clearit = 1;
138 */
139 clearit = 1;
507f4e33
NS
140 do_warn(
141 _("entry contains illegal value in attribute named SGI_MAC_LABEL\n"));
2bd0ea18
NS
142 }
143 } else if (strncmp(namevalue, SGI_CAP_FILE, SGI_CAP_FILE_SIZE) == 0) {
14290264 144 if ( valuelen != sizeof(xfs_cap_set_t)) {
2bd0ea18 145 clearit = 1;
507f4e33
NS
146 do_warn(
147 _("entry contains illegal value in attribute named SGI_CAP_FILE\n"));
2bd0ea18
NS
148 }
149 }
150
151 return(clearit);
152}
153
154
155/*
156 * this routine validates the attributes in shortform format.
157 * a non-zero return repair value means certain attributes are bogus
158 * and were cleared if possible. Warnings do not generate error conditions
159 * if you cannot modify the structures. repair is set to 1, if anything
160 * was fixed.
161 */
162int
163process_shortform_attr(
164 xfs_ino_t ino,
165 xfs_dinode_t *dip,
dfc130f3 166 int *repair)
2bd0ea18
NS
167{
168 xfs_attr_shortform_t *asf;
169 xfs_attr_sf_entry_t *currententry, *nextentry, *tempentry;
170 int i, junkit;
171 int currentsize, remainingspace;
dfc130f3 172
2bd0ea18
NS
173 *repair = 0;
174
46eca962 175 asf = (xfs_attr_shortform_t *) XFS_DFORK_APTR(dip);
2bd0ea18
NS
176
177 /* Assumption: hdr.totsize is less than a leaf block and was checked
dfc130f3 178 * by lclinode for valid sizes. Check the count though.
2bd0ea18 179 */
dfc130f3 180 if (INT_GET(asf->hdr.count, ARCH_CONVERT) == 0)
2bd0ea18
NS
181 /* then the total size should just be the header length */
182 if (INT_GET(asf->hdr.totsize, ARCH_CONVERT) != sizeof(xfs_attr_sf_hdr_t)) {
183 /* whoops there's a discrepancy. Clear the hdr */
184 if (!no_modify) {
507f4e33
NS
185 do_warn(
186 _("there are no attributes in the fork for inode %llu\n"),
187 ino);
2bd0ea18
NS
188 INT_SET(asf->hdr.totsize, ARCH_CONVERT,
189 sizeof(xfs_attr_sf_hdr_t));
190 *repair = 1;
dfc130f3 191 return(1);
2bd0ea18 192 } else {
507f4e33
NS
193 do_warn(
194 _("would junk the attribute fork since count is 0 for inode %llu\n"),
195 ino);
2bd0ea18
NS
196 return(1);
197 }
dfc130f3
RC
198 }
199
200 currentsize = sizeof(xfs_attr_sf_hdr_t);
2bd0ea18
NS
201 remainingspace = INT_GET(asf->hdr.totsize, ARCH_CONVERT) - currentsize;
202 nextentry = &asf->list[0];
203 for (i = 0; i < INT_GET(asf->hdr.count, ARCH_CONVERT); i++) {
204 currententry = nextentry;
205 junkit = 0;
206
207 /* don't go off the end if the hdr.count was off */
dfc130f3 208 if ((currentsize + (sizeof(xfs_attr_sf_entry_t) - 1)) >
2bd0ea18
NS
209 INT_GET(asf->hdr.totsize, ARCH_CONVERT))
210 break; /* get out and reset count and totSize */
211
212 /* if the namelen is 0, can't get to the rest of the entries */
213 if (INT_GET(currententry->namelen, ARCH_CONVERT) == 0) {
507f4e33 214 do_warn(_("zero length name entry in attribute fork,"));
2bd0ea18 215 if (!no_modify) {
507f4e33
NS
216 do_warn(
217 _(" truncating attributes for inode %llu to %d\n"), ino, i);
2bd0ea18 218 *repair = 1;
dfc130f3 219 break; /* and then update hdr fields */
2bd0ea18 220 } else {
507f4e33
NS
221 do_warn(
222 _(" would truncate attributes for inode %llu to %d\n"), ino, i);
2bd0ea18
NS
223 break;
224 }
225 } else {
226 /* It's okay to have a 0 length valuelen, but do a
227 * rough check to make sure we haven't gone outside of
228 * totsize.
229 */
507f4e33
NS
230 if ((remainingspace <
231 INT_GET(currententry->namelen, ARCH_CONVERT)) ||
232 ((remainingspace -
233 INT_GET(currententry->namelen, ARCH_CONVERT)) <
234 INT_GET(currententry->valuelen, ARCH_CONVERT))) {
235 do_warn(
236 _("name or value attribute lengths are too large,\n"));
2bd0ea18 237 if (!no_modify) {
507f4e33
NS
238 do_warn(
239 _(" truncating attributes for inode %llu to %d\n"),
240 ino, i);
dfc130f3 241 *repair = 1;
2bd0ea18
NS
242 break; /* and then update hdr fields */
243 } else {
507f4e33
NS
244 do_warn(
245 _(" would truncate attributes for inode %llu to %d\n"),
dfc130f3 246 ino, i);
2bd0ea18 247 break;
dfc130f3 248 }
2bd0ea18
NS
249 }
250 }
dfc130f3
RC
251
252 /* namecheck checks for / and null terminated for file names.
2bd0ea18
NS
253 * attributes names currently follow the same rules.
254 */
dfc130f3 255 if (namecheck((char *)&currententry->nameval[0],
2bd0ea18 256 INT_GET(currententry->namelen, ARCH_CONVERT))) {
507f4e33
NS
257 do_warn(
258 _("entry contains illegal character in shortform attribute name\n"));
2bd0ea18
NS
259 junkit = 1;
260 }
261
262 if (INT_GET(currententry->flags, ARCH_CONVERT) & XFS_ATTR_INCOMPLETE) {
507f4e33
NS
263 do_warn(
264 _("entry has INCOMPLETE flag on in shortform attribute\n"));
2bd0ea18
NS
265 junkit = 1;
266 }
267
268 /* Only check values for root security attributes */
dfc130f3 269 if (INT_GET(currententry->flags, ARCH_CONVERT) & XFS_ATTR_ROOT)
507f4e33 270 junkit = valuecheck((char *)&currententry->nameval[0],
dfc130f3 271 NULL,
507f4e33
NS
272 INT_GET(currententry->namelen, ARCH_CONVERT),
273 INT_GET(currententry->valuelen, ARCH_CONVERT));
2bd0ea18 274
dfc130f3 275 remainingspace = remainingspace -
2bd0ea18
NS
276 XFS_ATTR_SF_ENTSIZE(currententry);
277
278 if (junkit) {
279 if (!no_modify) {
280 /* get rid of only this entry */
507f4e33
NS
281 do_warn(
282 _("removing attribute entry %d for inode %llu\n"),
283 i, ino);
2bd0ea18
NS
284 tempentry = (xfs_attr_sf_entry_t *)
285 ((__psint_t) currententry +
286 XFS_ATTR_SF_ENTSIZE(currententry));
287 memmove(currententry,tempentry,remainingspace);
288 INT_MOD(asf->hdr.count, ARCH_CONVERT, -1);
289 i--; /* no worries, it will wrap back to 0 */
290 *repair = 1;
291 continue; /* go back up now */
dfc130f3 292 } else {
507f4e33
NS
293 do_warn(
294 _("would remove attribute entry %d for inode %llu\n"),
295 i, ino);
dfc130f3
RC
296 }
297 }
2bd0ea18
NS
298
299 /* Let's get ready for the next entry... */
300 nextentry = (xfs_attr_sf_entry_t *)
301 ((__psint_t) nextentry +
302 XFS_ATTR_SF_ENTSIZE(currententry));
303 currentsize = currentsize + XFS_ATTR_SF_ENTSIZE(currententry);
dfc130f3 304
507f4e33 305 } /* end the loop */
2bd0ea18 306
2bd0ea18
NS
307 if (INT_GET(asf->hdr.count, ARCH_CONVERT) != i) {
308 if (no_modify) {
507f4e33
NS
309 do_warn(_("would have corrected attribute entry count "
310 "in inode %llu from %d to %d\n"),
2bd0ea18
NS
311 ino, INT_GET(asf->hdr.count, ARCH_CONVERT), i);
312 } else {
507f4e33
NS
313 do_warn(_("corrected attribute entry count in inode "
314 "%llu, was %d, now %d\n"),
2bd0ea18
NS
315 ino, INT_GET(asf->hdr.count, ARCH_CONVERT), i);
316 INT_SET(asf->hdr.count, ARCH_CONVERT, i);
317 *repair = 1;
318 }
319 }
dfc130f3 320
2bd0ea18
NS
321 /* ASSUMPTION: currentsize <= totsize */
322 if (INT_GET(asf->hdr.totsize, ARCH_CONVERT) != currentsize) {
323 if (no_modify) {
507f4e33
NS
324 do_warn(_("would have corrected attribute totsize in "
325 "inode %llu from %d to %d\n"),
326 ino, INT_GET(asf->hdr.totsize, ARCH_CONVERT),
327 currentsize);
2bd0ea18 328 } else {
507f4e33
NS
329 do_warn(_("corrected attribute entry totsize in "
330 "inode %llu, was %d, now %d\n"),
331 ino, INT_GET(asf->hdr.totsize, ARCH_CONVERT),
332 currentsize);
2bd0ea18
NS
333 INT_SET(asf->hdr.totsize, ARCH_CONVERT, currentsize);
334 *repair = 1;
335 }
336 }
337
338 return(*repair);
339}
340
341/* This routine brings in blocks from disk one by one and assembles them
342 * in the value buffer. If get_bmapi gets smarter later to return an extent
343 * or list of extents, that would be great. For now, we don't expect too
344 * many blocks per remote value, so one by one is sufficient.
345 */
346static int
347rmtval_get(xfs_mount_t *mp, xfs_ino_t ino, blkmap_t *blkmap,
348 xfs_dablk_t blocknum, int valuelen, char* value)
349{
350 xfs_dfsbno_t bno;
351 xfs_buf_t *bp;
352 int clearit = 0, i = 0, length = 0, amountdone = 0;
dfc130f3 353
2bd0ea18 354 /* ASSUMPTION: valuelen is a valid number, so use it for looping */
dfc130f3 355 /* Note that valuelen is not a multiple of blocksize */
2bd0ea18
NS
356 while (amountdone < valuelen) {
357 bno = blkmap_get(blkmap, blocknum + i);
358 if (bno == NULLDFSBNO) {
507f4e33
NS
359 do_warn(_("remote block for attributes of inode %llu"
360 " is missing\n"), ino);
2bd0ea18
NS
361 clearit = 1;
362 break;
363 }
364 bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, bno),
365 XFS_FSB_TO_BB(mp, 1), 0);
366 if (!bp) {
507f4e33
NS
367 do_warn(_("can't read remote block for attributes"
368 " of inode %llu\n"), ino);
2bd0ea18
NS
369 clearit = 1;
370 break;
371 }
372 ASSERT(mp->m_sb.sb_blocksize == XFS_BUF_COUNT(bp));
373 length = MIN(XFS_BUF_COUNT(bp), valuelen - amountdone);
dfc130f3 374 bcopy(XFS_BUF_PTR(bp), value, length);
2bd0ea18
NS
375 amountdone += length;
376 value += length;
377 i++;
378 libxfs_putbuf(bp);
379 }
380 return (clearit);
381}
382
383/*
384 * freespace map for directory and attribute leaf blocks (1 bit per byte)
385 * 1 == used, 0 == free
386 */
387static da_freemap_t attr_freemap[DA_BMAP_SIZE];
388
389/* The block is read in. The magic number and forward / backward
390 * links are checked by the caller process_leaf_attr.
391 * If any problems occur the routine returns with non-zero. In
392 * this case the next step is to clear the attribute fork, by
393 * changing it to shortform and zeroing it out. Forkoff need not
dfc130f3 394 * be changed.
2bd0ea18
NS
395 */
396
397int
398process_leaf_attr_block(
399 xfs_mount_t *mp,
400 xfs_attr_leafblock_t *leaf,
401 xfs_dablk_t da_bno,
402 xfs_ino_t ino,
403 blkmap_t *blkmap,
404 xfs_dahash_t last_hashval,
405 xfs_dahash_t *current_hashval,
dfc130f3 406 int *repair)
2bd0ea18
NS
407{
408 xfs_attr_leaf_entry_t *entry;
409 xfs_attr_leaf_name_local_t *local;
410 xfs_attr_leaf_name_remote_t *remotep;
411 int i, start, stop, clearit, usedbs, firstb, thissize;
412
413 clearit = usedbs = 0;
414 *repair = 0;
dfc130f3 415 firstb = mp->m_sb.sb_blocksize;
2bd0ea18
NS
416 stop = sizeof(xfs_attr_leaf_hdr_t);
417
418 /* does the count look sorta valid? */
419 if (INT_GET(leaf->hdr.count, ARCH_CONVERT)
420 * sizeof(xfs_attr_leaf_entry_t)
421 + sizeof(xfs_attr_leaf_hdr_t)
422 > XFS_LBSIZE(mp)) {
507f4e33
NS
423 do_warn(
424 _("bad attribute count %d in attr block %u, inode %llu\n"),
2bd0ea18
NS
425 (int) INT_GET(leaf->hdr.count, ARCH_CONVERT),
426 da_bno, ino);
427 return (1);
428 }
dfc130f3 429
2bd0ea18
NS
430 init_da_freemap(attr_freemap);
431 (void) set_da_freemap(mp, attr_freemap, 0, stop);
dfc130f3 432
2bd0ea18 433 /* go thru each entry checking for problems */
dfc130f3 434 for (i = 0, entry = &leaf->entries[0];
2bd0ea18
NS
435 i < INT_GET(leaf->hdr.count, ARCH_CONVERT);
436 i++, entry++) {
dfc130f3 437
2bd0ea18
NS
438 /* check if index is within some boundary. */
439 if (INT_GET(entry->nameidx, ARCH_CONVERT) > XFS_LBSIZE(mp)) {
507f4e33
NS
440 do_warn(
441 _("bad attribute nameidx %d in attr block %u, inode %llu\n"),
2bd0ea18
NS
442 (int)INT_GET(entry->nameidx, ARCH_CONVERT),
443 da_bno,ino);
444 clearit = 1;
445 break;
507f4e33 446 }
2bd0ea18
NS
447
448 if (INT_GET(entry->flags, ARCH_CONVERT) & XFS_ATTR_INCOMPLETE) {
449 /* we are inconsistent state. get rid of us */
507f4e33
NS
450 do_warn(
451 _("attribute entry #%d in attr block %u, inode %llu is INCOMPLETE\n"),
2bd0ea18
NS
452 i, da_bno, ino);
453 clearit = 1;
454 break;
507f4e33 455 }
2bd0ea18
NS
456
457 /* mark the entry used */
458 start = (__psint_t)&leaf->entries[i] - (__psint_t)leaf;
459 stop = start + sizeof(xfs_attr_leaf_entry_t);
460 if (set_da_freemap(mp, attr_freemap, start, stop)) {
507f4e33
NS
461 do_warn(
462 _("attribute entry %d in attr block %u, inode %llu claims "
463 "already used space\n"),
464 i, da_bno, ino);
2bd0ea18
NS
465 clearit = 1;
466 break; /* got an overlap */
507f4e33 467 }
2bd0ea18
NS
468
469 if (INT_GET(entry->flags, ARCH_CONVERT) & XFS_ATTR_LOCAL) {
470
dfc130f3
RC
471 local = XFS_ATTR_LEAF_NAME_LOCAL(leaf, i);
472 if ((INT_GET(local->namelen, ARCH_CONVERT) == 0) ||
473 (namecheck((char *)&local->nameval[0],
507f4e33
NS
474 INT_GET(local->namelen, ARCH_CONVERT)))) {
475 do_warn(
476 _("attribute entry %d in attr block %u, inode %llu "
477 "has bad name (namelen = %d)\n"),
478 i, da_bno, ino, (int)
479 INT_GET(local->namelen, ARCH_CONVERT));
2bd0ea18
NS
480 clearit = 1;
481 break;
507f4e33 482 }
2bd0ea18 483
507f4e33
NS
484 /* Check on the hash value. Checking order of values
485 * is not necessary, since one wrong clears the whole
dfc130f3
RC
486 * fork. If the ordering's wrong, it's caught here or
487 * the kernel code has a bug with transaction logging
507f4e33 488 * or attributes itself. Being paranoid, let's check
dfc130f3
RC
489 * ordering anyway in case both the name value and the
490 * hashvalue were wrong but matched. Unlikely, however.
2bd0ea18 491 */
dfc130f3 492 if (INT_GET(entry->hashval, ARCH_CONVERT) !=
2bd0ea18 493 libxfs_da_hashname((char *)&local->nameval[0],
507f4e33
NS
494 INT_GET(local->namelen,
495 ARCH_CONVERT)) ||
496 (INT_GET(entry->hashval, ARCH_CONVERT) <
497 last_hashval)) {
498 do_warn(
499 _("bad hashvalue for attribute entry %d in "
500 "attr block %u, inode %llu\n"),
2bd0ea18
NS
501 i, da_bno, ino);
502 clearit = 1;
503 break;
504 }
505
506 /* Only check values for root security attributes */
dfc130f3 507 if (INT_GET(entry->flags, ARCH_CONVERT) & XFS_ATTR_ROOT)
2bd0ea18 508 if (valuecheck((char *)&local->nameval[0], NULL,
507f4e33
NS
509 INT_GET(local->namelen, ARCH_CONVERT),
510 INT_GET(local->valuelen, ARCH_CONVERT))) {
511 do_warn(
512 _("bad security value for attribute entry %d in "
513 "attr block %u, inode %llu\n"),
514 i, da_bno, ino);
2bd0ea18
NS
515 clearit = 1;
516 break;
507f4e33
NS
517 }
518
2bd0ea18 519 thissize = XFS_ATTR_LEAF_ENTSIZE_LOCAL(
507f4e33
NS
520 INT_GET(local->namelen, ARCH_CONVERT),
521 INT_GET(local->valuelen, ARCH_CONVERT));
2bd0ea18
NS
522
523 } else {
524 /* do the remote case */
525 remotep = XFS_ATTR_LEAF_NAME_REMOTE(leaf, i);
526 thissize = XFS_ATTR_LEAF_ENTSIZE_REMOTE(
dfc130f3 527 INT_GET(remotep->namelen, ARCH_CONVERT));
2bd0ea18 528
dfc130f3 529 if ((INT_GET(remotep->namelen, ARCH_CONVERT) == 0) ||
2bd0ea18
NS
530 (namecheck((char *)&remotep->name[0],
531 INT_GET(remotep->namelen, ARCH_CONVERT))) ||
532 (INT_GET(entry->hashval, ARCH_CONVERT)
533 != libxfs_da_hashname(
534 (char *)&remotep->name[0],
535 INT_GET(remotep->namelen, ARCH_CONVERT))) ||
536 (INT_GET(entry->hashval, ARCH_CONVERT)
537 < last_hashval) ||
538 (INT_GET(remotep->valueblk, ARCH_CONVERT) == 0)) {
507f4e33
NS
539 do_warn(
540 _("inconsistent remote attribute entry %d in "
541 "attr block %u, ino %llu\n"),
2bd0ea18
NS
542 i, da_bno, ino);
543 clearit = 1;
544 break;
507f4e33 545 }
2bd0ea18
NS
546
547 if (INT_GET(entry->flags, ARCH_CONVERT) & XFS_ATTR_ROOT) {
548 char* value;
507f4e33
NS
549
550 if ((value = malloc(INT_GET(remotep->valuelen,
551 ARCH_CONVERT))) == NULL) {
552 do_warn(
553 _("cannot malloc enough for remotevalue attribute for inode %llu\n"),
554 ino);
555 do_warn(
556 _("SKIPPING this remote attribute\n"));
2bd0ea18
NS
557 continue;
558 }
559 if (rmtval_get(mp, ino, blkmap,
507f4e33
NS
560 INT_GET(remotep->valueblk,
561 ARCH_CONVERT),
562 INT_GET(remotep->valuelen,
563 ARCH_CONVERT), value)) {
564 do_warn(
565 _("remote attribute get failed for entry %d, inode %llu\n"), i, ino);
2bd0ea18
NS
566 clearit = 1;
567 free(value);
568 break;
569 }
570 if (valuecheck((char *)&remotep->name[0], value,
507f4e33
NS
571 INT_GET(remotep->namelen,
572 ARCH_CONVERT),
573 INT_GET(remotep->valuelen,
574 ARCH_CONVERT))) {
575 do_warn(
576 _("remote attribute value check failed for entry %d, inode %llu\n"),
577 i, ino);
2bd0ea18
NS
578 clearit = 1;
579 free(value);
580 break;
581 }
582 free(value);
583 }
584 }
585
dfc130f3 586 *current_hashval = last_hashval
2bd0ea18
NS
587 = INT_GET(entry->hashval, ARCH_CONVERT);
588
507f4e33
NS
589 if (set_da_freemap(mp, attr_freemap,
590 INT_GET(entry->nameidx, ARCH_CONVERT),
591 INT_GET(entry->nameidx, ARCH_CONVERT) +
592 thissize)) {
593 do_warn(_("attribute entry %d in attr block %u, "
594 "inode %llu claims used space\n"),
2bd0ea18
NS
595 i, da_bno, ino);
596 clearit = 1;
597 break; /* got an overlap */
dfc130f3 598 }
2bd0ea18 599 usedbs += thissize;
dfc130f3 600 if (INT_GET(entry->nameidx, ARCH_CONVERT) < firstb)
2bd0ea18
NS
601 firstb = INT_GET(entry->nameidx, ARCH_CONVERT);
602
603 } /* end the loop */
604
605 if (!clearit) {
606 /* verify the header information is correct */
607
608 /* if the holes flag is set, don't reset first_used unless it's
609 * pointing to used bytes. we're being conservative here
dfc130f3 610 * since the block will get compacted anyhow by the kernel.
2bd0ea18
NS
611 */
612
613 if ( (INT_GET(leaf->hdr.holes, ARCH_CONVERT) == 0
614 && firstb != INT_GET(leaf->hdr.firstused, ARCH_CONVERT))
615 || INT_GET(leaf->hdr.firstused, ARCH_CONVERT) > firstb) {
616 if (!no_modify) {
507f4e33
NS
617 do_warn(
618 _("- resetting first used heap value from %d to %d in "
619 "block %u of attribute fork of inode %llu\n"),
2bd0ea18
NS
620 (int)INT_GET(leaf->hdr.firstused,
621 ARCH_CONVERT), firstb,
622 da_bno, ino);
623 INT_SET(leaf->hdr.firstused,
624 ARCH_CONVERT, firstb);
625 *repair = 1;
626 } else {
507f4e33
NS
627 do_warn(
628 _("- would reset first used value from %d to %d in "
629 "block %u of attribute fork of inode %llu\n"),
2bd0ea18
NS
630 (int)INT_GET(leaf->hdr.firstused,
631 ARCH_CONVERT), firstb,
632 da_bno, ino);
633 }
634 }
635
636 if (usedbs != INT_GET(leaf->hdr.usedbytes, ARCH_CONVERT)) {
637 if (!no_modify) {
507f4e33
NS
638 do_warn(
639 _("- resetting usedbytes cnt from %d to %d in "
640 "block %u of attribute fork of inode %llu\n"),
2bd0ea18
NS
641 (int)INT_GET(leaf->hdr.usedbytes,
642 ARCH_CONVERT), usedbs, da_bno, ino);
643 INT_SET(leaf->hdr.usedbytes,
644 ARCH_CONVERT, usedbs);
645 *repair = 1;
646 } else {
507f4e33
NS
647 do_warn(
648 _("- would reset usedbytes cnt from %d to %d in "
649 "block %u of attribute fork of %llu\n"),
2bd0ea18
NS
650 (int)INT_GET(leaf->hdr.usedbytes,
651 ARCH_CONVERT), usedbs,da_bno,ino);
652 }
653 }
654
655 /* there's a lot of work in process_leaf_dir_block to go thru
656 * checking for holes and compacting if appropiate. I don't think
657 * attributes need all that, so let's just leave the holes. If
658 * we discover later that this is a good place to do compaction
dfc130f3 659 * we can add it then.
2bd0ea18
NS
660 */
661 }
662 return (clearit); /* and repair */
663}
664
665
666/*
667 * returns 0 if the attribute fork is ok, 1 if it has to be junked.
668 */
669int
670process_leaf_attr_level(xfs_mount_t *mp,
671 da_bt_cursor_t *da_cursor)
672{
673 int repair;
674 xfs_attr_leafblock_t *leaf;
675 xfs_buf_t *bp;
676 xfs_ino_t ino;
677 xfs_dfsbno_t dev_bno;
678 xfs_dablk_t da_bno;
679 xfs_dablk_t prev_bno;
680 xfs_dahash_t current_hashval = 0;
681 xfs_dahash_t greatest_hashval;
682
683 da_bno = da_cursor->level[0].bno;
684 ino = da_cursor->ino;
685 prev_bno = 0;
686
687 do {
688 repair = 0;
689 dev_bno = blkmap_get(da_cursor->blkmap, da_bno);
690 /*
691 * 0 is the root block and no block
692 * pointer can point to the root block of the btree
693 */
694 ASSERT(da_bno != 0);
695
696 if (dev_bno == NULLDFSBNO) {
507f4e33
NS
697 do_warn(_("can't map block %u for attribute fork "
698 "for inode %llu\n"), da_bno, ino);
dfc130f3 699 goto error_out;
2bd0ea18
NS
700 }
701
702 bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, dev_bno),
703 XFS_FSB_TO_BB(mp, 1), 0);
704 if (!bp) {
507f4e33
NS
705 do_warn(_("can't read file block %u (fsbno %llu) for"
706 " attribute fork of inode %llu\n"),
2bd0ea18
NS
707 da_bno, dev_bno, ino);
708 goto error_out;
709 }
710
711 leaf = (xfs_attr_leafblock_t *)XFS_BUF_PTR(bp);
712
713 /* check magic number for leaf directory btree block */
714 if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
715 != XFS_ATTR_LEAF_MAGIC) {
507f4e33
NS
716 do_warn(_("bad attribute leaf magic %#x "
717 "for inode %llu\n"),
2bd0ea18
NS
718 leaf->hdr.info.magic, ino);
719 libxfs_putbuf(bp);
720 goto error_out;
721 }
722
723 /*
724 * for each block, process the block, verify it's path,
725 * then get next block. update cursor values along the way
726 */
727 if (process_leaf_attr_block(mp, leaf, da_bno, ino,
728 da_cursor->blkmap, current_hashval,
729 &greatest_hashval, &repair)) {
730 libxfs_putbuf(bp);
731 goto error_out;
732 }
733
734 /*
735 * index can be set to hdr.count so match the
736 * indexes of the interior blocks -- which at the
737 * end of the block will point to 1 after the final
738 * real entry in the block
739 */
740 da_cursor->level[0].hashval = greatest_hashval;
741 da_cursor->level[0].bp = bp;
742 da_cursor->level[0].bno = da_bno;
743 da_cursor->level[0].index
744 = INT_GET(leaf->hdr.count, ARCH_CONVERT);
dfc130f3 745 da_cursor->level[0].dirty = repair;
2bd0ea18
NS
746
747 if (INT_GET(leaf->hdr.info.back, ARCH_CONVERT) != prev_bno) {
507f4e33
NS
748 do_warn(_("bad sibling back pointer for block %u in "
749 "attribute fork for inode %llu\n"),
750 da_bno, ino);
2bd0ea18
NS
751 libxfs_putbuf(bp);
752 goto error_out;
753 }
754
755 prev_bno = da_bno;
756 da_bno = INT_GET(leaf->hdr.info.forw, ARCH_CONVERT);
757
758 if (da_bno != 0 && verify_da_path(mp, da_cursor, 0)) {
759 libxfs_putbuf(bp);
760 goto error_out;
761 }
762
763 current_hashval = greatest_hashval;
764
765 if (repair && !no_modify) {
766 libxfs_writebuf(bp, 0);
767 }
768 else {
769 libxfs_putbuf(bp);
770 }
771 } while (da_bno != 0);
772
773 if (verify_final_da_path(mp, da_cursor, 0)) {
774 /*
775 * verify the final path up (right-hand-side) if still ok
776 */
507f4e33 777 do_warn(_("bad hash path in attribute fork for inode %llu\n"),
2bd0ea18
NS
778 da_cursor->ino);
779 goto error_out;
780 }
781
782 /* releases all buffers holding interior btree blocks */
783 release_da_cursor(mp, da_cursor, 0);
784 return(0);
785
786error_out:
787 /* release all buffers holding interior btree blocks */
788 err_release_da_cursor(mp, da_cursor, 0);
789 return(1);
790}
791
792
793/*
794 * a node directory is a true btree -- where the attribute fork
795 * has gotten big enough that it is represented as a non-trivial (e.g.
796 * has more than just a block) btree.
797 *
798 * Note that if we run into any problems, we will trash the attribute fork.
dfc130f3 799 *
2bd0ea18 800 * returns 0 if things are ok, 1 if bad
dfc130f3 801 * Note this code has been based off process_node_dir.
2bd0ea18
NS
802 */
803int
804process_node_attr(
805 xfs_mount_t *mp,
806 xfs_ino_t ino,
807 xfs_dinode_t *dip,
808 blkmap_t *blkmap)
809{
810 xfs_dablk_t bno;
811 int error = 0;
812 da_bt_cursor_t da_cursor;
813
814 /*
815 * try again -- traverse down left-side of tree until we hit
816 * the left-most leaf block setting up the btree cursor along
817 * the way. Then walk the leaf blocks left-to-right, calling
818 * a parent-verification routine each time we traverse a block.
819 */
820 bzero(&da_cursor, sizeof(da_bt_cursor_t));
821 da_cursor.active = 0;
822 da_cursor.type = 0;
823 da_cursor.ino = ino;
824 da_cursor.dip = dip;
825 da_cursor.greatest_bno = 0;
826 da_cursor.blkmap = blkmap;
827
828 /*
829 * now process interior node. don't have any buffers held in this path.
830 */
831 error = traverse_int_dablock(mp, &da_cursor, &bno, XFS_ATTR_FORK);
dfc130f3 832 if (error == 0)
2bd0ea18
NS
833 return(1); /* 0 means unsuccessful */
834
835 /*
836 * now pass cursor and bno into leaf-block processing routine
837 * the leaf dir level routine checks the interior paths
838 * up to the root including the final right-most path.
839 */
dfc130f3 840
2bd0ea18
NS
841 return (process_leaf_attr_level(mp, &da_cursor));
842}
843
844/*
845 * Start processing for a leaf or fuller btree.
846 * A leaf directory is one where the attribute fork is too big for
847 * the inode but is small enough to fit into one btree block
848 * outside the inode. This code is modelled after process_leaf_dir_block.
849 *
850 * returns 0 if things are ok, 1 if bad (attributes needs to be junked)
851 * repair is set, if anything was changed, but attributes can live thru it
852 */
853
854int
855process_longform_attr(
856 xfs_mount_t *mp,
857 xfs_ino_t ino,
858 xfs_dinode_t *dip,
859 blkmap_t *blkmap,
860 int *repair) /* out - 1 if something was fixed */
861{
862 xfs_attr_leafblock_t *leaf;
863 xfs_dfsbno_t bno;
864 xfs_buf_t *bp;
865 xfs_dahash_t next_hashval;
866 int repairlinks = 0;
867
868 *repair = 0;
869
870 bno = blkmap_get(blkmap, 0);
871
872 if ( bno == NULLDFSBNO ) {
873 if (INT_GET(dip->di_core.di_anextents, ARCH_CONVERT) == 0 &&
874 dip->di_core.di_aformat == XFS_DINODE_FMT_EXTENTS )
875 /* it's okay the kernel can handle this state */
876 return(0);
877 else {
507f4e33
NS
878 do_warn(_("block 0 of inode %llu attribute fork"
879 " is missing\n"), ino);
2bd0ea18
NS
880 return(1);
881 }
882 }
883 /* FIX FOR bug 653709 -- EKN */
884 if (mp->m_sb.sb_agcount < XFS_FSB_TO_AGNO(mp, bno)) {
507f4e33
NS
885 do_warn(_("agno of attribute fork of inode %llu out of "
886 "regular partition\n"), ino);
2bd0ea18
NS
887 return(1);
888 }
889
890 bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, bno),
891 XFS_FSB_TO_BB(mp, 1), 0);
892 if (!bp) {
507f4e33 893 do_warn(_("can't read block 0 of inode %llu attribute fork\n"),
2bd0ea18
NS
894 ino);
895 return(1);
896 }
897
898 /* verify leaf block */
899 leaf = (xfs_attr_leafblock_t *)XFS_BUF_PTR(bp);
900
901 /* check sibling pointers in leaf block or root block 0 before
902 * we have to release the btree block
903 */
904 if ( INT_GET(leaf->hdr.info.forw, ARCH_CONVERT) != 0
905 || INT_GET(leaf->hdr.info.back, ARCH_CONVERT) != 0) {
906 if (!no_modify) {
507f4e33
NS
907 do_warn(_("clearing forw/back pointers in block 0 "
908 "for attributes in inode %llu\n"), ino);
2bd0ea18
NS
909 repairlinks = 1;
910 INT_SET(leaf->hdr.info.forw, ARCH_CONVERT, 0);
911 INT_SET(leaf->hdr.info.back, ARCH_CONVERT, 0);
912 } else {
507f4e33
NS
913 do_warn(_("would clear forw/back pointers in block 0 "
914 "for attributes in inode %llu\n"), ino);
2bd0ea18
NS
915 }
916 }
917
918 /*
919 * use magic number to tell us what type of attribute this is.
920 * it's possible to have a node or leaf attribute in either an
921 * extent format or btree format attribute fork.
922 */
923 switch (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)) {
924 case XFS_ATTR_LEAF_MAGIC: /* leaf-form attribute */
925 if (process_leaf_attr_block(mp, leaf, 0, ino, blkmap,
926 0, &next_hashval, repair)) {
927 /* the block is bad. lose the attribute fork. */
928 libxfs_putbuf(bp);
dfc130f3 929 return(1);
2bd0ea18 930 }
dfc130f3 931 *repair = *repair || repairlinks;
2bd0ea18
NS
932 break;
933
934 case XFS_DA_NODE_MAGIC: /* btree-form attribute */
935 /* must do this now, to release block 0 before the traversal */
936 if (repairlinks) {
937 *repair = 1;
938 libxfs_writebuf(bp, 0);
dfc130f3
RC
939 } else
940 libxfs_putbuf(bp);
2bd0ea18
NS
941 return (process_node_attr(mp, ino, dip, blkmap)); /* + repair */
942 default:
507f4e33 943 do_warn(_("bad attribute leaf magic # %#x for dir ino %llu\n"),
2bd0ea18
NS
944 INT_GET(leaf->hdr.info.magic, ARCH_CONVERT), ino);
945 libxfs_putbuf(bp);
946 return(1);
947 }
948
dfc130f3 949 if (*repair && !no_modify)
2bd0ea18
NS
950 libxfs_writebuf(bp, 0);
951 else
952 libxfs_putbuf(bp);
953
954 return(0); /* repair may be set */
955}
956
957
061313d4 958static void
43533211 959xfs_acl_get_endian(xfs_acl_t *aclp)
061313d4 960{
43533211
NS
961 xfs_acl_entry_t *ace, *end;
962
963 INT_SET(aclp->acl_cnt, ARCH_CONVERT, aclp->acl_cnt);
964 end = &aclp->acl_entry[0]+aclp->acl_cnt;
965 for (ace = &aclp->acl_entry[0]; ace < end; ace++) {
966 INT_SET(ace->ae_tag, ARCH_CONVERT, ace->ae_tag);
967 INT_SET(ace->ae_id, ARCH_CONVERT, ace->ae_id);
968 INT_SET(ace->ae_perm, ARCH_CONVERT, ace->ae_perm);
969 }
061313d4
AG
970}
971
2bd0ea18
NS
972/*
973 * returns 1 if attributes got cleared
dfc130f3 974 * and 0 if things are ok.
2bd0ea18
NS
975 */
976int
977process_attributes(
978 xfs_mount_t *mp,
979 xfs_ino_t ino,
980 xfs_dinode_t *dip,
981 blkmap_t *blkmap,
982 int *repair) /* returned if we did repair */
983{
984 int err;
985 xfs_dinode_core_t *dinoc;
986 /* REFERENCED */
987 xfs_attr_shortform_t *asf;
988
989 dinoc = &dip->di_core;
46eca962 990 asf = (xfs_attr_shortform_t *) XFS_DFORK_APTR(dip);
2bd0ea18
NS
991
992 if (dinoc->di_aformat == XFS_DINODE_FMT_LOCAL) {
507f4e33 993 ASSERT(INT_GET(asf->hdr.totsize, ARCH_CONVERT) <=
46eca962 994 XFS_DFORK_ASIZE(dip, mp));
2bd0ea18
NS
995 err = process_shortform_attr(ino, dip, repair);
996 } else if (dinoc->di_aformat == XFS_DINODE_FMT_EXTENTS ||
997 dinoc->di_aformat == XFS_DINODE_FMT_BTREE) {
998 err = process_longform_attr(mp, ino, dip, blkmap,
999 repair);
1000 /* if err, convert this to shortform and clear it */
1001 /* if repair and no error, it's taken care of */
1002 } else {
507f4e33 1003 do_warn(_("illegal attribute format %d, ino %llu\n"),
2bd0ea18 1004 dinoc->di_aformat, ino);
dfc130f3 1005 err = 1;
2bd0ea18
NS
1006 }
1007 return (err); /* and repair */
1008}
1009
dfc130f3 1010/*
2bd0ea18
NS
1011 * Validate an ACL
1012 */
1013static int
43533211 1014xfs_acl_valid(xfs_acl_t *aclp)
2bd0ea18 1015{
43533211 1016 xfs_acl_entry_t *entry, *e;
2bd0ea18
NS
1017 int user = 0, group = 0, other = 0, mask = 0, mask_required = 0;
1018 int i, j;
1019
1020 if (aclp == NULL)
1021 goto acl_invalid;
1022
061313d4
AG
1023 xfs_acl_get_endian(aclp);
1024
43533211 1025 if (aclp->acl_cnt > XFS_ACL_MAX_ENTRIES)
2bd0ea18
NS
1026 goto acl_invalid;
1027
43533211 1028 for (i = 0; i < aclp->acl_cnt; i++) {
2bd0ea18 1029 entry = &aclp->acl_entry[i];
e80ad1c7
NS
1030 if (entry->ae_perm & ~(ACL_READ|ACL_WRITE|ACL_EXECUTE))
1031 goto acl_invalid;
43533211 1032 switch (entry->ae_tag) {
2bd0ea18
NS
1033 case ACL_USER_OBJ:
1034 if (user++)
1035 goto acl_invalid;
1036 break;
1037 case ACL_GROUP_OBJ:
1038 if (group++)
1039 goto acl_invalid;
1040 break;
43533211 1041 case ACL_OTHER:
2bd0ea18
NS
1042 if (other++)
1043 goto acl_invalid;
1044 break;
1045 case ACL_USER:
1046 case ACL_GROUP:
43533211 1047 for (j = i + 1; j < aclp->acl_cnt; j++) {
2bd0ea18 1048 e = &aclp->acl_entry[j];
43533211
NS
1049 if (e->ae_id == entry->ae_id &&
1050 e->ae_tag == entry->ae_tag)
2bd0ea18
NS
1051 goto acl_invalid;
1052 }
1053 mask_required++;
1054 break;
1055 case ACL_MASK:
1056 if (mask++)
1057 goto acl_invalid;
1058 break;
1059 default:
1060 goto acl_invalid;
1061 }
1062 }
1063 if (!user || !group || !other || (mask_required && !mask))
1064 goto acl_invalid;
1065 else
1066 return 0;
1067acl_invalid:
1068 errno = EINVAL;
1069 return (-1);
1070}
1071
1072/*
1073 * Check a category or division set to ensure that all values are in
1074 * ascending order and each division or category appears only once.
1075 */
1076static int
1077__check_setvalue(const unsigned short *list, unsigned short count)
1078{
43533211 1079 unsigned short i;
2bd0ea18 1080
43533211
NS
1081 for (i = 1; i < count ; i++)
1082 if (list[i] <= list[i-1])
1083 return -1;
1084 return 0;
2bd0ea18
NS
1085}
1086
2bd0ea18 1087/*
43533211 1088 * xfs_mac_valid(lp)
14290264 1089 * Check the validity of a MAC label.
2bd0ea18
NS
1090 */
1091static int
14290264 1092xfs_mac_valid(xfs_mac_label_t *lp)
2bd0ea18
NS
1093{
1094 if (lp == NULL)
1095 return (0);
1096
1097 /*
1098 * if the total category set and division set is greater than 250
1099 * report error
1100 */
14290264 1101 if ((lp->ml_catcount + lp->ml_divcount) > XFS_MAC_MAX_SETS)
2bd0ea18
NS
1102 return(0);
1103
1104 /*
1105 * check whether the msentype value is valid, and do they have
dfc130f3
RC
1106 * appropriate level, category association.
1107 */
2bd0ea18 1108 switch (lp->ml_msen_type) {
e49e365f
NS
1109 case XFS_MSEN_ADMIN_LABEL:
1110 case XFS_MSEN_EQUAL_LABEL:
1111 case XFS_MSEN_HIGH_LABEL:
1112 case XFS_MSEN_MLD_HIGH_LABEL:
1113 case XFS_MSEN_LOW_LABEL:
1114 case XFS_MSEN_MLD_LOW_LABEL:
2bd0ea18
NS
1115 if (lp->ml_level != 0 || lp->ml_catcount > 0 )
1116 return (0);
1117 break;
e49e365f
NS
1118 case XFS_MSEN_TCSEC_LABEL:
1119 case XFS_MSEN_MLD_LABEL:
2bd0ea18
NS
1120 if (lp->ml_catcount > 0 &&
1121 __check_setvalue(lp->ml_list,
1122 lp->ml_catcount) == -1)
1123 return (0);
1124 break;
e49e365f 1125 case XFS_MSEN_UNKNOWN_LABEL:
2bd0ea18
NS
1126 default:
1127 return (0);
1128 }
1129
1130 /*
1131 * check whether the minttype value is valid, and do they have
1132 * appropriate grade, division association.
1133 */
1134 switch (lp->ml_mint_type) {
e49e365f 1135 case XFS_MINT_BIBA_LABEL:
2bd0ea18
NS
1136 if (lp->ml_divcount > 0 &&
1137 __check_setvalue(lp->ml_list + lp->ml_catcount,
1138 lp->ml_divcount) == -1)
1139 return(0);
1140 break;
e49e365f
NS
1141 case XFS_MINT_EQUAL_LABEL:
1142 case XFS_MINT_HIGH_LABEL:
1143 case XFS_MINT_LOW_LABEL:
2bd0ea18
NS
1144 if (lp->ml_grade != 0 || lp->ml_divcount > 0 )
1145 return(0);
1146 break;
1147 default:
1148 return(0);
1149 }
1150
1151 return (1);
1152}