CatalogueDrive.cpp 32.4 KB
Newer Older
Steven Murray's avatar
Steven Murray committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/******************************************************************************
 *
 * This file is part of the Castor project.
 * See http://castor.web.cern.ch/castor
 *
 * Copyright (C) 2003  CERN
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 *
 *
21
 * @author Castor Dev team, castor-dev@cern.ch
Steven Murray's avatar
Steven Murray committed
22
23
 *****************************************************************************/

24
#include "castor/exception/Exception.hpp"
25
#include "castor/tape/tapeserver/daemon/CatalogueDrive.hpp"
26
#include "castor/tape/tapeserver/daemon/Constants.hpp"
27
28
#include "castor/utils/utils.hpp"
#include "h/Ctape_constants.h"
29
#include "h/rmc_constants.h"
Steven Murray's avatar
Steven Murray committed
30

31
32
#include <errno.h>
#include <signal.h>
Steven Murray's avatar
Steven Murray committed
33
#include <string.h>
34
#include <sys/types.h>
Steven Murray's avatar
Steven Murray committed
35
36
37
38

//------------------------------------------------------------------------------
// constructor
//------------------------------------------------------------------------------
39
castor::tape::tapeserver::daemon::CatalogueDrive::CatalogueDrive(
40
  const int netTimeout,
41
42
  log::Logger &log,
  ProcessForkerProxy &processForker,
43
  legacymsg::CupvProxy &cupv,
44
  legacymsg::VdqmProxy &vdqm,
45
  legacymsg::VmgrProxy &vmgr,
46
47
  const std::string &hostName,
  const utils::DriveConfig &config,
48
49
50
51
  const DriveState state,
  const time_t waitJobTimeoutInSecs,
  const time_t mountTimeoutInSecs,
  const time_t blockMoveTimeoutInSecs)
Steven Murray's avatar
Steven Murray committed
52
  throw():
53
  m_netTimeout(netTimeout),
54
55
  m_log(log),
  m_processForker(processForker),
56
  m_cupv(cupv),
57
  m_vdqm(vdqm),
58
  m_vmgr(vmgr),
59
  m_hostName(hostName),
60
61
  m_config(config),
  m_state(state),
62
63
64
  m_waitJobTimeoutInSecs(waitJobTimeoutInSecs),
  m_mountTimeoutInSecs(mountTimeoutInSecs),
  m_blockMoveTimeoutInSecs(blockMoveTimeoutInSecs),
Daniele Kruse's avatar
Daniele Kruse committed
65
  m_session(NULL) {
66
67
68
}

//------------------------------------------------------------------------------
69
// destructor
70
//------------------------------------------------------------------------------
71
castor::tape::tapeserver::daemon::CatalogueDrive::~CatalogueDrive()
72
  throw() {
73
74
75
  deleteSession();
}

76
//------------------------------------------------------------------------------
77
// handleTick
78
//------------------------------------------------------------------------------
79
bool castor::tape::tapeserver::daemon::CatalogueDrive::handleTick() {
80
81
82
  try {
    checkForSession();
  } catch(...) {
83
    return true; // Continue the main event loop
84
85
  }

86
  return m_session->handleTick();
87
88
}

89
90
91
//------------------------------------------------------------------------------
// deleteSession
//------------------------------------------------------------------------------
92
void castor::tape::tapeserver::daemon::CatalogueDrive::deleteSession() {
93
  delete m_session;
94
  m_session = NULL;
Steven Murray's avatar
Steven Murray committed
95
96
97
}

//-----------------------------------------------------------------------------
98
// driveStateToStr
Steven Murray's avatar
Steven Murray committed
99
100
//-----------------------------------------------------------------------------
const char
101
  *castor::tape::tapeserver::daemon::CatalogueDrive::driveStateToStr(
Steven Murray's avatar
Steven Murray committed
102
103
  const DriveState state) throw() {
  switch(state) {
104
105
106
107
108
109
110
111
112
  case DRIVE_STATE_INIT                : return "INIT";
  case DRIVE_STATE_DOWN                : return "DOWN";
  case DRIVE_STATE_UP                  : return "UP";
  case DRIVE_STATE_RUNNING             : return "RUNNING";
  case DRIVE_STATE_WAITDOWN            : return "WAITDOWN";
  case DRIVE_STATE_WAITSHUTDOWNKILL    : return "WAITSHUTDOWNKILL";
  case DRIVE_STATE_WAITSHUTDOWNCLEANER : return "WAITSHUTDOWNCLEANER";
  case DRIVE_STATE_SHUTDOWN            : return "SHUTDOWN";
  default                              : return "UNKNOWN";
Steven Murray's avatar
Steven Murray committed
113
114
115
  }
}

