50311ef63a08f00ebd50b3410675a679c3ed3758
[openafs.git] / src / vol / volscan-main.c
1 /*
2  * Copyright 2013-2014, Sine Nomine Associates
3  * All Rights Reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
17  * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include <afsconfig.h>
30 #include <afs/param.h>
31
32 #include <roken.h>
33 #include <ctype.h>
34 #include <afs/cmd.h>
35 #include <afs/afsint.h>
36 #include <rx/rx_queue.h>
37 #include "nfs.h"
38 #include "ihandle.h"
39 #include "lock.h"
40 #include "vnode.h"  /* for vSmall, vLarge */
41 #include "vol-info.h"
42
43 #ifndef AFS_NT40_ENV
44 #include "AFS_component_version_number.c"
45 #endif
46
47 static const char *progname = "volscan";
48
49 /* All columns names as a single string. */
50 #define c(x) #x " "
51 static char *ColumnNames = VOLSCAN_COLUMNS;
52 #undef c
53 #undef VOLSCAN_COLUMNS
54
55 /* Command line options */
56 typedef enum {
57     P_CHECKOUT,
58     P_PART,
59     P_VOLUMEID,
60     P_TYPE,
61     P_FIND,
62     P_MASK,
63     P_OUTPUT,
64     P_DELIM,
65     P_NOHEADING,
66     P_NOMAGIC,
67 } volscan_parm_t;
68
69 /**
70  * Process command line options and start scanning
71  *
72  * @param[in] as     command syntax object
73  * @param[in] arock  opaque object; not used
74  *
75  * @return error code
76  *    @retval 0 success
77  *    @retvol 1 failure
78  */
79 static int
80 VolScan(struct cmd_syndesc *as, void *arock)
81 {
82     int code;
83     struct cmd_item *ti;
84     VolumeId volumeId = 0;
85     char *partNameOrId = NULL;
86     int i;
87     struct VolInfoOpt *opt;
88
89     code = volinfo_Init(progname);
90     if (code) {
91         return code;
92     }
93     code = volinfo_Options(&opt);
94     if (code) {
95         return code;
96     }
97
98     opt->dumpInfo = 0;          /* volscan mode */
99     if (as->parms[P_CHECKOUT].items) {
100         opt->checkout = 1;
101     }
102     if ((ti = as->parms[P_PART].items)) {
103         partNameOrId = ti->data;
104     }
105     if ((ti = as->parms[P_VOLUMEID].items)) {
106         volumeId = strtoul(ti->data, NULL, 10);
107     }
108     if (as->parms[P_NOHEADING].items) {
109         opt->printHeading = 0;
110     } else {
111         opt->printHeading = 1;
112     }
113     if (as->parms[P_NOMAGIC].items) {
114         opt->checkMagic = 0;
115     }
116     if ((ti = as->parms[P_DELIM].items)) {
117         strncpy(opt->columnDelim, ti->data, 15);
118         opt->columnDelim[15] = '\0';
119     }
120
121     /* Limit types of volumes to scan. */
122     if (!as->parms[P_TYPE].items) {
123         opt->scanVolType = (SCAN_RW | SCAN_RO | SCAN_BK);
124     } else {
125         opt->scanVolType = 0;
126         for (ti = as->parms[P_TYPE].items; ti; ti = ti->next) {
127             if (strcmp(ti->data, "rw") == 0) {
128                 opt->scanVolType |= SCAN_RW;
129             } else if (strcmp(ti->data, "ro") == 0) {
130                 opt->scanVolType |= SCAN_RO;
131             } else if (strcmp(ti->data, "bk") == 0) {
132                 opt->scanVolType |= SCAN_BK;
133             } else {
134                 fprintf(stderr, "%s: Unknown -type value: %s\n", progname,
135                         ti->data);
136                 return 1;
137             }
138         }
139     }
140
141     /* Limit types of vnodes to find (plus access entries) */
142     if (!as->parms[P_FIND].items) {
143         opt->findVnType = (FIND_FILE | FIND_DIR | FIND_MOUNT | FIND_SYMLINK);
144     } else {
145         opt->findVnType = 0;
146         for (ti = as->parms[P_FIND].items; ti; ti = ti->next) {
147             if (strcmp(ti->data, "file") == 0) {
148                 opt->findVnType |= FIND_FILE;
149             } else if (strcmp(ti->data, "dir") == 0) {
150                 opt->findVnType |= FIND_DIR;
151             } else if (strcmp(ti->data, "mount") == 0) {
152                 opt->findVnType |= FIND_MOUNT;
153             } else if (strcmp(ti->data, "symlink") == 0) {
154                 opt->findVnType |= FIND_SYMLINK;
155             } else if (strcmp(ti->data, "acl") == 0) {
156                 opt->findVnType |= FIND_ACL;
157             } else {
158                 fprintf(stderr, "%s: Unknown -find value: %s\n", progname,
159                         ti->data);
160                 return 1;
161             }
162         }
163     }
164
165     /* Show vnodes matching one of the mode masks */
166     for (i = 0, ti = as->parms[P_MASK].items; ti; i++, ti = ti->next) {
167         if (i >= (sizeof(opt->modeMask) / sizeof(*opt->modeMask))) {
168             fprintf(stderr, "Too many -mask values\n");
169             return -1;
170         }
171         opt->modeMask[i] = strtol(ti->data, NULL, 8);
172         if (!opt->modeMask[i]) {
173             fprintf(stderr, "Invalid -mask value: %s\n", ti->data);
174             return 1;
175         }
176     }
177
178     /* Set which columns to be printed. */
179     if (!as->parms[P_OUTPUT].items) {
180         volinfo_AddOutputColumn("host");
181         volinfo_AddOutputColumn("desc");
182         volinfo_AddOutputColumn("fid");
183         volinfo_AddOutputColumn("dv");
184         if (opt->findVnType & FIND_ACL) {
185             volinfo_AddOutputColumn("aid");
186             volinfo_AddOutputColumn("arights");
187         }
188         volinfo_AddOutputColumn("path");
189     } else {
190         for (ti = as->parms[P_OUTPUT].items; ti; ti = ti->next) {
191             if (volinfo_AddOutputColumn(ti->data) != 0) {;
192                 fprintf(stderr, "%s: Unknown -output value: %s\n", progname,
193                         ti->data);
194                 return 1;
195             }
196         }
197     }
198
199     if (opt->findVnType & FIND_DIR) {
200         volinfo_AddVnodeHandler(vLarge, volinfo_PrintVnodeDetails, NULL);
201     }
202     if (opt->findVnType & (FIND_FILE | FIND_MOUNT | FIND_SYMLINK)) {
203         volinfo_AddVnodeHandler(vSmall, volinfo_PrintVnodeDetails, NULL);
204     }
205     if (opt->findVnType & FIND_ACL) {
206         volinfo_AddVnodeHandler(vLarge, volinfo_ScanAcl, NULL);
207     }
208
209     code = volinfo_ScanPartitions(opt, partNameOrId, volumeId);
210     if (opt) {
211         free(opt);
212     }
213     return code;
214 }
215 /**
216  * volscan program entry
217  */
218 int
219 main(int argc, char **argv)
220 {
221     afs_int32 code;
222     struct cmd_syndesc *ts;
223
224     ts = cmd_CreateSyntax(NULL, VolScan, NULL,
225                           "Print volume vnode information");
226
227     cmd_AddParmAtOffset(ts, P_CHECKOUT, "-checkout", CMD_FLAG, CMD_OPTIONAL,
228                         "Checkout volumes from running fileserver");
229     cmd_AddParmAtOffset(ts, P_PART, "-partition", CMD_SINGLE, CMD_OPTIONAL,
230                         "AFS partition name or id (default current partition)");
231     cmd_AddParmAtOffset(ts, P_VOLUMEID, "-volumeid", CMD_SINGLE, CMD_OPTIONAL,
232                         "Volume id (-partition required)");
233     cmd_AddParmAtOffset(ts, P_TYPE, "-type", CMD_LIST, CMD_OPTIONAL,
234                         "Volume types: rw, ro, bk");
235     cmd_AddParmAtOffset(ts, P_FIND, "-find", CMD_LIST, CMD_OPTIONAL,
236                         "Objects to find: file, dir, mount, symlink, acl");
237     cmd_AddParmAtOffset(ts, P_MASK, "-mask", CMD_LIST, CMD_OPTIONAL,
238                         "Unix mode mask (example: 06000)");
239     cmd_AddParmAtOffset(ts, P_OUTPUT, "-output", CMD_LIST, CMD_OPTIONAL,
240                         ColumnNames);
241     cmd_AddParmAtOffset(ts, P_DELIM, "-delim", CMD_SINGLE, CMD_OPTIONAL,
242                         "Output field delimiter");
243     cmd_AddParmAtOffset(ts, P_NOHEADING, "-noheading", CMD_FLAG, CMD_OPTIONAL,
244                         "Do not print the heading line");
245     cmd_AddParmAtOffset(ts, P_NOMAGIC, "-ignore-magic", CMD_FLAG, CMD_OPTIONAL,
246                         "Skip directory vnode magic checks when looking up paths.");
247
248     code = cmd_Dispatch(argc, argv);
249     return code;
250 }