vol: Windows requires binary fmode for salvaged
[openafs.git] / src / vol / salvaged.c
index 2a79027..b765f42 100644 (file)
@@ -1,13 +1,13 @@
 /*
  * Copyright 2006-2007, Sine Nomine Associates and others.
  * All Rights Reserved.
- * 
+ *
  * This software has been released under the terms of the IBM Public
  * License.  For details, see the LICENSE file in the top-level source
  * directory or online at http://www.openafs.org/dl/license10.html
  */
 
-/* 
+/*
  * demand attach fs
  * online salvager daemon
  */
@@ -18,6 +18,7 @@
 #include <afsconfig.h>
 #include <afs/param.h>
 
+#include <roken.h>
 
 #include <stdlib.h>
 #include <stdio.h>
 #include <sys/time.h>
 #endif /* ITIMER_REAL */
 #endif
-#if    defined(AFS_AIX_ENV) || defined(AFS_SUN4_ENV)
-#define WCOREDUMP(x)   (x & 0200)
+#ifndef WCOREDUMP
+#define WCOREDUMP(x)   ((x) & 0200)
 #endif
 #include <rx/xdr.h>
 #include <afs/afsint.h>
-#include <afs/assert.h>
+#include <afs/afs_assert.h>
 #if !defined(AFS_SGI_ENV) && !defined(AFS_NT40_ENV)
 #if defined(AFS_VFSINCL_ENV)
 #include <sys/vnode.h>
 #include "viceinode.h"
 #include "salvage.h"
 #include "vol-salvage.h"
+#include "common.h"
 #ifdef AFS_NT40_ENV
 #include <pthread.h>
 #endif
 #error "online salvager not supported on NT"
 #endif /* AFS_NT40_ENV */
 
-
-/* Forward declarations */
-/*@printflike@*/ void Log(const char *format, ...);
-/*@printflike@*/ void Abort(const char *format, ...);
-
-
 /*@+fcnmacros +macrofcndecl@*/
 #ifdef O_LARGEFILE
 #define afs_fopen      fopen64
@@ -155,7 +151,7 @@ static pthread_cond_t worker_cv;
 static void * SalvageChildReaperThread(void *);
 static int DoSalvageVolume(struct SalvageQueueNode * node, int slot);
 
-static void SalvageServer(void);
+static void SalvageServer(int argc, char **argv);
 static void SalvageClient(VolumeId vid, char * pname);
 
 static int Reap_Child(char * prog, int * pid, int * status);
@@ -166,6 +162,11 @@ static int SalvageLogCleanup(int pid);
 static void * SalvageLogScanningThread(void *);
 static void ScanLogs(struct rx_queue *log_watch_queue);
 