116
117
118
119
//------------------------------------------------------------------------------
// getConfig
//------------------------------------------------------------------------------
const castor::tape::utils::DriveConfig
120
  &castor::tape::tapeserver::daemon::CatalogueDrive::getConfig() const {
121
122
123
124
  return m_config;
}

//------------------------------------------------------------------------------
125
126
// getState
//------------------------------------------------------------------------------
127
128
castor::tape::tapeserver::daemon::CatalogueDrive::DriveState
  castor::tape::tapeserver::daemon::CatalogueDrive::getState()
129
130
131
132
133
134
  const throw() {
  return m_state;
} 

//------------------------------------------------------------------------------
// getSession
135
//------------------------------------------------------------------------------
136
const castor::tape::tapeserver::daemon::CatalogueSession &
137
  castor::tape::tapeserver::daemon::CatalogueDrive::getSession() const {
138
139
140
141
142
143
144
145
146
  try {
    checkForSession();
    return *m_session;
  } catch(castor::exception::Exception &ne) {
    castor::exception::Exception ex;
    ex.getMessage() << "Failed to get tape session for drive " <<
      m_config.unitName << " from drive catalogue: " << ne.getMessage().str();
    throw ex;
  }
147
148
149
}

//------------------------------------------------------------------------------
150
// checkForSession
151
//------------------------------------------------------------------------------
152
void castor::tape::tapeserver::daemon::CatalogueDrive::checkForSession()
153
  const {
154
155
  if(NULL == m_session) {
    castor::exception::Exception ex;
156
157
    ex.getMessage() << "Drive is currently not running a session: state=" <<
      driveStateToStr(m_state);
158
159
    throw ex;
  }
160
161
162
}

//------------------------------------------------------------------------------
163
// getCleanerSession
164
//------------------------------------------------------------------------------
165
166
const castor::tape::tapeserver::daemon::CatalogueCleanerSession &
  castor::tape::tapeserver::daemon::CatalogueDrive::getCleanerSession()
167
168
169
  const {
  try {
    checkForCleanerSession();
170
171
    const CatalogueCleanerSession *const cleanerSession =
      dynamic_cast<const CatalogueCleanerSession*>(m_session);
172
173
174
175
    if(NULL == cleanerSession) {
      // Should never get here
      castor::exception::Exception ex;
      ex.getMessage() <<
176
        "Failed to cast session to CatalogueCleanerSession";
177
178
179
180
181
182
183
184
185
186
187
      throw ex;
    }

    return *cleanerSession;
  } catch(castor::exception::Exception &ne) {
    castor::exception::Exception ex;
    ex.getMessage() << "Failed to get cleaner session for drive " <<
      m_config.unitName << " from drive catalogue: " << ne.getMessage().str();
    throw ex;
  }
}
188

Daniele Kruse's avatar
Daniele Kruse committed
189
//------------------------------------------------------------------------------
190
// getCleanerSession
Daniele Kruse's avatar
Daniele Kruse committed
191
//------------------------------------------------------------------------------
192
193
castor::tape::tapeserver::daemon::CatalogueCleanerSession &
  castor::tape::tapeserver::daemon::CatalogueDrive::getCleanerSession() {
194
195
  try {
    checkForCleanerSession();
196
197
    CatalogueCleanerSession *const cleanerSession =
      dynamic_cast<CatalogueCleanerSession*>(m_session);
198
199
200
201
    if(NULL == cleanerSession) {
      // Should never get here
      castor::exception::Exception ex;
      ex.getMessage() << 
202
        "Failed to cast session to CatalogueCleanerSession";
203
204
205
206
207
208
209
210
211
212
      throw ex;
    }

    return *cleanerSession;
  } catch(castor::exception::Exception &ne) {
    castor::exception::Exception ex;
    ex.getMessage() << "Failed to get cleaner session for drive " <<
      m_config.unitName << " from drive catalogue: " << ne.getMessage().str();
    throw ex;
  }
Daniele Kruse's avatar
Daniele Kruse committed
213
214
215
}

//------------------------------------------------------------------------------
216
// checkForCleanerSession
Daniele Kruse's avatar
Daniele Kruse committed
217
//------------------------------------------------------------------------------
218
void castor::tape::tapeserver::daemon::CatalogueDrive::
219
  checkForCleanerSession() const {
220
  checkForSession();
221
222
  const CatalogueSession::Type sessionType = m_session->getType();
  if(CatalogueSession::SESSION_TYPE_CLEANER != sessionType) {
223
224
225
    castor::exception::Exception ex;
    ex.getMessage() <<
      "Session associated with drive is not a cleaner session"
226
      ": actual=" << CatalogueSession::sessionTypeToStr(sessionType);
227
228
229
230
231
232
233
    throw ex;
  }
}

