]> granicus.if.org Git - strace/blob - quota.c
io.c: use printaddr and umove_or_printaddr
[strace] / quota.c
1 /*
2  * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3  * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4  * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
5  * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
6  * Copyright (c) 2005, 2006 Dmitry V. Levin <ldv@altlinux.org>
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. The name of the author may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include "defs.h"
33
34 #define SUBCMDMASK  0x00ff
35 #define SUBCMDSHIFT 8
36 #define QCMD_CMD(cmd)   ((u_int32_t)(cmd) >> SUBCMDSHIFT)
37 #define QCMD_TYPE(cmd)  ((u_int32_t)(cmd) & SUBCMDMASK)
38
39 #define OLD_CMD(cmd)    ((u_int32_t)(cmd) << 8)
40 #define NEW_CMD(cmd)    ((u_int32_t)(cmd) | 0x800000)
41 #define XQM_CMD(cmd)    ((u_int32_t)(cmd) | ('X'<<8))
42
43 #define Q_V1_QUOTAON    OLD_CMD(0x1)
44 #define Q_V1_QUOTAOFF   OLD_CMD(0x2)
45 #define Q_V1_GETQUOTA   OLD_CMD(0x3)
46 #define Q_V1_SETQUOTA   OLD_CMD(0x4)
47 #define Q_V1_SETUSE     OLD_CMD(0x5)
48 #define Q_V1_SYNC       OLD_CMD(0x6)
49 #define Q_SETQLIM       OLD_CMD(0x7)
50 #define Q_V1_GETSTATS   OLD_CMD(0x8)
51 #define Q_V1_RSQUASH    OLD_CMD(0x10)
52
53 #define Q_V2_GETQUOTA   OLD_CMD(0xD)
54 #define Q_V2_SETQUOTA   OLD_CMD(0xE)
55 #define Q_V2_SETUSE     OLD_CMD(0xF)
56 #define Q_V2_GETINFO    OLD_CMD(0x9)
57 #define Q_V2_SETINFO    OLD_CMD(0xA)
58 #define Q_V2_SETGRACE   OLD_CMD(0xB)
59 #define Q_V2_SETFLAGS   OLD_CMD(0xC)
60 #define Q_V2_GETSTATS   OLD_CMD(0x11)
61
62 #define Q_SYNC          NEW_CMD(0x1)
63 #define Q_QUOTAON       NEW_CMD(0x2)
64 #define Q_QUOTAOFF      NEW_CMD(0x3)
65 #define Q_GETFMT        NEW_CMD(0x4)
66 #define Q_GETINFO       NEW_CMD(0x5)
67 #define Q_SETINFO       NEW_CMD(0x6)
68 #define Q_GETQUOTA      NEW_CMD(0x7)
69 #define Q_SETQUOTA      NEW_CMD(0x8)
70
71 #define Q_XQUOTAON      XQM_CMD(0x1)
72 #define Q_XQUOTAOFF     XQM_CMD(0x2)
73 #define Q_XGETQUOTA     XQM_CMD(0x3)
74 #define Q_XSETQLIM      XQM_CMD(0x4)
75 #define Q_XGETQSTAT     XQM_CMD(0x5)
76 #define Q_XQUOTARM      XQM_CMD(0x6)
77 #define Q_XQUOTASYNC    XQM_CMD(0x7)
78
79 #include "xlat/quotacmds.h"
80
81 #define USRQUOTA 0
82 #define GRPQUOTA 1
83
84 #include "xlat/quotatypes.h"
85
86 /* Quota format identifiers */
87 #define QFMT_VFS_OLD 1
88 #define QFMT_VFS_V0  2
89
90 #include "xlat/quota_formats.h"
91
92 #define XFS_QUOTA_UDQ_ACCT      (1<<0)  /* user quota accounting */
93 #define XFS_QUOTA_UDQ_ENFD      (1<<1)  /* user quota limits enforcement */
94 #define XFS_QUOTA_GDQ_ACCT      (1<<2)  /* group quota accounting */
95 #define XFS_QUOTA_GDQ_ENFD      (1<<3)  /* group quota limits enforcement */
96
97 #define XFS_USER_QUOTA          (1<<0)  /* user quota type */
98 #define XFS_PROJ_QUOTA          (1<<1)  /* (IRIX) project quota type */
99 #define XFS_GROUP_QUOTA         (1<<2)  /* group quota type */
100
101 #include "xlat/xfs_quota_flags.h"
102 #include "xlat/xfs_dqblk_flags.h"
103
104 /*
105  * Following flags are used to specify which fields are valid
106  */
107 #define QIF_BLIMITS     1
108 #define QIF_SPACE       2
109 #define QIF_ILIMITS     4
110 #define QIF_INODES      8
111 #define QIF_BTIME       16
112 #define QIF_ITIME       32
113
114 #include "xlat/if_dqblk_valid.h"
115
116 struct if_dqblk
117 {
118         u_int64_t dqb_bhardlimit;
119         u_int64_t dqb_bsoftlimit;
120         u_int64_t dqb_curspace;
121         u_int64_t dqb_ihardlimit;
122         u_int64_t dqb_isoftlimit;
123         u_int64_t dqb_curinodes;
124         u_int64_t dqb_btime;
125         u_int64_t dqb_itime;
126         u_int32_t dqb_valid;
127 };
128
129 struct v1_dqblk
130 {
131         u_int32_t dqb_bhardlimit;       /* absolute limit on disk blks alloc */
132         u_int32_t dqb_bsoftlimit;       /* preferred limit on disk blks */
133         u_int32_t dqb_curblocks;        /* current block count */
134         u_int32_t dqb_ihardlimit;       /* maximum # allocated inodes */
135         u_int32_t dqb_isoftlimit;       /* preferred inode limit */
136         u_int32_t dqb_curinodes;        /* current # allocated inodes */
137         time_t  dqb_btime;      /* time limit for excessive disk use */
138         time_t  dqb_itime;      /* time limit for excessive files */
139 };
140
141 struct v2_dqblk
142 {
143         unsigned int dqb_ihardlimit;
144         unsigned int dqb_isoftlimit;
145         unsigned int dqb_curinodes;
146         unsigned int dqb_bhardlimit;
147         unsigned int dqb_bsoftlimit;
148         u_int64_t dqb_curspace;
149         time_t  dqb_btime;
150         time_t  dqb_itime;
151 };
152
153 struct xfs_dqblk
154 {
155         int8_t  d_version;      /* version of this structure */
156         int8_t  d_flags;        /* XFS_{USER,PROJ,GROUP}_QUOTA */
157         u_int16_t d_fieldmask;  /* field specifier */
158         u_int32_t d_id;         /* user, project, or group ID */
159         u_int64_t d_blk_hardlimit;      /* absolute limit on disk blks */
160         u_int64_t d_blk_softlimit;      /* preferred limit on disk blks */
161         u_int64_t d_ino_hardlimit;      /* maximum # allocated inodes */
162         u_int64_t d_ino_softlimit;      /* preferred inode limit */
163         u_int64_t d_bcount;     /* # disk blocks owned by the user */
164         u_int64_t d_icount;     /* # inodes owned by the user */
165         int32_t d_itimer;       /* zero if within inode limits */
166         int32_t d_btimer;       /* similar to above; for disk blocks */
167         u_int16_t d_iwarns;     /* # warnings issued wrt num inodes */
168         u_int16_t d_bwarns;     /* # warnings issued wrt disk blocks */
169         int32_t d_padding2;     /* padding2 - for future use */
170         u_int64_t d_rtb_hardlimit;      /* absolute limit on realtime blks */
171         u_int64_t d_rtb_softlimit;      /* preferred limit on RT disk blks */
172         u_int64_t d_rtbcount;   /* # realtime blocks owned */
173         int32_t d_rtbtimer;     /* similar to above; for RT disk blks */
174         u_int16_t d_rtbwarns;   /* # warnings issued wrt RT disk blks */
175         int16_t d_padding3;     /* padding3 - for future use */
176         char    d_padding4[8];  /* yet more padding */
177 };
178
179 /*
180  * Following flags are used to specify which fields are valid
181  */
182 #define IIF_BGRACE      1
183 #define IIF_IGRACE      2
184 #define IIF_FLAGS       4
185
186 #include "xlat/if_dqinfo_valid.h"
187
188 struct if_dqinfo
189 {
190         u_int64_t dqi_bgrace;
191         u_int64_t dqi_igrace;
192         u_int32_t dqi_flags;
193         u_int32_t dqi_valid;
194 };
195
196 struct v2_dqinfo
197 {
198         unsigned int dqi_bgrace;
199         unsigned int dqi_igrace;
200         unsigned int dqi_flags;
201         unsigned int dqi_blocks;
202         unsigned int dqi_free_blk;
203         unsigned int dqi_free_entry;
204 };
205
206 struct v1_dqstats
207 {
208         u_int32_t lookups;
209         u_int32_t drops;
210         u_int32_t reads;
211         u_int32_t writes;
212         u_int32_t cache_hits;
213         u_int32_t allocated_dquots;
214         u_int32_t free_dquots;
215         u_int32_t syncs;
216 };
217
218 struct v2_dqstats
219 {
220         u_int32_t lookups;
221         u_int32_t drops;
222         u_int32_t reads;
223         u_int32_t writes;
224         u_int32_t cache_hits;
225         u_int32_t allocated_dquots;
226         u_int32_t free_dquots;
227         u_int32_t syncs;
228         u_int32_t version;
229 };
230
231 typedef struct fs_qfilestat
232 {
233         u_int64_t qfs_ino;      /* inode number */
234         u_int64_t qfs_nblks;    /* number of BBs 512-byte-blks */
235         u_int32_t qfs_nextents; /* number of extents */
236 } fs_qfilestat_t;
237
238 struct xfs_dqstats
239 {
240         int8_t  qs_version;     /* version number for future changes */
241         u_int16_t qs_flags;     /* XFS_QUOTA_{U,P,G}DQ_{ACCT,ENFD} */
242         int8_t  qs_pad;         /* unused */
243         fs_qfilestat_t qs_uquota;       /* user quota storage information */
244         fs_qfilestat_t qs_gquota;       /* group quota storage information */
245         u_int32_t qs_incoredqs; /* number of dquots incore */
246         int32_t qs_btimelimit;  /* limit for blks timer */
247         int32_t qs_itimelimit;  /* limit for inodes timer */
248         int32_t qs_rtbtimelimit;        /* limit for rt blks timer */
249         u_int16_t qs_bwarnlimit;        /* limit for num warnings */
250         u_int16_t qs_iwarnlimit;        /* limit for num warnings */
251 };
252
253 static void
254 decode_cmd_data(struct tcb *tcp, u_int32_t cmd, unsigned long data)
255 {
256         switch (cmd) {
257                 case Q_GETQUOTA:
258                 case Q_SETQUOTA:
259                 {
260                         struct if_dqblk dq;
261
262                         if (umove_or_printaddr(tcp, data, &dq))
263                                 break;
264                         tprintf("{bhardlimit=%" PRIu64 ", ", dq.dqb_bhardlimit);
265                         tprintf("bsoftlimit=%" PRIu64 ", ", dq.dqb_bsoftlimit);
266                         tprintf("curspace=%" PRIu64 ", ", dq.dqb_curspace);
267                         tprintf("ihardlimit=%" PRIu64 ", ", dq.dqb_ihardlimit);
268                         tprintf("isoftlimit=%" PRIu64 ", ", dq.dqb_isoftlimit);
269                         tprintf("curinodes=%" PRIu64 ", ", dq.dqb_curinodes);
270                         if (!abbrev(tcp)) {
271                                 tprintf("btime=%" PRIu64 ", ", dq.dqb_btime);
272                                 tprintf("itime=%" PRIu64 ", ", dq.dqb_itime);
273                                 tprints("valid=");
274                                 printflags(if_dqblk_valid,
275                                            dq.dqb_valid, "QIF_???");
276                                 tprints("}");
277                         } else
278                                 tprints("...}");
279                         break;
280                 }
281                 case Q_V1_GETQUOTA:
282                 case Q_V1_SETQUOTA:
283                 {
284                         struct v1_dqblk dq;
285
286                         if (umove_or_printaddr(tcp, data, &dq))
287                                 break;
288                         tprintf("{bhardlimit=%u, ", dq.dqb_bhardlimit);
289                         tprintf("bsoftlimit=%u, ", dq.dqb_bsoftlimit);
290                         tprintf("curblocks=%u, ", dq.dqb_curblocks);
291                         tprintf("ihardlimit=%u, ", dq.dqb_ihardlimit);
292                         tprintf("isoftlimit=%u, ", dq.dqb_isoftlimit);
293                         tprintf("curinodes=%u, ", dq.dqb_curinodes);
294                         tprintf("btime=%lu, ", (long) dq.dqb_btime);
295                         tprintf("itime=%lu}", (long) dq.dqb_itime);
296                         break;
297                 }
298                 case Q_V2_GETQUOTA:
299                 case Q_V2_SETQUOTA:
300                 {
301                         struct v2_dqblk dq;
302
303                         if (umove_or_printaddr(tcp, data, &dq))
304                                 break;
305                         tprintf("{ihardlimit=%u, ", dq.dqb_ihardlimit);
306                         tprintf("isoftlimit=%u, ", dq.dqb_isoftlimit);
307                         tprintf("curinodes=%u, ", dq.dqb_curinodes);
308                         tprintf("bhardlimit=%u, ", dq.dqb_bhardlimit);
309                         tprintf("bsoftlimit=%u, ", dq.dqb_bsoftlimit);
310                         tprintf("curspace=%" PRIu64 ", ", dq.dqb_curspace);
311                         tprintf("btime=%lu, ", (long) dq.dqb_btime);
312                         tprintf("itime=%lu}", (long) dq.dqb_itime);
313                         break;
314                 }
315                 case Q_XGETQUOTA:
316                 case Q_XSETQLIM:
317                 {
318                         struct xfs_dqblk dq;
319
320                         if (umove_or_printaddr(tcp, data, &dq))
321                                 break;
322                         tprintf("{version=%d, ", dq.d_version);
323                         tprints("flags=");
324                         printflags(xfs_dqblk_flags,
325                                    dq.d_flags, "XFS_???_QUOTA");
326                         tprintf(", fieldmask=%#x, ", dq.d_fieldmask);
327                         tprintf("id=%u, ", dq.d_id);
328                         tprintf("blk_hardlimit=%" PRIu64 ", ", dq.d_blk_hardlimit);
329                         tprintf("blk_softlimit=%" PRIu64 ", ", dq.d_blk_softlimit);
330                         tprintf("ino_hardlimit=%" PRIu64 ", ", dq.d_ino_hardlimit);
331                         tprintf("ino_softlimit=%" PRIu64 ", ", dq.d_ino_softlimit);
332                         tprintf("bcount=%" PRIu64 ", ", dq.d_bcount);
333                         tprintf("icount=%" PRIu64 ", ", dq.d_icount);
334                         if (!abbrev(tcp)) {
335                                 tprintf("itimer=%d, ", dq.d_itimer);
336                                 tprintf("btimer=%d, ", dq.d_btimer);
337                                 tprintf("iwarns=%u, ", dq.d_iwarns);
338                                 tprintf("bwarns=%u, ", dq.d_bwarns);
339                                 tprintf("rtbcount=%" PRIu64 ", ", dq.d_rtbcount);
340                                 tprintf("rtbtimer=%d, ", dq.d_rtbtimer);
341                                 tprintf("rtbwarns=%u}", dq.d_rtbwarns);
342                         } else
343                                 tprints("...}");
344                         break;
345                 }
346                 case Q_GETFMT:
347                 {
348                         u_int32_t fmt;
349
350                         if (umove_or_printaddr(tcp, data, &fmt))
351                                 break;
352                         tprints("{");
353                         printxval(quota_formats, fmt, "QFMT_VFS_???");
354                         tprints("}");
355                         break;
356                 }
357                 case Q_GETINFO:
358                 case Q_SETINFO:
359                 {
360                         struct if_dqinfo dq;
361
362                         if (umove_or_printaddr(tcp, data, &dq))
363                                 break;
364                         tprintf("{bgrace=%" PRIu64 ", ", dq.dqi_bgrace);
365                         tprintf("igrace=%" PRIu64 ", ", dq.dqi_igrace);
366                         tprintf("flags=%#x, ", dq.dqi_flags);
367                         tprints("valid=");
368                         printflags(if_dqinfo_valid, dq.dqi_valid, "IIF_???");
369                         tprints("}");
370                         break;
371                 }
372                 case Q_V2_GETINFO:
373                 case Q_V2_SETINFO:
374                 {
375                         struct v2_dqinfo dq;
376
377                         if (umove_or_printaddr(tcp, data, &dq))
378                                 break;
379                         tprintf("{bgrace=%u, ", dq.dqi_bgrace);
380                         tprintf("igrace=%u, ", dq.dqi_igrace);
381                         tprintf("flags=%#x, ", dq.dqi_flags);
382                         tprintf("blocks=%u, ", dq.dqi_blocks);
383                         tprintf("free_blk=%u, ", dq.dqi_free_blk);
384                         tprintf("free_entry=%u}", dq.dqi_free_entry);
385                         break;
386                 }
387                 case Q_V1_GETSTATS:
388                 {
389                         struct v1_dqstats dq;
390
391                         if (umove_or_printaddr(tcp, data, &dq))
392                                 break;
393                         tprintf("{lookups=%u, ", dq.lookups);
394                         tprintf("drops=%u, ", dq.drops);
395                         tprintf("reads=%u, ", dq.reads);
396                         tprintf("writes=%u, ", dq.writes);
397                         tprintf("cache_hits=%u, ", dq.cache_hits);
398                         tprintf("allocated_dquots=%u, ", dq.allocated_dquots);
399                         tprintf("free_dquots=%u, ", dq.free_dquots);
400                         tprintf("syncs=%u}", dq.syncs);
401                         break;
402                 }
403                 case Q_V2_GETSTATS:
404                 {
405                         struct v2_dqstats dq;
406
407                         if (umove_or_printaddr(tcp, data, &dq))
408                                 break;
409                         tprintf("{lookups=%u, ", dq.lookups);
410                         tprintf("drops=%u, ", dq.drops);
411                         tprintf("reads=%u, ", dq.reads);
412                         tprintf("writes=%u, ", dq.writes);
413                         tprintf("cache_hits=%u, ", dq.cache_hits);
414                         tprintf("allocated_dquots=%u, ", dq.allocated_dquots);
415                         tprintf("free_dquots=%u, ", dq.free_dquots);
416                         tprintf("syncs=%u, ", dq.syncs);
417                         tprintf("version=%u}", dq.version);
418                         break;
419                 }
420                 case Q_XGETQSTAT:
421                 {
422                         struct xfs_dqstats dq;
423
424                         if (umove_or_printaddr(tcp, data, &dq))
425                                 break;
426                         tprintf("{version=%d, ", dq.qs_version);
427                         if (abbrev(tcp)) {
428                                 tprints("...}");
429                                 break;
430                         }
431                         tprints("flags=");
432                         printflags(xfs_quota_flags,
433                                    dq.qs_flags, "XFS_QUOTA_???");
434                         tprintf(", incoredqs=%u, ", dq.qs_incoredqs);
435                         tprintf("u_ino=%" PRIu64 ", ", dq.qs_uquota.qfs_ino);
436                         tprintf("u_nblks=%" PRIu64 ", ", dq.qs_uquota.qfs_nblks);
437                         tprintf("u_nextents=%u, ", dq.qs_uquota.qfs_nextents);
438                         tprintf("g_ino=%" PRIu64 ", ", dq.qs_gquota.qfs_ino);
439                         tprintf("g_nblks=%" PRIu64 ", ", dq.qs_gquota.qfs_nblks);
440                         tprintf("g_nextents=%u, ", dq.qs_gquota.qfs_nextents);
441                         tprintf("btimelimit=%d, ", dq.qs_btimelimit);
442                         tprintf("itimelimit=%d, ", dq.qs_itimelimit);
443                         tprintf("rtbtimelimit=%d, ", dq.qs_rtbtimelimit);
444                         tprintf("bwarnlimit=%u, ", dq.qs_bwarnlimit);
445                         tprintf("iwarnlimit=%u}", dq.qs_iwarnlimit);
446                         break;
447                 }
448                 case Q_XQUOTAON:
449                 {
450                         u_int32_t flag;
451
452                         if (umove_or_printaddr(tcp, data, &flag))
453                                 break;
454                         tprints("{");
455                         printflags(xfs_quota_flags, flag, "XFS_QUOTA_???");
456                         tprints("}");
457                         break;
458                 }
459                 default:
460                         printaddr(data);
461                         break;
462         }
463 }
464
465 SYS_FUNC(quotactl)
466 {
467         /*
468          * The Linux kernel only looks at the low 32 bits of command and id
469          * arguments, but on some 64-bit architectures (s390x) this word
470          * will have been sign-extended when we see it.  The high 1 bits
471          * don't mean anything, so don't confuse the output with them.
472          */
473         u_int32_t qcmd = tcp->u_arg[0];
474         u_int32_t cmd = QCMD_CMD(qcmd);
475         u_int32_t type = QCMD_TYPE(qcmd);
476         u_int32_t id = tcp->u_arg[2];
477
478         if (entering(tcp)) {
479                 printxval(quotacmds, cmd, "Q_???");
480                 tprints("|");
481                 printxval(quotatypes, type, "???QUOTA");
482                 tprints(", ");
483                 printpath(tcp, tcp->u_arg[1]);
484                 tprints(", ");
485                 switch (cmd) {
486                         case Q_V1_QUOTAON:
487                         case Q_QUOTAON:
488                                 printxval(quota_formats, id, "QFMT_VFS_???");
489                                 break;
490                         case Q_V1_GETQUOTA:
491                         case Q_V2_GETQUOTA:
492                         case Q_GETQUOTA:
493                         case Q_XGETQUOTA:
494                                 tprintf("%u", id);
495                                 break;
496                         case Q_SETQLIM:
497                         case Q_SETQUOTA:
498                         case Q_V1_SETQUOTA:
499                         case Q_V1_SETUSE:
500                         case Q_V2_SETQUOTA:
501                         case Q_V2_SETUSE:
502                         case Q_XSETQLIM:
503                                 tprintf("%u, ", id);
504                         case Q_SETINFO:
505                         case Q_V2_SETFLAGS:
506                         case Q_V2_SETGRACE:
507                         case Q_V2_SETINFO:
508                                 decode_cmd_data(tcp, cmd, tcp->u_arg[3]);
509                                 return RVAL_DECODED;
510                                 break;
511                         default:
512                                 printaddr(tcp->u_arg[2]);
513                                 break;
514                 }
515                 tprints(", ");
516         } else {
517                 decode_cmd_data(tcp, cmd, tcp->u_arg[3]);
518         }
519         return 0;
520 }