+struct cmdline_rock {
+    int argc;
+    char **argv;
+};
+
 struct log_cleanup_node {
     struct rx_queue q;
     int pid;
@@ -182,9 +183,10 @@ struct {
 static int
 handleit(struct cmd_syndesc *as, void *arock)
 {
-    register struct cmd_item *ti;
+    struct cmd_item *ti;
     char pname[100], *temp;
     afs_int32 seenpart = 0, seenvol = 0, vid = 0;
+    struct cmdline_rock *rock = (struct cmdline_rock *)arock;
 
 #ifdef AFS_SGI_VNODE_GLUE
     if (afs_init_kernel_config(-1) < 0) {
@@ -274,6 +276,11 @@ handleit(struct cmd_syndesc *as, void *arock)
            vid = atoi(ti->data);
        }
 
+       if (ShowLog) {
+           printf("-showlog does not work with -client\n");
+           exit(-1);
+       }
+
        if (!seenpart || !seenvol) {
            printf("You must specify '-partition' and '-volumeid' with the '-client' option\n");
            exit(-1);
@@ -282,7 +289,7 @@ handleit(struct cmd_syndesc *as, void *arock)
        SalvageClient(vid, pname);
 
     } else {  /* salvageserver mode */
-       SalvageServer();
+       SalvageServer(rock->argc, rock->argv);
     }
     return (0);
 }
@@ -298,20 +305,17 @@ int n_save_args = 0;
 pthread_t main_thread;
 #endif
 
-static char commandLine[150];
-
 int
 main(int argc, char **argv)
 {
     struct cmd_syndesc *ts;
     int err = 0;
-
-    int i;
+    struct cmdline_rock arock;
 
 #ifdef AFS_AIX32_ENV
     /*
-     * The following signal action for AIX is necessary so that in case of a 
-     * crash (i.e. core is generated) we can include the user's data section 
+     * The following signal action for AIX is necessary so that in case of a
+     * crash (i.e. core is generated) we can include the user's data section
      * in the core dump. Unfortunately, by default, only a partial core is
      * generated which, in many cases, isn't too useful.
      */
@@ -334,6 +338,9 @@ main(int argc, char **argv)
        exit(2);
     }
 #ifdef AFS_NT40_ENV
+    /* Default to binary mode for fopen() */
+    _set_fmode(_O_BINARY);
+
     main_thread = pthread_self();
     if (spawnDatap && spawnDataLen) {
        /* This is a child per partition salvager. Don't setup log or
@@ -343,11 +350,6 @@ main(int argc, char **argv)
            exit(3);
     } else {
 #endif
-       for (commandLine[0] = '\0', i = 0; i < argc; i++) {
-           if (i > 0)
-               strlcat(commandLine, " ", sizeof(commandLine));
-           strlcat(commandLine, argv[i], sizeof(commandLine));
-       }
 
 #ifndef AFS_NT40_ENV
        if (geteuid() != 0) {
@@ -363,7 +365,10 @@ main(int argc, char **argv)
     }
 #endif
 
-    ts = cmd_CreateSyntax("initcmd", handleit, NULL, "initialize the program");
+    arock.argc = argc;
+    arock.argv = argv;
+
+    ts = cmd_CreateSyntax("initcmd", handleit, &arock, "initialize the program");
     cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL,
                "Name of partition to salvage");
     cmd_AddParm(ts, "-volumeid", CMD_SINGLE, CMD_OPTIONAL,
@@ -415,10 +420,18 @@ SalvageClient(VolumeId vid, char * pname)
     afs_int32 code;
     SYNC_response res;
     SALVSYNC_response_hdr sres;
-
-    VInitVolumePackage(volumeUtility, 5, 5, DONT_CONNECT_FS, 0);
+    VolumePackageOptions opts;
+
+    VOptDefaults(volumeUtility, &opts);
+    if (VInitVolumePackage2(volumeUtility, &opts)) {
+       /* VInitVolumePackage2 can fail on e.g. partition attachment errors,
+        * but we don't really care, since all we're doing is trying to use
+        * SALVSYNC */
+       fprintf(stderr, "errors encountered initializing volume package, but "
+                       "trying to continue anyway\n");
+    }
     SALVSYNC_clientInit();
-    
+
     code = SALVSYNC_SalvageVolume(vid, pname, SALVSYNC_SALVAGE, SALVSYNC_OPERATOR, 0, NULL);
     if (code != SYNC_OK) {
        goto sync_error;
@@ -460,13 +473,14 @@ SalvageClient(VolumeId vid, char * pname)
 static int * child_slot;
 
 static void
-SalvageServer(void)
+SalvageServer(int argc, char **argv)
 {
     int pid, ret;
     struct SalvageQueueNode * node;
     pthread_t tid;
     pthread_attr_t attrs;
     int slot;
+    VolumePackageOptions opts;
 
     /* All entries to the log will be appended.  Useful if there are
      * multiple salvagers appending to the log.
@@ -483,46 +497,49 @@ SalvageServer(void)
     setlinebuf(logFile);
 
     fprintf(logFile, "%s\n", cml_version_number);
-    Log("Starting OpenAFS Online Salvage Server %s (%s)\n", SalvageVersion, commandLine);
-    
+    LogCommandLine(argc, argv, "Online Salvage Server",
+                  SalvageVersion, "Starting OpenAFS", Log);
     /* Get and hold a lock for the duration of the salvage to make sure
      * that no other salvage runs at the same time.  The routine
-     * VInitVolumePackage (called below) makes sure that a file server or
+     * VInitVolumePackage2 (called below) makes sure that a file server or
      * other volume utilities don't interfere with the salvage.
      */
-    
+
     /* even demand attach online salvager
      * still needs this because we don't want
      * a stand-alone salvager to conflict with
      * the salvager daemon */
-    ObtainSalvageLock();
+    ObtainSharedSalvageLock();
 
     child_slot = (int *) malloc(Parallel * sizeof(int));
-    assert(child_slot != NULL);
+    osi_Assert(child_slot != NULL);
     memset(child_slot, 0, Parallel * sizeof(int));
-           
+
     /* initialize things */
-    VInitVolumePackage(salvageServer, 5, 5,
-                      1, 0);
+    VOptDefaults(salvageServer, &opts);
+    if (VInitVolumePackage2(salvageServer, &opts)) {
+       Log("Shutting down: errors encountered initializing volume package\n");
+       Exit(1);
+    }
     DInit(10);
     queue_Init(&pending_q);
     queue_Init(&log_cleanup_queue);
-    assert(pthread_mutex_init(&worker_lock, NULL) == 0);
-    assert(pthread_cond_init(&worker_cv, NULL) == 0);
-    assert(pthread_cond_init(&log_cleanup_queue.queue_change_cv, NULL) == 0);
-    assert(pthread_attr_init(&attrs) == 0);
+    MUTEX_INIT(&worker_lock, "worker", MUTEX_DEFAULT, 0);
+    CV_INIT(&worker_cv, "worker", CV_DEFAULT, 0);
+    CV_INIT(&log_cleanup_queue.queue_change_cv, "queuechange", CV_DEFAULT, 0);
+    osi_Assert(pthread_attr_init(&attrs) == 0);
 
     /* start up the reaper and log cleaner threads */
-    assert(pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED) == 0);
-    assert(pthread_create(&tid, 
-                         &attrs, 
+    osi_Assert(pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED) == 0);
+    osi_Assert(pthread_create(&tid,
+                         &attrs,
                          &SalvageChildReaperThread,
                          NULL) == 0);
-    assert(pthread_create(&tid, 
-                         &attrs, 
+    osi_Assert(pthread_create(&tid,
+                         &attrs,
                          &SalvageLogCleanupThread,
                          NULL) == 0);
-    assert(pthread_create(&tid,
+    osi_Assert(pthread_create(&tid,
                          &attrs,
                          &SalvageLogScanningThread,
                          NULL) == 0);
@@ -530,7 +547,7 @@ SalvageServer(void)
     /* loop forever serving requests */
     while (1) {
        node = SALVSYNC_getWork();
-       assert(node != NULL);
+       osi_Assert(node != NULL);
 
        Log("dispatching child to salvage volume %u...\n",
            node->command.sop.parent);
@@ -541,7 +558,7 @@ SalvageServer(void)
          if (!child_slot[slot])
            break;
        }
-       assert (slot < Parallel);
+       osi_Assert (slot < Parallel);
 
     do_fork:
        pid = Fork();
@@ -557,18 +574,18 @@ SalvageServer(void)
            child_slot[slot] = pid;
            node->pid = pid;
            VOL_UNLOCK;
-           
-           assert(pthread_mutex_lock(&worker_lock) == 0);
+
+           MUTEX_ENTER(&worker_lock);
            current_workers++;
-           
+
            /* let the reaper thread know another worker was spawned */
-           assert(pthread_cond_broadcast(&worker_cv) == 0);
-           
+           CV_BROADCAST(&worker_cv);
+
            /* if we're overquota, wait for the reaper */
            while (current_workers >= Parallel) {
-               assert(pthread_cond_wait(&worker_cv, &worker_lock) == 0);
+               CV_WAIT(&worker_cv, &worker_lock);
            }
-           assert(pthread_mutex_unlock(&worker_lock) == 0);
+           MUTEX_EXIT(&worker_lock);
        }
     }
 }
@@ -586,7 +603,7 @@ DoSalvageVolume(struct SalvageQueueNode * node, int slot)
      * another thread may have held the lock on the FILE
      * structure when fork was called! */
 
-    afs_snprintf(childLog, sizeof(childLog), "%s.%d", 
+    afs_snprintf(childLog, sizeof(childLog), "%s.%d",
                 AFSDIR_SERVER_SLVGLOG_FILEPATH, getpid());
 
     logFile = afs_fopen(childLog, "a");
@@ -599,14 +616,19 @@ DoSalvageVolume(struct SalvageQueueNode * node, int slot)
        Log("salvageServer: invalid volume id specified; salvage aborted\n");
        return 1;
     }
-    
+
     partP = VGetPartition(node->command.sop.partName, 0);
     if (!partP) {
-       Log("salvageServer: Unknown or unmounted partition %s; salvage aborted\n", 
+       Log("salvageServer: Unknown or unmounted partition %s; salvage aborted\n",
            node->command.sop.partName);
        return 1;
     }
 
+    /* obtain a shared salvage lock in the child worker, so if the
+     * salvageserver restarts (and we continue), we will still hold a lock and
+     * prevent standalone salvagers from interfering */
+    ObtainSharedSalvageLock();
+
     /* Salvage individual volume; don't notify fs */
     SalvageFileSys1(partP, node->command.sop.parent);
 
@@ -621,17 +643,17 @@ SalvageChildReaperThread(void * args)
     int slot, pid, status;
     struct log_cleanup_node * cleanup;
 
-    assert(pthread_mutex_lock(&worker_lock) == 0);
+    MUTEX_ENTER(&worker_lock);
 
     /* loop reaping our children */
     while (1) {
        /* wait() won't block unless we have children, so
         * block on the cond var if we're childless */
        while (current_workers == 0) {
-           assert(pthread_cond_wait(&worker_cv, &worker_lock) == 0);
+           CV_WAIT(&worker_cv, &worker_lock);
        }
 
-       assert(pthread_mutex_unlock(&worker_lock) == 0);
+       MUTEX_EXIT(&worker_lock);
 
        cleanup = (struct log_cleanup_node *) malloc(sizeof(struct log_cleanup_node));
 
@@ -645,23 +667,23 @@ SalvageChildReaperThread(void * args)
            if (child_slot[slot] == pid)
                break;
        }
-       assert(slot < Parallel);
+       osi_Assert(slot < Parallel);
        child_slot[slot] = 0;
        VOL_UNLOCK;
 
        SALVSYNC_doneWorkByPid(pid, status);
 
-       assert(pthread_mutex_lock(&worker_lock) == 0);
+       MUTEX_ENTER(&worker_lock);
 
        if (cleanup) {
            cleanup->pid = pid;
            queue_Append(&log_cleanup_queue, cleanup);
-           assert(pthread_cond_signal(&log_cleanup_queue.queue_change_cv) == 0);
+           CV_SIGNAL(&log_cleanup_queue.queue_change_cv);
        }
 
        /* ok, we've reaped a child */
        current_workers--;
-       assert(pthread_cond_broadcast(&worker_cv) == 0);
+       CV_BROADCAST(&worker_cv);
     }
 
     return NULL;
@@ -696,24 +718,24 @@ SalvageLogCleanupThread(void * arg)
 {
     struct log_cleanup_node * cleanup;
 
-    assert(pthread_mutex_lock(&worker_lock) == 0);
+    MUTEX_ENTER(&worker_lock);
 
     while (1) {
        while (queue_IsEmpty(&log_cleanup_queue)) {
-           assert(pthread_cond_wait(&log_cleanup_queue.queue_change_cv, &worker_lock) == 0);
+           CV_WAIT(&log_cleanup_queue.queue_change_cv, &worker_lock);
        }
 
        while (queue_IsNotEmpty(&log_cleanup_queue)) {
            cleanup = queue_First(&log_cleanup_queue, log_cleanup_node);
            queue_Remove(cleanup);
-           assert(pthread_mutex_unlock(&worker_lock) == 0);
+           MUTEX_EXIT(&worker_lock);
            SalvageLogCleanup(cleanup->pid);
            free(cleanup);
-           assert(pthread_mutex_lock(&worker_lock) == 0);
-       }           
+           MUTEX_ENTER(&worker_lock);
+       }
     }
 
-    assert(pthread_mutex_unlock(&worker_lock) == 0);
+    MUTEX_EXIT(&worker_lock);
     return NULL;
 }
 
@@ -725,9 +747,9 @@ SalvageLogCleanup(int pid)
     char fn[AFSDIR_PATH_MAX];
     static char buf[LOG_XFER_BUF_SIZE];
 
-    afs_snprintf(fn, sizeof(fn), "%s.%d", 
+    afs_snprintf(fn, sizeof(fn), "%s.%d",
                 AFSDIR_SERVER_SLVGLOG_FILEPATH, pid);
-    
+
 
     pidlog = open(fn, O_RDONLY);
     unlink(fn);
@@ -775,7 +797,7 @@ SalvageLogScanningThread(void * arg)
        prefix_len = strlen(prefix);
 
        dp = opendir(AFSDIR_LOGS_DIR);
-       assert(dp);
+       osi_Assert(dp);
 
        while ((dirp = readdir(dp)) != NULL) {
            pid_t pid;
@@ -841,7 +863,7 @@ ScanLogs(struct rx_queue *log_watch_queue)
 {
     struct log_cleanup_node *cleanup, *next;
 
-    assert(pthread_mutex_lock(&worker_lock) == 0);
+    MUTEX_ENTER(&worker_lock);
 
     for (queue_Scan(log_watch_queue, cleanup, next, log_cleanup_node)) {
        /* if a process is still running, assume it's the salvage process
@@ -849,9 +871,9 @@ ScanLogs(struct rx_queue *log_watch_queue)
        if (kill(cleanup->pid, 0) < 0 && errno == ESRCH) {
            queue_Remove(cleanup);
            queue_Append(&log_cleanup_queue, cleanup);
-           assert(pthread_cond_signal(&log_cleanup_queue.queue_change_cv) == 0);
+           CV_SIGNAL(&log_cleanup_queue.queue_change_cv);
        }
     }
 
-    assert(pthread_mutex_unlock(&worker_lock) == 0);
+    MUTEX_EXIT(&worker_lock);
 }