//------------------------------------------------------------------------------
// getLabelSession
//------------------------------------------------------------------------------
234
235
const castor::tape::tapeserver::daemon::CatalogueLabelSession &
  castor::tape::tapeserver::daemon::CatalogueDrive::getLabelSession()
Daniele Kruse's avatar
Daniele Kruse committed
236
  const {
237
238
  try {
    checkForLabelSession();
239
240
    const CatalogueLabelSession *const labelSession =
      dynamic_cast<const CatalogueLabelSession*>(m_session);
241
242
243
    if(NULL == labelSession) {
      // Should never get here
      castor::exception::Exception ex;
244
      ex.getMessage() << "Failed to cast session to CatalogueLabelSession";
245
246
247
248
249
      throw ex;
    }

    return *labelSession;
  } catch(castor::exception::Exception &ne) {
Daniele Kruse's avatar
Daniele Kruse committed
250
    castor::exception::Exception ex;
251
252
253
254
255
256
257
258
259
    ex.getMessage() << "Failed to get label session for drive " <<
      m_config.unitName << " from drive catalogue: " << ne.getMessage().str();
    throw ex;
  }
}

//------------------------------------------------------------------------------
// getLabelSession
//------------------------------------------------------------------------------
260
261
castor::tape::tapeserver::daemon::CatalogueLabelSession &
  castor::tape::tapeserver::daemon::CatalogueDrive::getLabelSession() {
262
263
  try {
    checkForLabelSession();
264
265
    CatalogueLabelSession *const labelSession =
      dynamic_cast<CatalogueLabelSession*>(m_session);
266
267
268
    if(NULL == labelSession) {
      // Should never get here
      castor::exception::Exception ex;
269
      ex.getMessage() << "Failed to cast session to CatalogueLabelSession";
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
      throw ex;
    }

    return *labelSession;
  } catch(castor::exception::Exception &ne) {
    castor::exception::Exception ex;
    ex.getMessage() << "Failed to get label session for drive " <<
      m_config.unitName << " from drive catalogue: " << ne.getMessage().str();
    throw ex;
  }
}

//------------------------------------------------------------------------------
// checkForLabelSession
//------------------------------------------------------------------------------
285
void castor::tape::tapeserver::daemon::CatalogueDrive::
286
  checkForLabelSession() const {
287
  checkForSession();
288
289
  const CatalogueSession::Type sessionType = m_session->getType();
  if(CatalogueSession::SESSION_TYPE_LABEL != sessionType) {
290
291
    castor::exception::Exception ex;
    ex.getMessage() << "Session associated with drive is not a label session"
292
      ": actual=" << CatalogueSession::sessionTypeToStr(sessionType);
293
294
295
296
297
298
299
    throw ex;
  }
}

//------------------------------------------------------------------------------
// getTransferSession
//------------------------------------------------------------------------------
300
301
const castor::tape::tapeserver::daemon::CatalogueTransferSession &
  castor::tape::tapeserver::daemon::CatalogueDrive::getTransferSession()
302
303
304
  const {
  try {
    checkForTransferSession();
305
306
    CatalogueTransferSession *const transferSession =
      dynamic_cast<CatalogueTransferSession*>(m_session);
307
308
309
310
    if(NULL == transferSession) {
      // Should never get here
      castor::exception::Exception ex;
      ex.getMessage() <<
311
        "Failed to cast session to CatalogueTransferSession";
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
      throw ex;
    }

    return *transferSession;
  } catch(castor::exception::Exception &ne) {
    castor::exception::Exception ex;
    ex.getMessage() << "Failed to get transfer session for drive " <<
      m_config.unitName << " from drive catalogue: " << ne.getMessage().str();
    throw ex;
  }
}

//------------------------------------------------------------------------------
// getTransferSession
//------------------------------------------------------------------------------
327
328
castor::tape::tapeserver::daemon::CatalogueTransferSession &
  castor::tape::tapeserver::daemon::CatalogueDrive::getTransferSession() {
329
330
  try {
    checkForTransferSession();
331
332
    CatalogueTransferSession *const transferSession =
      dynamic_cast<CatalogueTransferSession*>(m_session);
333
334
335
336
    if(NULL == transferSession) {
      // Should never get here
      castor::exception::Exception ex;
      ex.getMessage() <<
337
        "Failed to cast session to CatalogueTransferSession";
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
      throw ex;
    }

    return *transferSession;
  } catch(castor::exception::Exception &ne) {
    castor::exception::Exception ex;
    ex.getMessage() << "Failed to get transfer session for drive " <<
      m_config.unitName << " from drive catalogue: " << ne.getMessage().str();
    throw ex;
  }
}

