+typedef struct jopen_cb_info {
+ off_t jsize;
+ char *desired_uuid;
+ struct vnode *jvp;
+ size_t blksize;
+ int need_clean;
+ int need_init;
+} jopen_cb_info;
+
+static int
+journal_open_cb(const char *bsd_dev_name, const char *uuid_str, void *arg)
+{
+ struct nameidata nd;
+ jopen_cb_info *ji = (jopen_cb_info *)arg;
+ char bsd_name[256];
+ int error;
+
+ strlcpy(&bsd_name[0], "/dev/", sizeof(bsd_name));
+ strlcpy(&bsd_name[5], bsd_dev_name, sizeof(bsd_name)-5);
+
+ if (ji->desired_uuid && ji->desired_uuid[0] && strcmp(uuid_str, ji->desired_uuid) != 0) {
+ return 1; // keep iterating
+ }
+
+ // if we're here, either the desired uuid matched or there was no
+ // desired uuid so let's try to open the device for writing and
+ // see if it works. if it does, we'll use it.
+
+ NDINIT(&nd, LOOKUP, LOCKLEAF, UIO_SYSSPACE32, CAST_USER_ADDR_T(bsd_name), vfs_context_kernel());
+ if ((error = namei(&nd))) {
+ printf("hfs: journal open cb: error %d looking up device %s (dev uuid %s)\n", error, bsd_name, uuid_str);
+ return 1; // keep iterating
+ }
+
+ ji->jvp = nd.ni_vp;
+ nameidone(&nd);
+
+ if (ji->jvp == NULL) {
+ printf("hfs: journal open cb: did not find %s (error %d)\n", bsd_name, error);
+ } else {
+ error = VNOP_OPEN(ji->jvp, FREAD|FWRITE, vfs_context_kernel());
+ if (error == 0) {
+ // if the journal is dirty and we didn't specify a desired
+ // journal device uuid, then do not use the journal. but
+ // if the journal is just invalid (e.g. it hasn't been
+ // initialized) then just set the need_init flag.
+ if (ji->need_clean && ji->desired_uuid && ji->desired_uuid[0] == '\0') {
+ error = journal_is_clean(ji->jvp, 0, ji->jsize, (void *)1, ji->blksize);
+ if (error == EBUSY) {
+ VNOP_CLOSE(ji->jvp, FREAD|FWRITE, vfs_context_kernel());
+ vnode_put(ji->jvp);
+ ji->jvp = NULL;
+ return 1; // keep iterating
+ } else if (error == EINVAL) {
+ ji->need_init = 1;
+ }
+ }
+
+ if (ji->desired_uuid && ji->desired_uuid[0] == '\0') {
+ strlcpy(ji->desired_uuid, uuid_str, 128);
+ }
+ vnode_setmountedon(ji->jvp);
+ // printf("hfs: journal open cb: got device %s (%s)\n", bsd_name, uuid_str);
+ return 0; // stop iterating
+ } else {
+ vnode_put(ji->jvp);
+ ji->jvp = NULL;
+ }
+ }
+
+ return 1; // keep iterating
+}
+
+extern dev_t IOBSDGetMediaWithUUID(const char *uuid_cstring, char *bsd_name, int bsd_name_len, int timeout);
+extern void IOBSDIterateMediaWithContent(const char *uuid_cstring, int (*func)(const char *bsd_dev_name, const char *uuid_str, void *arg), void *arg);
+extern kern_return_t IOBSDGetPlatformUUID(__darwin_uuid_t uuid, mach_timespec_t timeoutp);
+kern_return_t IOBSDGetPlatformSerialNumber(char *serial_number_str, u_int32_t len);
+
+
+static vnode_t
+open_journal_dev(const char *vol_device,
+ int need_clean,
+ char *uuid_str,
+ char *machine_serial_num,
+ off_t jsize,
+ size_t blksize,
+ int *need_init)
+{
+ int retry_counter=0;
+ jopen_cb_info ji;
+
+ ji.jsize = jsize;
+ ji.desired_uuid = uuid_str;
+ ji.jvp = NULL;
+ ji.blksize = blksize;
+ ji.need_clean = need_clean;
+ ji.need_init = 0;
+
+// if (uuid_str[0] == '\0') {
+// printf("hfs: open journal dev: %s: locating any available non-dirty external journal partition\n", vol_device);
+// } else {
+// printf("hfs: open journal dev: %s: trying to find the external journal partition w/uuid %s\n", vol_device, uuid_str);
+// }
+ while (ji.jvp == NULL && retry_counter++ < 4) {
+ if (retry_counter > 1) {
+ if (uuid_str[0]) {
+ printf("hfs: open_journal_dev: uuid %s not found. waiting 10sec.\n", uuid_str);
+ } else {
+ printf("hfs: open_journal_dev: no available external journal partition found. waiting 10sec.\n");
+ }
+ delay_for_interval(10* 1000000, NSEC_PER_USEC); // wait for ten seconds and then try again
+ }
+
+ IOBSDIterateMediaWithContent(EXTJNL_CONTENT_TYPE_UUID, journal_open_cb, &ji);
+ }
+
+ if (ji.jvp == NULL) {
+ printf("hfs: volume: %s: did not find jnl device uuid: %s from machine serial number: %s\n",
+ vol_device, uuid_str, machine_serial_num);
+ }
+
+ *need_init = ji.need_init;
+
+ return ji.jvp;
+}
+
+