Update NEWS for 1.6.22
[pkg-k5-afs_openafs.git] / src / vol / salvager.c
blobe49747ce79504ff4a3b00558403d61335420bef7
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
8 */
11 * System: VICE-TWO
12 * Module: salvager.c
13 * Institution: The Information Technology Center, Carnegie-Mellon University
17 /* Main program file. Define globals. */
18 #define MAIN 1
20 #include <afsconfig.h>
21 #include <afs/param.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <dirent.h>
28 #include <sys/stat.h>
29 #include <time.h>
30 #include <errno.h>
31 #ifdef AFS_NT40_ENV
32 #include <io.h>
33 #include <WINNT/afsevent.h>
34 #else
35 #include <sys/param.h>
36 #include <sys/file.h>
37 #ifndef ITIMER_REAL
38 #include <sys/time.h>
39 #endif /* ITIMER_REAL */
40 #endif
41 #ifndef WCOREDUMP
42 #define WCOREDUMP(x) ((x) & 0200)
43 #endif
44 #include <rx/xdr.h>
45 #include <afs/afsint.h>
46 #include <afs/afs_assert.h>
47 #if !defined(AFS_SGI_ENV) && !defined(AFS_NT40_ENV)
48 #if defined(AFS_VFSINCL_ENV)
49 #include <sys/vnode.h>
50 #ifdef AFS_SUN5_ENV
51 #include <sys/fs/ufs_inode.h>
52 #else
53 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
54 #include <ufs/ufs/dinode.h>
55 #include <ufs/ffs/fs.h>
56 #else
57 #include <ufs/inode.h>
58 #endif
59 #endif
60 #else /* AFS_VFSINCL_ENV */
61 #ifdef AFS_OSF_ENV
62 #include <ufs/inode.h>
63 #else /* AFS_OSF_ENV */
64 #if !defined(AFS_LINUX20_ENV) && !defined(AFS_XBSD_ENV) && !defined(AFS_DARWIN_ENV)
65 #include <sys/inode.h>
66 #endif
67 #endif
68 #endif /* AFS_VFSINCL_ENV */
69 #endif /* AFS_SGI_ENV */
70 #ifdef AFS_AIX_ENV
71 #include <sys/vfs.h>
72 #include <sys/lockf.h>
73 #else
74 #ifdef AFS_HPUX_ENV
75 #include <unistd.h>
76 #include <checklist.h>
77 #else
78 #if defined(AFS_SGI_ENV)
79 #include <unistd.h>
80 #include <fcntl.h>
81 #include <mntent.h>
82 #else
83 #if defined(AFS_SUN_ENV) || defined(AFS_SUN5_ENV)
84 #ifdef AFS_SUN5_ENV
85 #include <unistd.h>
86 #include <sys/mnttab.h>
87 #include <sys/mntent.h>
88 #else
89 #include <mntent.h>
90 #endif
91 #else
92 #endif /* AFS_SGI_ENV */
93 #endif /* AFS_HPUX_ENV */
94 #endif
95 #endif
96 #include <fcntl.h>
97 #ifndef AFS_NT40_ENV
98 #include <afs/osi_inode.h>
99 #endif
100 #include <afs/cmd.h>
101 #include <afs/dir.h>
102 #include <afs/afsutil.h>
103 #include <afs/fileutil.h>
104 #include <afs/procmgmt.h> /* signal(), kill(), wait(), etc. */
105 #ifndef AFS_NT40_ENV
106 #include <syslog.h>
107 #endif
109 #include "nfs.h"
110 #include "lwp.h"
111 #include "lock.h"
112 #include <afs/afssyscalls.h>
113 #include "ihandle.h"
114 #include "vnode.h"
115 #include "volume.h"
116 #include "partition.h"
117 #include "daemon_com.h"
118 #include "fssync.h"
119 #include "salvsync.h"
120 #include "viceinode.h"
121 #include "salvage.h"
122 #include "vol-salvage.h"
123 #include "common.h"
124 #ifdef AFS_NT40_ENV
125 #include <pthread.h>
126 pthread_t main_thread;
127 #endif
129 static int get_salvage_lock = 0;
131 static int
132 handleit(struct cmd_syndesc *as, void *arock)
134 struct cmd_item *ti;
135 char pname[100], *temp;
136 afs_int32 seenpart = 0, seenvol = 0;
137 VolumeId vid = 0;
138 ProgramType pt;
140 #ifdef FAST_RESTART
141 afs_int32 seenany = 0;
142 #endif
144 VolumePackageOptions opts;
145 struct DiskPartition64 *partP;
147 #ifdef AFS_SGI_VNODE_GLUE
148 if (afs_init_kernel_config(-1) < 0) {
149 printf
150 ("Can't determine NUMA configuration, not starting salvager.\n");
151 exit(1);
153 #endif
155 #ifdef FAST_RESTART
157 afs_int32 i;
158 for (i = 0; i < CMD_MAXPARMS; i++) {
159 if (as->parms[i].items) {
160 seenany = 1;
161 break;
165 if (!seenany) {
166 char *msg =
167 "Exiting immediately without salvage. Look into the FileLog to find volumes which really need to be salvaged!";
169 #ifndef AFS_NT40_ENV
170 if (useSyslog)
171 Log(msg);
172 else
173 #endif
174 printf("%s\n", msg);
176 Exit(0);
178 #endif /* FAST_RESTART */
179 if ((ti = as->parms[0].items)) { /* -partition */
180 seenpart = 1;
181 strncpy(pname, ti->data, 100);
183 if ((ti = as->parms[1].items)) { /* -volumeid */
184 char *end;
185 unsigned long vid_l;
186 if (!seenpart) {
187 printf
188 ("You must also specify '-partition' option with the '-volumeid' option\n");
189 exit(-1);
191 seenvol = 1;
192 vid_l = strtoul(ti->data, &end, 10);
193 if (vid_l >= MAX_AFS_UINT32 || vid_l == ULONG_MAX || *end != '\0') {
194 Log("salvage: invalid volume id specified; salvage aborted\n");
195 Exit(1);
197 vid = (VolumeId)vid_l;
199 if (as->parms[2].items) /* -debug */
200 debug = 1;
201 if (as->parms[3].items) /* -nowrite */
202 Testing = 1;
203 if (as->parms[4].items) /* -inodes */
204 ListInodeOption = 1;
205 if (as->parms[5].items || as->parms[21].items) /* -force, -f */
206 ForceSalvage = 1;
207 if (as->parms[6].items) /* -oktozap */
208 OKToZap = 1;
209 if (as->parms[7].items) /* -rootinodes */
210 ShowRootFiles = 1;
211 if (as->parms[8].items) /* -RebuildDirs */
212 RebuildDirs = 1;
213 if (as->parms[9].items) /* -ForceReads */
214 forceR = 1;
215 if ((ti = as->parms[10].items)) { /* -Parallel # */
216 temp = ti->data;
217 if (strncmp(temp, "all", 3) == 0) {
218 PartsPerDisk = 1;
219 temp += 3;
221 if (strlen(temp) != 0) {
222 Parallel = atoi(temp);
223 if (Parallel < 1)
224 Parallel = 1;
225 if (Parallel > MAXPARALLEL) {
226 printf("Setting parallel salvages to maximum of %d \n",
227 MAXPARALLEL);
228 Parallel = MAXPARALLEL;
232 if ((ti = as->parms[11].items)) { /* -tmpdir */
233 DIR *dirp;
235 tmpdir = ti->data;
236 dirp = opendir(tmpdir);
237 if (!dirp) {
238 printf
239 ("Can't open temporary placeholder dir %s; using current partition \n",
240 tmpdir);
241 tmpdir = NULL;
242 } else
243 closedir(dirp);
245 if ((ti = as->parms[12].items)) /* -showlog */
246 ShowLog = 1;
247 if ((ti = as->parms[13].items)) { /* -showsuid */
248 Testing = 1;
249 ShowSuid = 1;
250 Showmode = 1;
252 if ((ti = as->parms[14].items)) { /* -showmounts */
253 Testing = 1;
254 Showmode = 1;
255 ShowMounts = 1;
257 if ((ti = as->parms[15].items)) { /* -orphans */
258 if (Testing)
259 orphans = ORPH_IGNORE;
260 else if (strcmp(ti->data, "remove") == 0
261 || strcmp(ti->data, "r") == 0)
262 orphans = ORPH_REMOVE;
263 else if (strcmp(ti->data, "attach") == 0
264 || strcmp(ti->data, "a") == 0)
265 orphans = ORPH_ATTACH;
267 #ifndef AFS_NT40_ENV /* ignore options on NT */
268 if ((ti = as->parms[16].items)) { /* -syslog */
269 useSyslog = 1;
270 ShowLog = 0;
272 if ((ti = as->parms[17].items)) { /* -syslogfacility */
273 useSyslogFacility = atoi(ti->data);
276 if ((ti = as->parms[18].items)) { /* -datelogs */
277 TimeStampLogFile((char *)AFSDIR_SERVER_SLVGLOG_FILEPATH);
279 #endif
281 #ifdef FAST_RESTART
282 if (ti = as->parms[19].items) { /* -DontSalvage */
283 char *msg =
284 "Exiting immediately without salvage. Look into the FileLog to find volumes which really need to be salvaged!";
286 #ifndef AFS_NT40_ENV
287 if (useSyslog)
288 Log(msg);
289 else
290 #endif
291 printf("%s\n", msg);
292 Exit(0);
294 #endif
296 /* Note: if seenvol we initialize this as a standard volume utility: this has the
297 * implication that the file server may be running; negotations have to be made with
298 * the file server in this case to take the read write volume and associated read-only
299 * volumes off line before salvaging */
300 #ifdef AFS_NT40_ENV
301 if (seenvol) {
302 if (afs_winsockInit() < 0) {
303 ReportErrorEventAlt(AFSEVT_SVR_WINSOCK_INIT_FAILED, 0,
304 AFSDIR_SALVAGER_FILE, 0);
305 Log("Failed to initailize winsock, exiting.\n");
306 Exit(1);
309 #endif
311 if (seenvol) {
312 pt = volumeSalvager;
313 } else {
314 pt = salvager;
317 VOptDefaults(pt, &opts);
318 if (VInitVolumePackage2(pt, &opts)) {
319 Log("errors encountered initializing volume package; salvage aborted\n");
320 Exit(1);
323 /* defer lock until we init volume package */
324 if (get_salvage_lock) {
325 if (seenvol && AskDAFS()) /* support forceDAFS */
326 ObtainSharedSalvageLock();
327 else
328 ObtainSalvageLock();
332 * Ok to defer this as Exit will clean up and no real work is done
333 * init'ing volume package
335 if (seenvol) {
336 char *msg = NULL;
337 #ifdef AFS_DEMAND_ATTACH_FS
338 if (!AskDAFS()) {
339 msg =
340 "The DAFS dasalvager cannot be run with a non-DAFS fileserver. Please use 'salvager'.";
342 if (!msg && !as->parms[20].items) {
343 msg =
344 "The standalone salvager cannot be run concurrently with a Demand Attach Fileserver. Please use 'salvageserver -client <partition> <volume id>' to manually schedule volume salvages with the salvageserver (new versions of 'bos salvage' automatically do this for you). Or, if you insist on using the standalone salvager, add the -forceDAFS flag to your salvager command line.";
346 #else
347 if (AskDAFS()) {
348 msg =
349 "The non-DAFS salvager cannot be run with a Demand Attach Fileserver. Please use 'salvageserver -client <partition> <volume id>' to manually schedule volume salvages with the salvageserver (new versions of 'bos salvage' automatically do this for you). Or, if you insist on using the standalone salvager, run dasalvager with the -forceDAFS flag.";
351 #endif
353 if (msg) {
354 #ifndef AFS_NT40_ENV
355 if (useSyslog)
356 Log("%s", msg);
357 else
358 #endif
359 printf("%s\n", msg);
360 Exit(1);
364 DInit(10);
365 #ifdef AFS_NT40_ENV
366 if (myjob.cj_number != NOT_CHILD) {
367 if (!seenpart) {
368 seenpart = 1;
369 (void)strcpy(pname, myjob.cj_part);
372 #endif
373 if (seenpart == 0) {
374 for (partP = DiskPartitionList; partP; partP = partP->next) {
375 SalvageFileSysParallel(partP);
377 SalvageFileSysParallel(0);
378 } else {
379 partP = VGetPartition(pname, 0);
380 if (!partP) {
381 Log("salvage: Unknown or unmounted partition %s; salvage aborted\n", pname);
382 Exit(1);
384 if (!seenvol)
385 SalvageFileSys(partP, 0);
386 else {
387 /* Salvage individual volume */
388 SalvageFileSys(partP, vid);
391 return (0);
395 #ifndef AFS_NT40_ENV
396 #include "AFS_component_version_number.c"
397 #endif
400 main(int argc, char **argv)
402 struct cmd_syndesc *ts;
403 int err = 0;
405 extern char cml_version_number[];
407 #ifdef AFS_AIX32_ENV
409 * The following signal action for AIX is necessary so that in case of a
410 * crash (i.e. core is generated) we can include the user's data section
411 * in the core dump. Unfortunately, by default, only a partial core is
412 * generated which, in many cases, isn't too useful.
414 struct sigaction nsa;
416 sigemptyset(&nsa.sa_mask);
417 nsa.sa_handler = SIG_DFL;
418 nsa.sa_flags = SA_FULLDUMP;
419 sigaction(SIGABRT, &nsa, NULL);
420 sigaction(SIGSEGV, &nsa, NULL);
421 #endif
423 /* Initialize directory paths */
424 if (!(initAFSDirPath() & AFSDIR_SERVER_PATHS_OK)) {
425 #ifdef AFS_NT40_ENV
426 ReportErrorEventAlt(AFSEVT_SVR_NO_INSTALL_DIR, 0, argv[0], 0);
427 #endif
428 fprintf(stderr, "%s: Unable to obtain AFS server directory.\n",
429 argv[0]);
430 exit(2);
432 #ifdef AFS_NT40_ENV
433 /* Default to binary mode for fopen() */
434 _set_fmode(_O_BINARY);
436 main_thread = pthread_self();
437 if (spawnDatap && spawnDataLen) {
438 /* This is a child per partition salvager. Don't setup log or
439 * try to lock the salvager lock.
441 if (nt_SetupPartitionSalvage(spawnDatap, spawnDataLen) < 0)
442 exit(3);
443 } else {
444 #endif
445 /* All entries to the log will be appended. Useful if there are
446 * multiple salvagers appending to the log.
449 CheckLogFile((char *)AFSDIR_SERVER_SLVGLOG_FILEPATH);
450 #ifndef AFS_NT40_ENV
451 #ifdef AFS_LINUX20_ENV
452 fcntl(fileno(logFile), F_SETFL, O_APPEND); /* Isn't this redundant? */
453 #else
454 fcntl(fileno(logFile), F_SETFL, FAPPEND); /* Isn't this redundant? */
455 #endif
456 #endif
457 setlinebuf(logFile);
459 #ifndef AFS_NT40_ENV
460 if (geteuid() != 0) {
461 printf("Salvager must be run as root.\n");
462 fflush(stdout);
463 Exit(0);
465 #endif
467 /* bad for normal help flag processing, but can do nada */
469 fprintf(logFile, "%s\n", cml_version_number);
470 LogCommandLine(argc, argv, "SALVAGER", SalvageVersion, "STARTING AFS",
471 Log);
473 /* Get and hold a lock for the duration of the salvage to make sure
474 * that no other salvage runs at the same time. The routine
475 * VInitVolumePackage2 (called below) makes sure that a file server or
476 * other volume utilities don't interfere with the salvage.
478 get_salvage_lock = 1;
479 #ifdef AFS_NT40_ENV
481 #endif
483 ts = cmd_CreateSyntax("initcmd", handleit, NULL, "initialize the program");
484 cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL,
485 "Name of partition to salvage");
486 cmd_AddParm(ts, "-volumeid", CMD_SINGLE, CMD_OPTIONAL,
487 "Volume Id to salvage");
488 cmd_AddParm(ts, "-debug", CMD_FLAG, CMD_OPTIONAL,
489 "Run in Debugging mode");
490 cmd_AddParm(ts, "-nowrite", CMD_FLAG, CMD_OPTIONAL,
491 "Run readonly/test mode");
492 cmd_AddParm(ts, "-inodes", CMD_FLAG, CMD_OPTIONAL,
493 "Just list affected afs inodes - debugging flag");
494 cmd_AddParm(ts, "-force", CMD_FLAG, CMD_OPTIONAL, "Force full salvaging");
495 cmd_AddParm(ts, "-oktozap", CMD_FLAG, CMD_OPTIONAL,
496 "Give permission to destroy bogus inodes/volumes - debugging flag");
497 cmd_AddParm(ts, "-rootinodes", CMD_FLAG, CMD_OPTIONAL,
498 "Show inodes owned by root - debugging flag");
499 cmd_AddParm(ts, "-salvagedirs", CMD_FLAG, CMD_OPTIONAL,
500 "Force rebuild/salvage of all directories");
501 cmd_AddParm(ts, "-blockreads", CMD_FLAG, CMD_OPTIONAL,
502 "Read smaller blocks to handle IO/bad blocks");
503 cmd_AddParm(ts, "-parallel", CMD_SINGLE, CMD_OPTIONAL,
504 "# of max parallel partition salvaging");
505 cmd_AddParm(ts, "-tmpdir", CMD_SINGLE, CMD_OPTIONAL,
506 "Name of dir to place tmp files ");
507 cmd_AddParm(ts, "-showlog", CMD_FLAG, CMD_OPTIONAL,
508 "Show log file upon completion");
509 cmd_AddParm(ts, "-showsuid", CMD_FLAG, CMD_OPTIONAL,
510 "Report on suid/sgid files");
511 cmd_AddParm(ts, "-showmounts", CMD_FLAG, CMD_OPTIONAL,
512 "Report on mountpoints");
513 cmd_AddParm(ts, "-orphans", CMD_SINGLE, CMD_OPTIONAL,
514 "ignore | remove | attach");
516 /* note - syslog isn't avail on NT, but if we make it conditional, have
517 * to deal with screwy offsets for cmd params */
518 cmd_AddParm(ts, "-syslog", CMD_FLAG, CMD_OPTIONAL,
519 "Write salvage log to syslogs");
520 cmd_AddParm(ts, "-syslogfacility", CMD_SINGLE, CMD_OPTIONAL,
521 "Syslog facility number to use");
522 cmd_AddParm(ts, "-datelogs", CMD_FLAG, CMD_OPTIONAL,
523 "Include timestamp in logfile filename");
524 #ifdef FAST_RESTART
525 cmd_AddParm(ts, "-DontSalvage", CMD_FLAG, CMD_OPTIONAL,
526 "Don't salvage. This my be set in BosConfig to let the fileserver restart immediately after a crash. Bad volumes will be taken offline");
527 #elif defined(AFS_DEMAND_ATTACH_FS)
528 cmd_Seek(ts, 20); /* skip DontSalvage */
529 cmd_AddParm(ts, "-forceDAFS", CMD_FLAG, CMD_OPTIONAL,
530 "For Demand Attach Fileserver, permit a manual volume salvage outside of the salvageserver");
531 #endif /* FAST_RESTART */
532 cmd_Seek(ts, 21); /* skip DontSalvage and forceDAFS if needed */
533 cmd_AddParm(ts, "-f", CMD_FLAG, CMD_OPTIONAL, "Alias for -force");
534 err = cmd_Dispatch(argc, argv);
535 Exit(err);
536 return 0; /* not reached */