//------------------------------------------------------------------------------
// checkForTransferSession
//------------------------------------------------------------------------------
353
void castor::tape::tapeserver::daemon::CatalogueDrive::
354
  checkForTransferSession() const {
355
  checkForSession();
356
357
  const CatalogueSession::Type sessionType = m_session->getType();
  if(CatalogueSession::SESSION_TYPE_TRANSFER != sessionType) {
358
359
360
    castor::exception::Exception ex;
    ex.getMessage() <<
      "Session associated with drive is not a transfer session"
361
      ": actual=" << CatalogueSession::sessionTypeToStr(sessionType);
362
363
    throw ex;
  }
364
365
366
367
368
}

//------------------------------------------------------------------------------
// configureUp
//------------------------------------------------------------------------------
369
void castor::tape::tapeserver::daemon::CatalogueDrive::configureUp() {
370
371
  switch(m_state) {
  case DRIVE_STATE_UP:
372
  case DRIVE_STATE_RUNNING:
373
374
    break;
  case DRIVE_STATE_DOWN:
375
    changeState(DRIVE_STATE_UP);
376
377
    break;
  case DRIVE_STATE_WAITDOWN:
378
    changeState(DRIVE_STATE_RUNNING);
379
380
381
382
383
    break;
  default:
    {
      castor::exception::Exception ex;
      ex.getMessage() << "Failed to configure tape-drive " << m_config.unitName
384
        << " up : Incompatible drive state: state=" << driveStateToStr(m_state);
385
386
387
      throw ex;
    }
  }
388
  m_vdqm.setDriveUp(m_hostName, m_config.unitName, m_config.dgn);
389
390
391
392
393
}

//-----------------------------------------------------------------------------
// configureDown
//-----------------------------------------------------------------------------
394
void castor::tape::tapeserver::daemon::CatalogueDrive::configureDown() {
395
396
  switch(m_state) {
  case DRIVE_STATE_DOWN:
397
  case DRIVE_STATE_WAITDOWN:
398
399
    break;
  case DRIVE_STATE_UP:
400
    changeState(DRIVE_STATE_DOWN);
401
    m_vdqm.setDriveDown(m_hostName, m_config.unitName, m_config.dgn);
402
    break;
403
  case CatalogueDrive::DRIVE_STATE_RUNNING:
404
    changeState(DRIVE_STATE_WAITDOWN);
405
406
407
408
409
    break;
  default:
    {
      castor::exception::Exception ex;
      ex.getMessage() << "Failed to configure tape drive " << m_config.unitName
410
        << " down: Incompatible drive state: state=" <<
411
        driveStateToStr(m_state);
412
413
414
415
416
417
418
419
      throw ex;
    }
  }
}

//-----------------------------------------------------------------------------
// receivedVdqmJob
//-----------------------------------------------------------------------------
420
void castor::tape::tapeserver::daemon::CatalogueDrive::receivedVdqmJob(
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
  const legacymsg::RtcpJobRqstMsgBody &job)  {

  std::ostringstream task;
  task << "handle vdqm job for tape drive " << m_config.unitName;

  // Sanity check
  if(job.driveUnit != m_config.unitName) {
    // Should never happen
    castor::exception::Exception ex;
    ex.getMessage() << "Failed to " << task.str() <<
      ": unit name mismatch: job.driveUnit=" << job.driveUnit <<
      " m_config.unitName=" << m_config.unitName;
    throw ex;
  }
  
  switch(m_state) {
  case DRIVE_STATE_UP:
    if(std::string(job.dgn) != m_config.dgn) {
      castor::exception::Exception ex;
      ex.getMessage() << "Failed to " << task.str() <<
        ": DGN mismatch: catalogueDgn=" << m_config.dgn << " vdqmJobDgn="
          << job.dgn;
      throw ex;
    }
445
    changeState(DRIVE_STATE_RUNNING);
446
    {
447
448
      CatalogueTransferSession *const transferSession =
        CatalogueTransferSession::create(
449
450
451
          m_log,
          m_netTimeout,
          m_config,
452
453
454
          job,
          m_vmgr,
          m_cupv,
455
          m_hostName,
456
457
458
          m_waitJobTimeoutInSecs,
          m_mountTimeoutInSecs,
          m_blockMoveTimeoutInSecs,
459
          m_processForker);
460
      m_session = dynamic_cast<CatalogueSession *>(transferSession);
461
462
      m_vdqm.assignDrive(m_hostName, m_config.unitName, job.dgn,
        job.volReqId, m_session->getPid());
463
    }
464
465
466
467
468
    break;
  default:
    {
      castor::exception::Exception ex;
      ex.getMessage() << "Failed to " << task.str() <<
469
        ": Incompatible drive state: state=" << driveStateToStr(m_state);
470
471
472
473
474
475
476
477
      throw ex;
    }
  } 
} 

