PageRenderTime 31ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/amanda/branches/amanda-260/device-src/device.c

#
C | 1121 lines | 881 code | 165 blank | 75 comment | 160 complexity | f6f31dcc2470f06c4ff87b49a3803445 MD5 | raw file
  1. /*
  2. * Copyright (c) 2005 Zmanda, Inc. All Rights Reserved.
  3. *
  4. * This library is free software; you can redistribute it and/or modify it
  5. * under the terms of the GNU Lesser General Public License version 2.1 as
  6. * published by the Free Software Foundation.
  7. *
  8. * This library is distributed in the hope that it will be useful, but
  9. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  10. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
  11. * License for more details.
  12. *
  13. * You should have received a copy of the GNU Lesser General Public License
  14. * along with this library; if not, write to the Free Software Foundation,
  15. * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  16. *
  17. * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
  18. * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
  19. */
  20. /* The Device API abstracts device workings, interaction, properties, and
  21. * capabilities from the rest of the Amanda code base. It supports
  22. * pluggable modules for different kinds of devices. */
  23. #include "amanda.h"
  24. #include "conffile.h"
  25. #include <regex.h>
  26. #include "device.h"
  27. #include "queueing.h"
  28. #include "property.h"
  29. #include "null-device.h"
  30. #include "timestamp.h"
  31. #include "vfs-device.h"
  32. #include "util.h"
  33. #ifdef WANT_TAPE_DEVICE
  34. #include "tape-device.h"
  35. #endif
  36. #include "rait-device.h"
  37. #ifdef WANT_S3_DEVICE
  38. #include "s3-device.h"
  39. #endif
  40. static GHashTable* driverList = NULL;
  41. void device_api_init(void) {
  42. g_type_init();
  43. amanda_thread_init();
  44. device_property_init();
  45. driverList = g_hash_table_new(g_str_hash, g_str_equal);
  46. /* register other types and devices. */
  47. null_device_register();
  48. vfs_device_register();
  49. #ifdef WANT_TAPE_DEVICE
  50. tape_device_register();
  51. #endif
  52. rait_device_register();
  53. #ifdef WANT_S3_DEVICE
  54. s3_device_register();
  55. #endif
  56. }
  57. void register_device(DeviceFactory factory,
  58. const char ** device_prefix_list) {
  59. char ** tmp;
  60. g_assert(driverList != NULL);
  61. g_assert(factory != NULL);
  62. g_return_if_fail(device_prefix_list != NULL);
  63. g_return_if_fail(*device_prefix_list != NULL);
  64. tmp = (char**)device_prefix_list;
  65. while (*tmp != NULL) {
  66. g_hash_table_insert(driverList, *tmp, (gpointer)factory);
  67. tmp ++;
  68. }
  69. }
  70. static DeviceFactory lookup_device_factory(const char *device_name) {
  71. gpointer key, value;
  72. g_assert(driverList != NULL);
  73. if (g_hash_table_lookup_extended(driverList, device_name, &key, &value)) {
  74. return (DeviceFactory)value;
  75. } else {
  76. return NULL;
  77. }
  78. }
  79. static const GFlagsValue read_label_status_flags_values[] = {
  80. { READ_LABEL_STATUS_SUCCESS,
  81. "READ_LABEL_STATUS_SUCCESS",
  82. "Success" },
  83. { READ_LABEL_STATUS_DEVICE_MISSING,
  84. "READ_LABEL_STATUS_DEVICE_MISSING",
  85. "Device not found" },
  86. { READ_LABEL_STATUS_DEVICE_ERROR,
  87. "READ_LABEL_STATUS_DEVICE_ERROR",
  88. "Device error" },
  89. { READ_LABEL_STATUS_VOLUME_MISSING,
  90. "READ_LABEL_STATUS_VOLUME_MISSING",
  91. "Volume not found" },
  92. { READ_LABEL_STATUS_VOLUME_UNLABELED,
  93. "READ_LABEL_STATUS_VOLUME_UNLABELED",
  94. "Volume not labeled" },
  95. { READ_LABEL_STATUS_VOLUME_ERROR,
  96. "READ_LABEL_STATUS_VOLUME_ERROR",
  97. "Volume error" },
  98. { 0, NULL, NULL }
  99. };
  100. GType read_label_status_flags_get_type(void) {
  101. static GType type = 0;
  102. if (G_UNLIKELY(type == 0)) {
  103. type = g_flags_register_static("ReadLabelStatusFlags",
  104. read_label_status_flags_values);
  105. }
  106. return type;
  107. }
  108. /* Device class definition starts here. */
  109. struct DevicePrivate_s {
  110. /* This is the return value of the device_get_property_list()
  111. method. */
  112. GArray *property_list;
  113. GHashTable * property_response;
  114. };
  115. /* This holds the default response to a particular property. */
  116. typedef struct {
  117. PropertyAccessFlags access;
  118. GValue response;
  119. } PropertyResponse;
  120. #define selfp (self->private)
  121. /* here are local prototypes, so we can make function pointers. */
  122. static void device_init (Device * o) G_GNUC_UNUSED;
  123. static void device_class_init (DeviceClass * c) G_GNUC_UNUSED;
  124. static void property_response_free(PropertyResponse *o);
  125. static gboolean default_device_open_device(Device * self, char * device_name);
  126. static gboolean default_device_finish(Device * self);
  127. static gboolean default_device_start(Device * self, DeviceAccessMode mode,
  128. char * label, char * timestamp);
  129. static gboolean default_device_start_file (Device * self,
  130. const dumpfile_t * jobinfo);
  131. static gboolean default_device_write_block (Device * self, guint size,
  132. gpointer data, gboolean last);
  133. static gboolean default_device_write_from_fd(Device *self, int fd);
  134. static gboolean default_device_finish_file (Device * self);
  135. static dumpfile_t* default_device_seek_file (Device * self, guint file);
  136. static gboolean default_device_seek_block (Device * self, guint64 block);
  137. static int default_device_read_block (Device * self, gpointer buffer,
  138. int * size);
  139. static gboolean default_device_read_to_fd(Device *self, int fd);
  140. static gboolean default_device_property_get(Device * self, DevicePropertyId ID,
  141. GValue * value);
  142. /* pointer to the class of our parent */
  143. static GObjectClass *parent_class = NULL;
  144. GType
  145. device_get_type (void)
  146. {
  147. static GType type = 0;
  148. if G_UNLIKELY(type == 0) {
  149. static const GTypeInfo info = {
  150. sizeof (DeviceClass),
  151. (GBaseInitFunc) NULL,
  152. (GBaseFinalizeFunc) NULL,
  153. (GClassInitFunc) device_class_init,
  154. (GClassFinalizeFunc) NULL,
  155. NULL /* class_data */,
  156. sizeof (Device),
  157. 0 /* n_preallocs */,
  158. (GInstanceInitFunc) device_init,
  159. NULL
  160. };
  161. type = g_type_register_static (G_TYPE_OBJECT, "Device", &info,
  162. (GTypeFlags)G_TYPE_FLAG_ABSTRACT);
  163. }
  164. return type;
  165. }
  166. static void device_finalize(GObject *obj_self) {
  167. Device *self G_GNUC_UNUSED = DEVICE (obj_self);
  168. if(G_OBJECT_CLASS(parent_class)->finalize)
  169. (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
  170. /* Here we call device_finish() if it hasn't been done
  171. yet. Subclasses may need to do this same check earlier. */
  172. if (self->access_mode != ACCESS_NULL) {
  173. device_finish(self);
  174. }
  175. amfree(self->device_name);
  176. amfree(self->volume_label);
  177. amfree(self->volume_time);
  178. g_array_free(selfp->property_list, TRUE);
  179. g_hash_table_destroy(selfp->property_response);
  180. amfree(self->private);
  181. }
  182. static void
  183. device_init (Device * self G_GNUC_UNUSED)
  184. {
  185. self->private = malloc(sizeof(DevicePrivate));
  186. self->device_name = NULL;
  187. self->access_mode = ACCESS_NULL;
  188. self->is_eof = FALSE;
  189. self->file = -1;
  190. self->block = 0;
  191. self->in_file = FALSE;
  192. self->volume_label = NULL;
  193. self->volume_time = NULL;
  194. selfp->property_list = g_array_new(TRUE, FALSE, sizeof(DeviceProperty));
  195. selfp->property_response =
  196. g_hash_table_new_full(g_direct_hash,
  197. g_direct_equal,
  198. NULL,
  199. (GDestroyNotify) property_response_free);
  200. }
  201. static void
  202. device_class_init (DeviceClass * c G_GNUC_UNUSED)
  203. {
  204. GObjectClass *g_object_class G_GNUC_UNUSED = (GObjectClass*) c;
  205. parent_class = g_type_class_ref (G_TYPE_OBJECT);
  206. c->open_device = default_device_open_device;
  207. c->finish = default_device_finish;
  208. c->read_label = NULL;
  209. c->start = default_device_start;
  210. c->start_file = default_device_start_file;
  211. c->write_block = default_device_write_block;
  212. c->write_from_fd = default_device_write_from_fd;
  213. c->finish_file = default_device_finish_file;
  214. c->seek_file = default_device_seek_file;
  215. c->seek_block = default_device_seek_block;
  216. c->read_block = default_device_read_block;
  217. c->read_to_fd = default_device_read_to_fd;
  218. c->property_get = default_device_property_get;
  219. c->property_set = NULL;
  220. c->recycle_file = NULL;
  221. g_object_class->finalize = device_finalize;
  222. }
  223. static void property_response_free(PropertyResponse * resp) {
  224. g_value_unset(&(resp->response));
  225. amfree(resp);
  226. }
  227. static char *
  228. regex_message(int result, regex_t *regex) {
  229. char * rval;
  230. size_t size;
  231. size = regerror(result, regex, NULL, 0);
  232. rval = malloc(size);
  233. regerror(result, regex, rval, size);
  234. return rval;
  235. }
  236. static gboolean
  237. handle_device_regex(const char * user_name, char ** driver_name,
  238. char ** device) {
  239. regex_t regex;
  240. int reg_result;
  241. regmatch_t pmatch[3];
  242. static const char * regex_string = "^([a-z0-9]+):(.*)$";
  243. bzero(&regex, sizeof(regex));
  244. reg_result = regcomp(&regex, regex_string, REG_EXTENDED | REG_ICASE);
  245. if (reg_result != 0) {
  246. char * message = regex_message(reg_result, &regex);
  247. g_fprintf(stderr, "Error compiling regular expression \"%s\": %s\n",
  248. regex_string, message);
  249. amfree(message);
  250. return FALSE;
  251. }
  252. reg_result = regexec(&regex, user_name, 3, pmatch, 0);
  253. if (reg_result != 0 && reg_result != REG_NOMATCH) {
  254. char * message = regex_message(reg_result, &regex);
  255. g_fprintf(stderr, "Error applying regular expression \"%s\" to string \"%s\":\n"
  256. "%s\n", user_name, regex_string, message);
  257. regfree(&regex);
  258. return FALSE;
  259. } else if (reg_result == REG_NOMATCH) {
  260. #ifdef WANT_TAPE_DEVICE
  261. g_fprintf(stderr, "\"%s\" uses deprecated device naming convention; \n"
  262. "using \"tape:%s\" instead.\n",
  263. user_name, user_name);
  264. *driver_name = stralloc("tape");
  265. *device = stralloc(user_name);
  266. #else /* !WANT_TAPE_DEVICE */
  267. g_fprintf(stderr, "\"%s\" is not a valid device name.\n", user_name);
  268. regfree(&regex);
  269. return FALSE;
  270. #endif /* WANT_TAPE_DEVICE */
  271. } else {
  272. *driver_name = find_regex_substring(user_name, pmatch[1]);
  273. *device = find_regex_substring(user_name, pmatch[2]);
  274. }
  275. regfree(&regex);
  276. return TRUE;
  277. }
  278. Device*
  279. device_open (char * device_name)
  280. {
  281. char *device_driver_name = NULL;
  282. char *device_node_name = NULL;
  283. DeviceFactory factory;
  284. Device *device;
  285. g_return_val_if_fail (device_name != NULL, NULL);
  286. if (driverList == NULL) {
  287. g_log(G_LOG_DOMAIN, G_LOG_LEVEL_ERROR,
  288. "device_open() called without device_api_init()!\n");
  289. g_assert_not_reached();
  290. }
  291. if (!handle_device_regex(device_name, &device_driver_name, &device_node_name)) {
  292. amfree(device_driver_name);
  293. amfree(device_node_name);
  294. return NULL;
  295. }
  296. factory = lookup_device_factory(device_driver_name);
  297. if (factory == NULL) {
  298. g_fprintf(stderr, "Device driver %s is not known.\n",
  299. device_driver_name);
  300. amfree(device_driver_name);
  301. amfree(device_node_name);
  302. return NULL;
  303. }
  304. device = factory(device_driver_name, device_node_name);
  305. amfree(device_driver_name);
  306. amfree(device_node_name);
  307. return device;
  308. }
  309. void
  310. device_add_property (Device * self, DeviceProperty * prop, GValue * response)
  311. {
  312. unsigned int i;
  313. g_return_if_fail (self != NULL);
  314. g_return_if_fail (IS_DEVICE (self));
  315. g_assert(selfp->property_list != NULL);
  316. g_assert(selfp->property_response != NULL);
  317. /* Delete it if it already exists. */
  318. for(i = 0; i < selfp->property_list->len; i ++) {
  319. if (g_array_index(selfp->property_list,
  320. DeviceProperty, i).base->ID == prop->base->ID) {
  321. g_array_remove_index_fast(selfp->property_list, i);
  322. break;
  323. }
  324. }
  325. g_array_append_val(selfp->property_list, *prop);
  326. if (response != NULL) {
  327. PropertyResponse * property_response;
  328. g_return_if_fail(G_IS_VALUE(response));
  329. property_response = malloc(sizeof(*property_response));
  330. property_response->access = prop->access;
  331. bzero(&(property_response->response),
  332. sizeof(property_response->response));
  333. g_value_init(&(property_response->response),
  334. G_VALUE_TYPE(response));
  335. g_value_copy(response, &(property_response->response));
  336. g_hash_table_insert(selfp->property_response,
  337. GINT_TO_POINTER(prop->base->ID),
  338. property_response);
  339. }
  340. }
  341. const DeviceProperty *
  342. device_property_get_list (Device * self)
  343. {
  344. g_return_val_if_fail (self != NULL, (const DeviceProperty * )0);
  345. g_return_val_if_fail (IS_DEVICE (self), (const DeviceProperty * )0);
  346. return (const DeviceProperty*) selfp->property_list->data;
  347. }
  348. guint device_write_min_size(Device * self) {
  349. GValue g_tmp;
  350. int block_size, min_block_size;
  351. bzero(&g_tmp, sizeof(g_tmp));
  352. device_property_get(self, PROPERTY_BLOCK_SIZE, &g_tmp);
  353. block_size = g_value_get_int(&g_tmp);
  354. g_value_unset(&g_tmp);
  355. if (block_size > 0) {
  356. return block_size;
  357. }
  358. /* variable block size */
  359. device_property_get(self, PROPERTY_MIN_BLOCK_SIZE, &g_tmp);
  360. min_block_size = g_value_get_uint(&g_tmp);
  361. g_value_unset(&g_tmp);
  362. return min_block_size;
  363. }
  364. guint device_write_max_size(Device * self) {
  365. GValue g_tmp;
  366. int block_size, max_block_size;
  367. bzero(&g_tmp, sizeof(g_tmp));
  368. device_property_get(self, PROPERTY_BLOCK_SIZE, &g_tmp);
  369. block_size = g_value_get_int(&g_tmp);
  370. g_value_unset(&g_tmp);
  371. if (block_size > 0) {
  372. return block_size;
  373. }
  374. /* variable block size */
  375. device_property_get(self, PROPERTY_MAX_BLOCK_SIZE, &g_tmp);
  376. max_block_size = g_value_get_uint(&g_tmp);
  377. g_value_unset(&g_tmp);
  378. return max_block_size;
  379. }
  380. guint device_read_max_size(Device * self) {
  381. GValue g_tmp;
  382. bzero(&g_tmp, sizeof(g_tmp));
  383. if (device_property_get(self, PROPERTY_READ_BUFFER_SIZE, &g_tmp)) {
  384. guint rval = g_value_get_uint(&g_tmp);
  385. g_value_unset(&g_tmp);
  386. return rval;
  387. } else {
  388. return device_write_max_size(self);
  389. }
  390. }
  391. char * device_build_amanda_header(Device * self, const dumpfile_t * info,
  392. int * size, gboolean * oneblock) {
  393. char *amanda_header;
  394. unsigned int min_header_length;
  395. unsigned int header_buffer_size;
  396. min_header_length = device_write_min_size(self);
  397. amanda_header = build_header(info, min_header_length);
  398. header_buffer_size = MAX(min_header_length, strlen(amanda_header)+1);
  399. if (size != NULL)
  400. *size = header_buffer_size;
  401. if (oneblock != NULL)
  402. *oneblock = (header_buffer_size <= device_write_max_size(self));
  403. return amanda_header;
  404. }
  405. dumpfile_t * make_tapestart_header(Device * self, char * label,
  406. char * timestamp) {
  407. dumpfile_t * rval;
  408. g_return_val_if_fail(label != NULL, NULL);
  409. rval = malloc(sizeof(*rval));
  410. fh_init(rval);
  411. rval->type = F_TAPESTART;
  412. amfree(self->volume_time);
  413. if (get_timestamp_state(timestamp) == TIME_STATE_REPLACE) {
  414. self->volume_time = get_proper_stamp_from_time(time(NULL));
  415. } else {
  416. self->volume_time = g_strdup(timestamp);
  417. }
  418. strncpy(rval->datestamp, self->volume_time, sizeof(rval->datestamp));
  419. strncpy(rval->name, label, sizeof(rval->name));
  420. return rval;
  421. }
  422. dumpfile_t * make_tapeend_header(void) {
  423. dumpfile_t * rval;
  424. char * timestamp;
  425. rval = malloc(sizeof(*rval));
  426. rval->type = F_TAPEEND;
  427. timestamp = get_timestamp_from_time(time(NULL));
  428. strncpy(rval->datestamp, timestamp, sizeof(rval->datestamp));
  429. amfree(timestamp);
  430. return rval;
  431. }
  432. /* Try setting max/fixed blocksize on a device. Check results, fallback, and
  433. * print messages for problems. */
  434. static void try_set_blocksize(Device * device, guint blocksize,
  435. gboolean try_max_first) {
  436. GValue val;
  437. gboolean success;
  438. bzero(&val, sizeof(val));
  439. g_value_init(&val, G_TYPE_UINT);
  440. g_value_set_uint(&val, blocksize);
  441. if (try_max_first) {
  442. success = device_property_set(device,
  443. PROPERTY_MAX_BLOCK_SIZE,
  444. &val);
  445. if (!success) {
  446. g_fprintf(stderr, "Setting MAX_BLOCK_SIZE to %u "
  447. "not supported for device %s.\n"
  448. "trying BLOCK_SIZE instead.\n",
  449. blocksize, device->device_name);
  450. } else {
  451. g_value_unset(&val);
  452. return;
  453. }
  454. }
  455. g_value_unset(&val);
  456. g_value_init(&val, G_TYPE_INT);
  457. g_value_set_int(&val, blocksize);
  458. success = device_property_set(device,
  459. PROPERTY_BLOCK_SIZE,
  460. &val);
  461. if (!success) {
  462. g_fprintf(stderr, "Setting BLOCK_SIZE to %u "
  463. "not supported for device %s.\n",
  464. blocksize, device->device_name);
  465. }
  466. g_value_unset(&val);
  467. }
  468. /* A GHFunc (callback for g_hash_table_foreach) */
  469. static void set_device_property(gpointer key_p, gpointer value_p,
  470. gpointer user_data_p) {
  471. char * property_s = key_p;
  472. char * value_s = value_p;
  473. Device * device = user_data_p;
  474. const DevicePropertyBase* property_base;
  475. GValue property_value;
  476. g_return_if_fail(IS_DEVICE(device));
  477. g_return_if_fail(property_s != NULL);
  478. g_return_if_fail(value_s != NULL);
  479. property_base = device_property_get_by_name(property_s);
  480. if (property_base == NULL) {
  481. /* Nonexistant property name. */
  482. g_fprintf(stderr, _("Unknown device property name %s.\n"), property_s);
  483. return;
  484. }
  485. bzero(&property_value, sizeof(property_value));
  486. g_value_init(&property_value, property_base->type);
  487. if (!g_value_set_from_string(&property_value, value_s)) {
  488. /* Value type could not be interpreted. */
  489. g_fprintf(stderr,
  490. _("Could not parse property value %s for property type %s.\n"),
  491. value_s, g_type_name(property_base->type));
  492. return;
  493. } else {
  494. g_assert (G_VALUE_HOLDS(&property_value, property_base->type));
  495. }
  496. if (!device_property_set(device, property_base->ID, &property_value)) {
  497. /* Device rejects property. */
  498. g_fprintf(stderr, _("Could not set property %s to %s on device %s.\n"),
  499. property_base->name, value_s, device->device_name);
  500. return;
  501. }
  502. }
  503. /* Set up first-run properties, including DEVICE_MAX_VOLUME_USAGE property
  504. * based on the tapetype. */
  505. void device_set_startup_properties_from_config(Device * device) {
  506. char * tapetype_name = getconf_str(CNF_TAPETYPE);
  507. if (tapetype_name != NULL) {
  508. tapetype_t * tapetype = lookup_tapetype(tapetype_name);
  509. if (tapetype != NULL) {
  510. GValue val;
  511. guint64 length;
  512. guint blocksize_kb;
  513. gboolean success;
  514. bzero(&val, sizeof(GValue));
  515. if (tapetype_seen(tapetype, TAPETYPE_LENGTH)) {
  516. length = tapetype_get_length(tapetype);
  517. g_value_init(&val, G_TYPE_UINT64);
  518. g_value_set_uint64(&val, length * 1024);
  519. /* If this fails, it's not really an error. */
  520. device_property_set(device, PROPERTY_MAX_VOLUME_USAGE, &val);
  521. g_value_unset(&val);
  522. }
  523. if (tapetype_seen(tapetype, TAPETYPE_READBLOCKSIZE)) {
  524. blocksize_kb = tapetype_get_readblocksize(tapetype);
  525. g_value_init(&val, G_TYPE_UINT);
  526. g_value_set_uint(&val, blocksize_kb * 1024);
  527. success = device_property_set(device,
  528. PROPERTY_READ_BUFFER_SIZE,
  529. &val);
  530. g_value_unset(&val);
  531. if (!success) {
  532. g_fprintf(stderr, "Setting READ_BUFFER_SIZE to %llu "
  533. "not supported for device %s.\n",
  534. 1024*(long long unsigned int)blocksize_kb,
  535. device->device_name);
  536. }
  537. }
  538. if (tapetype_seen(tapetype, TAPETYPE_BLOCKSIZE)) {
  539. blocksize_kb = tapetype_get_blocksize(tapetype);
  540. try_set_blocksize(device, blocksize_kb * 1024,
  541. !tapetype_get_file_pad(tapetype));
  542. }
  543. }
  544. }
  545. g_hash_table_foreach(getconf_proplist(CNF_DEVICE_PROPERTY),
  546. set_device_property, device);
  547. }
  548. void device_clear_volume_details(Device * device) {
  549. if (device == NULL || device->access_mode != ACCESS_NULL) {
  550. return;
  551. }
  552. amfree(device->volume_label);
  553. amfree(device->volume_time);
  554. }
  555. /* Here we put default implementations of virtual functions. Since
  556. this class is virtual, many of these functions offer at best
  557. incomplete functionality. But they do offer the useful commonality
  558. that all devices can expect to need. */
  559. /* This function only updates access_mode, volume_label, and volume_time. */
  560. static gboolean
  561. default_device_start (Device * self, DeviceAccessMode mode, char * label,
  562. char * timestamp) {
  563. if (mode != ACCESS_WRITE && self->volume_label == NULL) {
  564. g_debug("default_device_start calling device_read_label with mode %d", mode);
  565. if (device_read_label(self) != READ_LABEL_STATUS_SUCCESS)
  566. return FALSE;
  567. } else if (mode == ACCESS_WRITE) {
  568. self->volume_label = newstralloc(self->volume_label, label);
  569. self->volume_time = newstralloc(self->volume_time, timestamp);
  570. }
  571. self->access_mode = mode;
  572. return TRUE;
  573. }
  574. static gboolean default_device_open_device(Device * self,
  575. char * device_name) {
  576. DeviceProperty prop;
  577. guint i;
  578. self->device_name = stralloc(device_name);
  579. prop.base = &device_property_canonical_name;
  580. prop.access = PROPERTY_ACCESS_GET_MASK;
  581. for(i = 0; i < selfp->property_list->len; i ++) {
  582. if (g_array_index(selfp->property_list,
  583. DeviceProperty, i).base->ID == prop.base->ID) {
  584. return TRUE;
  585. }
  586. }
  587. /* If we got here, the property was not registered. */
  588. device_add_property(self, &prop, NULL);
  589. return TRUE;
  590. }
  591. /* This default implementation does very little. */
  592. static gboolean
  593. default_device_finish (Device * self) {
  594. self->access_mode = ACCESS_NULL;
  595. return TRUE;
  596. }
  597. /* This function updates the file, in_file, and block attributes. */
  598. static gboolean
  599. default_device_start_file (Device * self,
  600. const dumpfile_t * jobInfo G_GNUC_UNUSED) {
  601. self->in_file = TRUE;
  602. if (self->file <= 0)
  603. self->file = 1;
  604. else
  605. self->file ++;
  606. self->block = 0;
  607. return TRUE;
  608. }
  609. /* This function lies: It updates the block number and maybe calls
  610. device_finish_file(), but returns FALSE. */
  611. static gboolean
  612. default_device_write_block(Device * self, guint size G_GNUC_UNUSED,
  613. gpointer data G_GNUC_UNUSED, gboolean last_block) {
  614. self->block ++;
  615. if (last_block)
  616. device_finish_file(self);
  617. return FALSE;
  618. }
  619. /* This function lies: It updates the block number, but returns
  620. -1. */
  621. static int
  622. default_device_read_block(Device * self, gpointer buf G_GNUC_UNUSED,
  623. int * size G_GNUC_UNUSED) {
  624. self->block ++;
  625. return -1;
  626. }
  627. /* This function just updates the in_file field. */
  628. static gboolean
  629. default_device_finish_file(Device * self) {
  630. self->in_file = FALSE;
  631. return TRUE;
  632. }
  633. /* This function just updates the file number. */
  634. static dumpfile_t *
  635. default_device_seek_file(Device * self, guint file) {
  636. self->in_file = TRUE;
  637. self->file = file;
  638. return NULL;
  639. }
  640. /* This function just updates the block number. */
  641. static gboolean
  642. default_device_seek_block(Device * self, guint64 block) {
  643. self->block = block;
  644. return TRUE;
  645. }
  646. /* This default implementation serves up static responses, and
  647. implements a default response to the "canonical name" property. */
  648. static gboolean
  649. default_device_property_get(Device * self, DevicePropertyId ID,
  650. GValue * value) {
  651. const PropertyResponse * resp;
  652. resp = (PropertyResponse*)g_hash_table_lookup(selfp->property_response,
  653. GINT_TO_POINTER(ID));
  654. if (resp == NULL) {
  655. if (ID == PROPERTY_CANONICAL_NAME) {
  656. g_value_unset_init(value, G_TYPE_STRING);
  657. g_value_set_string(value, self->device_name);
  658. return TRUE;
  659. } else {
  660. return FALSE;
  661. }
  662. }
  663. g_value_unset_copy(&resp->response, value);
  664. return TRUE;
  665. }
  666. static gboolean
  667. default_device_read_to_fd(Device *self, int fd) {
  668. GValue val;
  669. StreamingRequirement streaming_mode;
  670. /* Get the device's parameters */
  671. bzero(&val, sizeof(val));
  672. if (!device_property_get(self, PROPERTY_STREAMING, &val)
  673. || !G_VALUE_HOLDS(&val, STREAMING_REQUIREMENT_TYPE)) {
  674. streaming_mode = STREAMING_REQUIREMENT_REQUIRED;
  675. } else {
  676. streaming_mode = g_value_get_enum(&val);
  677. }
  678. return QUEUE_SUCCESS ==
  679. do_consumer_producer_queue_full(
  680. device_read_producer,
  681. self,
  682. fd_write_consumer,
  683. GINT_TO_POINTER(fd),
  684. device_read_max_size(self),
  685. DEFAULT_MAX_BUFFER_MEMORY,
  686. streaming_mode);
  687. }
  688. static gboolean
  689. default_device_write_from_fd(Device *self, int fd) {
  690. GValue val;
  691. StreamingRequirement streaming_mode;
  692. /* Get the device's parameters */
  693. bzero(&val, sizeof(val));
  694. if (!device_property_get(self, PROPERTY_STREAMING, &val)
  695. || !G_VALUE_HOLDS(&val, STREAMING_REQUIREMENT_TYPE)) {
  696. streaming_mode = STREAMING_REQUIREMENT_REQUIRED;
  697. } else {
  698. streaming_mode = g_value_get_enum(&val);
  699. }
  700. return QUEUE_SUCCESS ==
  701. do_consumer_producer_queue_full(
  702. fd_read_producer,
  703. GINT_TO_POINTER(fd),
  704. device_write_consumer,
  705. self,
  706. device_write_max_size(self),
  707. DEFAULT_MAX_BUFFER_MEMORY,
  708. streaming_mode);
  709. }
  710. /* XXX WARNING XXX
  711. * All the functions below this comment are stub functions that do nothing
  712. * but implement the virtual function table. Call these functions and they
  713. * will do what you expect vis-a-vis virtual functions. But don't put code
  714. * in them beyond error checking and VFT lookup. */
  715. gboolean
  716. device_open_device (Device * self, char * device_name)
  717. {
  718. DeviceClass *klass;
  719. g_return_val_if_fail (self != NULL, FALSE);
  720. g_return_val_if_fail (IS_DEVICE (self), FALSE);
  721. g_return_val_if_fail (device_name != NULL, FALSE);
  722. klass = DEVICE_GET_CLASS(self);
  723. if(klass->open_device)
  724. return (*klass->open_device)(self,device_name);
  725. else
  726. return FALSE;
  727. }
  728. ReadLabelStatusFlags device_read_label(Device * self) {
  729. DeviceClass * klass;
  730. g_debug("device_read_label; mode = %d", self->access_mode);
  731. g_return_val_if_fail(self != NULL, FALSE);
  732. g_return_val_if_fail(IS_DEVICE(self), FALSE);
  733. g_return_val_if_fail(self->access_mode == ACCESS_NULL, FALSE);
  734. klass = DEVICE_GET_CLASS(self);
  735. if (klass->read_label) {
  736. return (klass->read_label)(self);
  737. } else {
  738. return ~ READ_LABEL_STATUS_SUCCESS;
  739. }
  740. }
  741. gboolean
  742. device_finish (Device * self) {
  743. DeviceClass *klass;
  744. g_return_val_if_fail (self != NULL, FALSE);
  745. g_return_val_if_fail (IS_DEVICE (self), FALSE);
  746. if (self->access_mode == ACCESS_NULL)
  747. return TRUE;
  748. klass = DEVICE_GET_CLASS(self);
  749. if (klass->finish) {
  750. return (*klass->finish)(self);
  751. } else {
  752. return FALSE;
  753. }
  754. }
  755. /* For a good combination of synchronization and public simplicity,
  756. this stub function does not take a timestamp, but the actual
  757. implementation function does. We generate the timestamp here with
  758. time(). */
  759. gboolean
  760. device_start (Device * self, DeviceAccessMode mode,
  761. char * label, char * timestamp)
  762. {
  763. DeviceClass *klass;
  764. g_debug("device_start mode = %d", mode);
  765. g_return_val_if_fail (self != NULL, FALSE);
  766. g_return_val_if_fail (IS_DEVICE (self), FALSE);
  767. g_return_val_if_fail (mode != ACCESS_NULL, FALSE);
  768. g_return_val_if_fail (mode != ACCESS_WRITE || label != NULL,
  769. FALSE);
  770. klass = DEVICE_GET_CLASS(self);
  771. if(klass->start) {
  772. char * local_timestamp = NULL;
  773. gboolean rv;
  774. /* fill in a timestamp if none was given */
  775. if (mode == ACCESS_WRITE &&
  776. get_timestamp_state(timestamp) == TIME_STATE_REPLACE) {
  777. local_timestamp = timestamp =
  778. get_proper_stamp_from_time(time(NULL));
  779. }
  780. rv = (*klass->start)(self, mode, label, timestamp);
  781. amfree(local_timestamp);
  782. g_debug("device_start done; dev->access_mode = %d, result %d", self->access_mode, rv);
  783. return rv;
  784. } else {
  785. return FALSE;
  786. }
  787. }
  788. gboolean
  789. device_write_block (Device * self, guint size, gpointer block,
  790. gboolean short_block)
  791. {
  792. DeviceClass *klass;
  793. g_return_val_if_fail (self != NULL, FALSE);
  794. g_return_val_if_fail (IS_DEVICE (self), FALSE);
  795. g_return_val_if_fail (size > 0, FALSE);
  796. g_return_val_if_fail (short_block ||
  797. size >= device_write_min_size(self), FALSE);
  798. g_return_val_if_fail (size <= device_write_max_size(self), FALSE);
  799. g_return_val_if_fail (block != NULL, FALSE);
  800. g_return_val_if_fail (IS_WRITABLE_ACCESS_MODE(self->access_mode),
  801. FALSE);
  802. klass = DEVICE_GET_CLASS(self);
  803. if(klass->write_block)
  804. return (*klass->write_block)(self,size, block, short_block);
  805. else
  806. return FALSE;
  807. }
  808. gboolean
  809. device_write_from_fd (Device * self, int fd)
  810. {
  811. DeviceClass *klass;
  812. g_return_val_if_fail (self != NULL, FALSE);
  813. g_return_val_if_fail (IS_DEVICE (self), FALSE);
  814. g_return_val_if_fail (fd >= 0, FALSE);
  815. g_return_val_if_fail (IS_WRITABLE_ACCESS_MODE(self->access_mode),
  816. FALSE);
  817. klass = DEVICE_GET_CLASS(self);
  818. if(klass->write_from_fd)
  819. return (*klass->write_from_fd)(self,fd);
  820. else
  821. return FALSE;
  822. }
  823. gboolean
  824. device_start_file (Device * self, const dumpfile_t * jobInfo) {
  825. DeviceClass * klass;
  826. g_return_val_if_fail (self != NULL, FALSE);
  827. g_return_val_if_fail (IS_DEVICE (self), FALSE);
  828. g_return_val_if_fail (!(self->in_file), FALSE);
  829. g_return_val_if_fail (jobInfo != NULL, FALSE);
  830. klass = DEVICE_GET_CLASS(self);
  831. if(klass->start_file)
  832. return (*klass->start_file)(self, jobInfo );
  833. else
  834. return FALSE;
  835. }
  836. gboolean
  837. device_finish_file (Device * self)
  838. {
  839. DeviceClass *klass;
  840. g_return_val_if_fail (self != NULL, FALSE);
  841. g_return_val_if_fail (IS_DEVICE (self), FALSE);
  842. g_return_val_if_fail (IS_WRITABLE_ACCESS_MODE(self->access_mode),
  843. FALSE);
  844. g_return_val_if_fail (self->in_file, FALSE);
  845. klass = DEVICE_GET_CLASS(self);
  846. if(klass->finish_file)
  847. return (*klass->finish_file)(self);
  848. else
  849. return FALSE;
  850. }
  851. dumpfile_t*
  852. device_seek_file (Device * self, guint file)
  853. {
  854. DeviceClass *klass;
  855. g_return_val_if_fail (self != NULL, NULL);
  856. g_return_val_if_fail (IS_DEVICE (self), NULL);
  857. g_return_val_if_fail (self->access_mode == ACCESS_READ,
  858. NULL);
  859. klass = DEVICE_GET_CLASS(self);
  860. if(klass->seek_file)
  861. return (*klass->seek_file)(self,file);
  862. else
  863. return FALSE;
  864. }
  865. gboolean
  866. device_seek_block (Device * self, guint64 block)
  867. {
  868. DeviceClass *klass;
  869. g_return_val_if_fail (self != NULL, FALSE);
  870. g_return_val_if_fail (IS_DEVICE (self), FALSE);
  871. g_return_val_if_fail (self->access_mode == ACCESS_READ,
  872. FALSE);
  873. g_return_val_if_fail (self->in_file, FALSE);
  874. klass = DEVICE_GET_CLASS(self);
  875. if(klass->seek_block)
  876. return (*klass->seek_block)(self,block);
  877. else
  878. return FALSE;
  879. }
  880. int
  881. device_read_block (Device * self, gpointer buffer, int * size)
  882. {
  883. DeviceClass *klass;
  884. g_return_val_if_fail (self != NULL, -1);
  885. g_return_val_if_fail (IS_DEVICE (self), -1);
  886. g_return_val_if_fail (size != NULL, -1);
  887. g_return_val_if_fail (self->access_mode == ACCESS_READ, -1);
  888. if (*size != 0) {
  889. g_return_val_if_fail (buffer != NULL, -1);
  890. }
  891. /* Do a quick check here, so fixed-block subclasses don't have to. */
  892. if (*size == 0 &&
  893. device_write_min_size(self) == device_write_max_size(self)) {
  894. *size = device_write_min_size(self);
  895. return 0;
  896. }
  897. klass = DEVICE_GET_CLASS(self);
  898. if(klass->read_block)
  899. return (*klass->read_block)(self,buffer,size);
  900. else
  901. return -1;
  902. }
  903. gboolean
  904. device_read_to_fd (Device * self, int fd)
  905. {
  906. DeviceClass *klass;
  907. g_return_val_if_fail (self != NULL, FALSE);
  908. g_return_val_if_fail (IS_DEVICE (self), FALSE);
  909. g_return_val_if_fail (fd >= 0, FALSE);
  910. g_return_val_if_fail (self->access_mode == ACCESS_READ, FALSE);
  911. klass = DEVICE_GET_CLASS(self);
  912. if(klass->read_to_fd)
  913. return (*klass->read_to_fd)(self,fd);
  914. else
  915. return FALSE;
  916. }
  917. gboolean
  918. device_property_get (Device * self, DevicePropertyId id, GValue * val)
  919. {
  920. DeviceClass *klass;
  921. g_return_val_if_fail (self != NULL, FALSE);
  922. g_return_val_if_fail (IS_DEVICE (self), FALSE);
  923. g_return_val_if_fail (device_property_get_by_id(id) != NULL, FALSE);
  924. klass = DEVICE_GET_CLASS(self);
  925. /* FIXME: Check access flags? */
  926. if(klass->property_get)
  927. return (*klass->property_get)(self,id,val);
  928. else
  929. return FALSE;
  930. }
  931. gboolean
  932. device_property_set (Device * self, DevicePropertyId id, GValue * val)
  933. {
  934. DeviceClass *klass;
  935. g_return_val_if_fail (self != NULL, FALSE);
  936. g_return_val_if_fail (IS_DEVICE (self), FALSE);
  937. klass = DEVICE_GET_CLASS(self);
  938. /* FIXME: Check access flags? */
  939. if(klass->property_set)
  940. return (*klass->property_set)(self,id,val);
  941. else
  942. return FALSE;
  943. }
  944. gboolean
  945. device_recycle_file (Device * self, guint filenum)
  946. {
  947. DeviceClass *klass;
  948. g_return_val_if_fail (self != NULL, FALSE);
  949. g_return_val_if_fail (IS_DEVICE (self), FALSE);
  950. g_return_val_if_fail (self->access_mode == ACCESS_APPEND, FALSE);
  951. klass = DEVICE_GET_CLASS(self);
  952. if(klass->recycle_file)
  953. return (*klass->recycle_file)(self,filenum);
  954. else
  955. return FALSE;
  956. }