//-----------------------------------------------------------------------------
// receivedLabelJob
//-----------------------------------------------------------------------------
478
void castor::tape::tapeserver::daemon::CatalogueDrive::receivedLabelJob(
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
  const legacymsg::TapeLabelRqstMsgBody &job, const int labelCmdConnection) {
  const std::string unitName(job.drive);

  std::ostringstream task;
  task << "handle label job for tape drive " << m_config.unitName;

  // Sanity check
  if(job.drive != m_config.unitName) {
    // Should never happen
    castor::exception::Exception ex;
    ex.getMessage() << "Failed to " << task.str() <<
      ": unit name mismatch: job.drive=" << job.drive << 
      " m_config.unitName=" << m_config.unitName;
    throw ex;
  }

  switch(m_state) {
  case DRIVE_STATE_UP:
    if(std::string(job.dgn) != m_config.dgn) {
      castor::exception::Exception ex;
      ex.getMessage() << "Failed to " << task.str() <<
        ": DGN mismatch: catalogueDgn=" << m_config.dgn << " labelJobDgn="
        << job.dgn;
      throw ex;
    }
504
505
506
507
508
509
510
511
    m_session = CatalogueLabelSession::create(
      m_log,
      m_netTimeout,
      m_config,
      job,
      labelCmdConnection,
      m_cupv,
      m_processForker);
512
    changeState(DRIVE_STATE_RUNNING);
513
514
515
516
517
    break;
  default:
    {
      castor::exception::Exception ex;
      ex.getMessage() << "Failed to " << task.str() <<
518
        ": Incompatible drive state: state=" << driveStateToStr(m_state);
519
520
521
522
523
      throw ex;
    }
  }
}

524
//-----------------------------------------------------------------------------
525
// createCleaner
526
//-----------------------------------------------------------------------------
527
void castor::tape::tapeserver::daemon::CatalogueDrive::createCleaner(
528
529
  const std::string &vid, const time_t assignmentTime,
  const uint32_t driveReadyDelayInSeconds) {
530
  try {
531
    // Create a cleaner session
532
    m_session = CatalogueCleanerSession::create(
533
      m_log,
534
      m_netTimeout,
535
      m_config,
536
      m_processForker,
537
      vid,
538
539
      assignmentTime,
      driveReadyDelayInSeconds);
540
541
542
543
544
  } catch(castor::exception::Exception &ne) {
    castor::exception::Exception ex;
    ex.getMessage() << "Failed to create cleaner session: " <<
      ne.getMessage().str();
    throw ex;
545
  } 
546
547
}

548
549
550
//-----------------------------------------------------------------------------
// sessionSucceeded
//-----------------------------------------------------------------------------
551
void castor::tape::tapeserver::daemon::CatalogueDrive::
552
  sessionSucceeded() {
553
  switch(m_state) {
554
  case DRIVE_STATE_RUNNING:
555
    changeState(DRIVE_STATE_UP);
556
    m_vdqm.setDriveUp(m_hostName, m_config.unitName, m_config.dgn);
557
558
    break;
  case DRIVE_STATE_WAITDOWN:
559
560
561
562
563
    changeState(CatalogueDrive::DRIVE_STATE_DOWN);
    m_vdqm.setDriveDown(m_hostName, m_config.unitName, m_config.dgn);
    break;
  case DRIVE_STATE_WAITSHUTDOWNCLEANER:
    changeState(DRIVE_STATE_SHUTDOWN);
564
    m_vdqm.setDriveDown(m_hostName, m_config.unitName, m_config.dgn);
565
566
567
568
569
570
    break;
  default:
    {
      castor::exception::Exception ex;
      ex.getMessage() <<
        "Failed to record tape session succeeded for session with pid " <<
571
        getSession().getPid() << ": Incompatible drive state: state=" <<
572
        driveStateToStr(m_state);
Daniele Kruse's avatar
Daniele Kruse committed
573
574
      delete m_session;
      m_session = NULL;
575
576
577
      throw ex;
    }
  }
578

579
  std::auto_ptr<CatalogueSession> session(m_session);
Daniele Kruse's avatar
Daniele Kruse committed
580
  m_session = NULL;
581
  session->sessionSucceeded();
582
583
584
585
586
}

//-----------------------------------------------------------------------------
// sessionFailed
//-----------------------------------------------------------------------------
587
void castor::tape::tapeserver::daemon::CatalogueDrive::sessionFailed() {
588
  switch(m_state) {
589
  case DRIVE_STATE_RUNNING:
590
  case DRIVE_STATE_WAITDOWN:
591
    return runningSessionFailed();
592
  case DRIVE_STATE_WAITSHUTDOWNKILL:
593
    return sessionKilledByShutdown();
594
  case DRIVE_STATE_WAITSHUTDOWNCLEANER:
595
    return cleanerOfShutdownFailed();
596
597
598
599
600
  default:
    {
      castor::exception::Exception ex;
      ex.getMessage() <<
        "Failed to record tape session failed for session with pid " <<
601
        getSession().getPid() << ": Incompatible drive state: state=" <<
602
        driveStateToStr(m_state);
Daniele Kruse's avatar
Daniele Kruse committed
603
604
      delete m_session;
      m_session = NULL;
605
606
607
608
609
      throw ex;
    }
  }
}

610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
//------------------------------------------------------------------------------
// runningSessionFailed
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::CatalogueDrive::runningSessionFailed() {
  std::auto_ptr<CatalogueSession> session(m_session);
  m_session = NULL;
  session->sessionFailed();

  if(CatalogueSession::SESSION_TYPE_CLEANER != session->getType()) {
    const uint32_t driveReadyDelayInSeconds = 60;
    createCleaner(session->getVid(), session->getAssignmentTime(),
      driveReadyDelayInSeconds);
  } else {
    changeState(DRIVE_STATE_DOWN);
    m_vdqm.setDriveDown(m_hostName, m_config.unitName, m_config.dgn);
  }
}

//------------------------------------------------------------------------------
// sessionKilledByShutdown
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::CatalogueDrive::
  sessionKilledByShutdown() {
  std::auto_ptr<CatalogueSession> session(m_session);
  m_session = NULL;
  session->sessionFailed();

  changeState(DRIVE_STATE_WAITSHUTDOWNCLEANER);
  const uint32_t driveReadyDelayInSeconds = 60;
  createCleaner(session->getVid(), session->getAssignmentTime(),
    driveReadyDelayInSeconds);
}

//------------------------------------------------------------------------------
// cleanerOfShutdownFailed
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::CatalogueDrive::
  cleanerOfShutdownFailed() {
  std::auto_ptr<CatalogueSession> session(m_session);
  m_session = NULL;
  session->sessionFailed();

  // Cleaner failed, no more can be done, mark drive as shutdown
  changeState(DRIVE_STATE_SHUTDOWN);
}

656
657
658
659
//------------------------------------------------------------------------------
// getTapeStatDriveEntry
//------------------------------------------------------------------------------
castor::legacymsg::TapeStatDriveEntry
660
  castor::tape::tapeserver::daemon::CatalogueDrive::getTapeStatDriveEntry()
661
662
663
664
  const {
  legacymsg::TapeStatDriveEntry entry;

  try {
665
666
    entry.uid = getUidForTapeStatDriveEntry();
    entry.jid = getJidForTapeStatDriveEntry();
667
    castor::utils::copyString(entry.dgn, m_config.dgn);
668
669
670
    entry.up = getUpForTapeStatDriveEntry();
    entry.asn = getAsnForTapeStatDriveEntry();
    entry.asn_time = getAsnTimeForTapeStatDriveEntry();
671
    castor::utils::copyString(entry.drive, m_config.unitName);
672
673
674
675
    entry.mode = getModeForTapeStatDriveEntry();
    castor::utils::copyString(entry.lblcode,
      getLblCodeForTapeStatDriveEntry().c_str());
    entry.tobemounted = getToBeMountedForTapeStatDriveEntry();
676
677
    castor::utils::copyString(entry.vid, getVidForTapeStatDriveEntry());
    castor::utils::copyString(entry.vsn, getVsnForTapeStatDriveEntry());
678
679
680
681
682
683
684
685
686
687
688
689
690
691
    entry.cfseq = 0; // the fseq is ignored by tpstat, so we leave it set to 0
  } catch(castor::exception::Exception &ne) {
    castor::exception::Exception ex;
    ex.getMessage() << "Failed to get TapeStatDriveEntry: " <<
      ne.getMessage().str();
    throw ex;
  }

  return entry;
}

//------------------------------------------------------------------------------
// getUidForTapeStatDriveEntry
//------------------------------------------------------------------------------
692
uint32_t castor::tape::tapeserver::daemon::CatalogueDrive::
693
694
  getUidForTapeStatDriveEntry() const throw() {
  switch(m_state) {
695
  case DRIVE_STATE_RUNNING:
696
697
698
699
700
701
702
703
704
705
  case DRIVE_STATE_WAITDOWN:
    return geteuid();
  default:
    return 0;
  }
}

//------------------------------------------------------------------------------
// getJidForTapeStatDriveEntry
//------------------------------------------------------------------------------
706
uint32_t castor::tape::tapeserver::daemon::CatalogueDrive::
707
  getJidForTapeStatDriveEntry() const throw() {
708
  try {
709
    return getSession().getPid();
710
  } catch(...) {
711
712
713
714
715
716
717
    return 0;
  }
}

//------------------------------------------------------------------------------
// getUpForTapeStatDriveEntry
//------------------------------------------------------------------------------
718
uint16_t castor::tape::tapeserver::daemon::CatalogueDrive::
719
720
721
  getUpForTapeStatDriveEntry() const throw() {
  switch(m_state) {
  case DRIVE_STATE_UP:
722
  case DRIVE_STATE_RUNNING:
723
724
725
726
727
728
729
730
731
    return 1;
  default:
    return 0;
  }
}

//------------------------------------------------------------------------------
// getAsnForTapeStatDriveEntry
//------------------------------------------------------------------------------
732
uint16_t castor::tape::tapeserver::daemon::CatalogueDrive::
733
734
  getAsnForTapeStatDriveEntry() const throw() {
  switch(m_state) {
735
  case DRIVE_STATE_RUNNING:
736
737
738
739
740
741
742
743
744
745
  case DRIVE_STATE_WAITDOWN:
    return 1;
  default:
    return 0;
  }
}

//------------------------------------------------------------------------------
// getAsnTimeForTapeStatDriveEntry
//------------------------------------------------------------------------------
746
uint32_t castor::tape::tapeserver::daemon::CatalogueDrive::
747
  getAsnTimeForTapeStatDriveEntry() const throw() {
748
749
750
  try {
    return getSession().getAssignmentTime();
  } catch(...) {
751
752
    return 0;
  }
753
754
755
756
757
}

//------------------------------------------------------------------------------
// getModeForTapeStatDriveEntry
//------------------------------------------------------------------------------
758
uint16_t castor::tape::tapeserver::daemon::CatalogueDrive::
759
  getModeForTapeStatDriveEntry() const throw() {
760
761
762
  try {
    return getSession().getMode();
  } catch(...) {
763
764
765
766
767
768
769
    return WRITE_DISABLE;
  }
}

//------------------------------------------------------------------------------
// getLblCodeForTapeStatDriveEntry
//------------------------------------------------------------------------------
770
std::string castor::tape::tapeserver::daemon::CatalogueDrive::
771
772
773
774
775
776
777
  getLblCodeForTapeStatDriveEntry() const throw() {
  return "aul";
}

//------------------------------------------------------------------------------
// getToBeMountedForTapeStatDriveEntry
//------------------------------------------------------------------------------
778
uint16_t castor::tape::tapeserver::daemon::CatalogueDrive::
779
  getToBeMountedForTapeStatDriveEntry() const throw() {
780
781
782
  try {
    return getSession().tapeIsBeingMounted();
  } catch(...) {
783
784
    return 0;
  }
785
786
787
788
789
}

//------------------------------------------------------------------------------
// getVidForTapeStatDriveEntry
//------------------------------------------------------------------------------
790
std::string castor::tape::tapeserver::daemon::CatalogueDrive::
791
  getVidForTapeStatDriveEntry() const throw() {
792
793
794
  try {
    return getSession().getVid();
  } catch(...) {
795
796
    return "";
  }
797
798
}

799
800
801
//------------------------------------------------------------------------------
// getVidForCleaner
//------------------------------------------------------------------------------
802
std::string castor::tape::tapeserver::daemon::CatalogueDrive::
803
804
805
806
807
808
809
810
811
812
813
  getVidForCleaner() const throw() {
  try {
    return getSession().getVid();
  } catch(...) {
    return "";
  }
}

//------------------------------------------------------------------------------
// getAssignmentTimeForCleaner
//------------------------------------------------------------------------------
814
time_t castor::tape::tapeserver::daemon::CatalogueDrive::
815
816
817
818
819
820
821
822
  getAssignmentTimeForCleaner() const throw() {
  try {
    return getSession().getAssignmentTime();
  } catch(...) {
    return 0;
  }
}

823
//------------------------------------------------------------------------------
824
// shutdown
825
//------------------------------------------------------------------------------
826
827
828
829
void castor::tape::tapeserver::daemon::CatalogueDrive::shutdown() {
  // If there is no running session
  if(NULL == m_session) {

830
    changeState(DRIVE_STATE_WAITSHUTDOWNCLEANER);
831

832
833
834
835
836
    // Create a cleaner process to make 100% sure the tape drive is empty
    const std::string vid = ""; // Empty string means VID is not known
    const time_t assignmentTime = time(NULL);
    const uint32_t driveReadyDelayInSeconds = 0;
    createCleaner(vid, assignmentTime, driveReadyDelayInSeconds);
837

838
839
  // Else there is a running session
  } else {
840

841
842
    // If the running session is a cleaner
    if(CatalogueSession::SESSION_TYPE_CLEANER == m_session->getType()) {
843

844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
      changeState(DRIVE_STATE_WAITSHUTDOWNCLEANER);

    // Else the running session is not a cleaner
    } else {

      changeState(DRIVE_STATE_WAITSHUTDOWNKILL);

      const pid_t sessionPid = m_session->getPid();
      const CatalogueSession::Type sessionType = m_session->getType();
      const char *sessionTypeStr =
        CatalogueSession::sessionTypeToStr(sessionType);

      std::list<log::Param> params;
      params.push_back(log::Param("unitName", m_config.unitName));
      params.push_back(log::Param("sessionType", sessionTypeStr));
      params.push_back(log::Param("sessionPid", sessionPid));

      // Kill the non-cleaner session
      if(kill(sessionPid, SIGKILL)) {
        const std::string message = castor::utils::errnoToString(errno);
        params.push_back(log::Param("message", message));
        m_log(LOG_ERR, "Failed to kill non-cleaner session whilst shutting"
          " down", params);

        // Nothing else can be done, mark drive as shutdown
        changeState(DRIVE_STATE_SHUTDOWN);

      } else {
        m_log(LOG_WARNING, "Sent SIGKILL to tape-session child-process",
          params);
      }

    } // Else the running session is not a cleaner

  } // Else there is a running session
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
}

//------------------------------------------------------------------------------
// killSession
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::CatalogueDrive::killSession() {
  // Do nothing if there is no running session
  if(NULL == m_session) {
    return;
  }

  const pid_t sessionPid = m_session->getPid();
  const CatalogueSession::Type sessionType = m_session->getType();
  const char *sessionTypeStr =
    CatalogueSession::sessionTypeToStr(sessionType);

  std::list<log::Param> params;
  params.push_back(log::Param("unitName", m_config.unitName));
  params.push_back(log::Param("sessionType", sessionTypeStr));
  params.push_back(log::Param("sessionPid", sessionPid));

  if(kill(sessionPid, SIGKILL)) {
    const std::string errorStr = castor::utils::errnoToString(errno);
    castor::exception::Exception ex;
    ex.getMessage() << "CatalogueDrive failed to kill session: sessionPid=" <<
     sessionPid << " sessionType=" << sessionTypeStr << ": " << errorStr;
    throw ex;
906
  }
907
908
909
910
911
  m_log(LOG_WARNING, "Killed tape-session child-process", params);
  delete m_session;
  m_session = NULL;
  changeState(DRIVE_STATE_DOWN);
  m_vdqm.setDriveDown(m_hostName, m_config.unitName, m_config.dgn);
912
913
}

914
915
916
//------------------------------------------------------------------------------
// getVsnForTapeStatDriveEntry
//------------------------------------------------------------------------------
917
std::string castor::tape::tapeserver::daemon::CatalogueDrive::
918
919
920
  getVsnForTapeStatDriveEntry() const throw() {
  return getVidForTapeStatDriveEntry();
}
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937

//------------------------------------------------------------------------------
// changeState
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::CatalogueDrive::changeState(
  const DriveState newState) throw() {
  std::list<log::Param> params;
  params.push_back(log::Param("unitName", m_config.unitName));
  params.push_back(log::Param("previousState", driveStateToStr(m_state)));
  params.push_back(log::Param("newState", driveStateToStr(newState)));
  if(NULL != m_session) {
    params.push_back(log::Param("sessionPid", m_session->getPid()));
  }

  m_state = newState;
  m_log(LOG_DEBUG, "CatalogueDrive changed state", params);
}