void pfinet_bind (int portclass, const char *name) { struct trivfs_control *cntl; error_t err = 0; mach_port_t right; file_t file = file_name_lookup (name, O_CREAT|O_NOTRANS, 0666); if (file == MACH_PORT_NULL) err = errno; if (! err) { if (pfinet_protid_portclasses[portclass] != MACH_PORT_NULL) error (1, 0, "Cannot bind one protocol to multiple nodes.\n"); #ifdef CONFIG_IPV6 if (portclass == PORTCLASS_INET6) pfinet_activate_ipv6 (); #endif //mark err = trivfs_add_protid_port_class (&pfinet_protid_portclasses[portclass]); if (err) error (1, 0, "error creating control port class"); err = trivfs_add_control_port_class (&pfinet_cntl_portclasses[portclass]); if (err) error (1, 0, "error creating control port class"); err = trivfs_create_control (file, pfinet_cntl_portclasses[portclass], pfinet_bucket, pfinet_protid_portclasses[portclass], pfinet_bucket, &cntl); } if (! err) { right = ports_get_send_right (cntl); err = file_set_translator (file, 0, FS_TRANS_EXCL | FS_TRANS_SET, 0, 0, 0, right, MACH_MSG_TYPE_COPY_SEND); mach_port_deallocate (mach_task_self (), right); } if (err) error (1, err, "%s", name); ports_port_deref (cntl); }
/* Try and start the translator for CTL_PORT on NODE. If successful, this call will not return until the translator is stopped; otherwise it returns an error code describing the reason why it couldn't start. */ static error_t start_translator(file_t node, fsys_t ctl_port) { mach_port_t prev; error_t err = file_set_translator(node, 0, FS_TRANS_EXCL, 0, NULL, 0, ctl_port); if (err) return err; /* Set up a watch on the process we're interested in. */ err = mach_port_request_notification(mach_task_self(), watched_process, MACH_NOTIFY_DEAD_NAME, 1, node, MACH_MSG_TYPE_MAKE_SEND_ONCE, &prev); if (prev) mach_port_deallocate(mach_task_self(), prev); /* Boogie. */ ports_manage_port_operations_onethread(); return 0; }
/* Unmount one filesystem. */ static error_t do_umount (struct fs *fs) { error_t err = 0; file_t node = file_name_lookup (fs->mntent.mnt_dir, O_NOTRANS, 0666); if (node == MACH_PORT_NULL) { error (0, errno, "%s", fs->mntent.mnt_dir); return errno; } if (verbose) printf ("settrans -ag%s%s %s\n", goaway_flags & FSYS_GOAWAY_NOSYNC? "S": "", goaway_flags & FSYS_GOAWAY_FORCE? "f": "", fs->mntent.mnt_dir); if (! fake) { err = file_set_translator (node, 0, active_flags, goaway_flags, NULL, 0, MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND); if (! err) { if (strcmp (fs->mntent.mnt_fsname, "") != 0 && strcmp (fs->mntent.mnt_fsname, "none") != 0) { if (verbose) printf ("settrans -ag%s%s %s\n", goaway_flags & FSYS_GOAWAY_NOSYNC? "S": "", goaway_flags & FSYS_GOAWAY_FORCE? "f": "", fs->mntent.mnt_fsname); file_t source = file_name_lookup (fs->mntent.mnt_fsname, O_NOTRANS, 0666); if (source == MACH_PORT_NULL) { error (0, errno, "%s", fs->mntent.mnt_fsname); return errno; } err = file_set_translator (source, 0, active_flags, goaway_flags, NULL, 0, MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND); if (!(goaway_flags & FSYS_GOAWAY_FORCE)) err = 0; if (err) error (0, err, "%s", fs->mntent.mnt_fsname); mach_port_deallocate (mach_task_self (), source); } } else { error (0, err, "%s", fs->mntent.mnt_dir); /* Try remounting readonly instead if requested. */ if (readonly) { if (verbose) printf ("fsysopts %s --readonly\n", fs->mntent.mnt_dir); error_t e = fs_set_readonly (fs, TRUE); if (e) error (0, e, "%s", fs->mntent.mnt_dir); } } } /* Deallocate the reference so that unmounting nested translators works properly. */ mach_port_deallocate (mach_task_self (), node); return err; }
/* Mount one filesystem. */ static error_t do_mount (struct fs *fs, int remount) { error_t err; char *fsopts, *o; size_t fsopts_len; char *mntopts; size_t mntopts_len; fsys_t mounted; inline void explain (const char *command) { if (verbose) { const char *o; printf ("%s %s", command, fs->mntent.mnt_dir); for (o = fsopts; o; o = argz_next (fsopts, fsopts_len, o)) printf (" %s", o); putchar ('\n'); } } err = fs_fsys (fs, &mounted); if (err) { error (0, err, "cannot determine if %s is already mounted", fs->mntent.mnt_fsname); return err; } /* Produce an argz of translator option arguments from the given FS's options and the command-line options. */ #define ARGZ(call) \ err = argz_##call; \ if (err) \ error (3, ENOMEM, "collecting mount options"); \ if (fs->mntent.mnt_opts) { /* Append the fstab options to any specified on the command line. */ ARGZ (create_sep (fs->mntent.mnt_opts, ',', &mntopts, &mntopts_len)); /* Remove the `noauto' and `bind' options, since they're for us not the filesystem. */ for (o = mntopts; o; o = argz_next (mntopts, mntopts_len, o)) { if (strcmp (o, MNTOPT_NOAUTO) == 0) argz_delete (&mntopts, &mntopts_len, o); if (strcmp (o, "bind") == 0) { fs->mntent.mnt_type = strdup ("firmlink"); if (!fs->mntent.mnt_type) error (3, ENOMEM, "failed to allocate memory"); argz_delete (&mntopts, &mntopts_len, o); } } ARGZ (append (&mntopts, &mntopts_len, options, options_len)); } else { mntopts = options; mntopts_len = options_len; } /* Convert the list of options into a list of switch arguments. */ fsopts = 0; fsopts_len = 0; for (o = mntopts; o; o = argz_next (mntopts, mntopts_len, o)) if (*o == '-') /* Allow letter opts `-o -r,-E', BSD style. */ { ARGZ (add (&fsopts, &fsopts_len, o)); } else if ((strcmp (o, "defaults") != 0) && (strlen (o) != 0)) { /* Prepend `--' to the option to make a long option switch, e.g. `--ro' or `--rsize=1024'. */ char arg[2 + strlen (o) + 1]; arg[0] = arg[1] = '-'; memcpy (&arg[2], o, sizeof arg - 2); ARGZ (add (&fsopts, &fsopts_len, arg)); } if (mntopts != options) free (mntopts); #undef ARGZ if (remount) { if (mounted == MACH_PORT_NULL) { error (0, 0, "%s not already mounted", fs->mntent.mnt_fsname); return EBUSY; } /* Send an RPC to request the new options, including --update. */ explain ("fsysopts"); err = fsys_set_options (mounted, fsopts, fsopts_len, 0); if (err) error (0, err, "cannot remount %s", fs->mntent.mnt_fsname); return err; } else { /* Error during file lookup; we use this to avoid duplicating error messages. */ error_t open_err = 0; /* The control port for any active translator we start up. */ fsys_t active_control; file_t node; /* Port to the underlying node. */ struct fstype *type; /* The callback to start_translator opens NODE as a side effect. */ error_t open_node (int flags, mach_port_t *underlying, mach_msg_type_name_t *underlying_type, task_t task, void *cookie) { node = file_name_lookup (fs->mntent.mnt_dir, flags | O_NOTRANS, 0666); if (node == MACH_PORT_NULL) { open_err = errno; return open_err; } *underlying = node; *underlying_type = MACH_MSG_TYPE_COPY_SEND; return 0; } /* Do not fail if there is an active translator if --fake is given. This mimics Linux mount utility more closely which just looks into the mtab file. */ if (mounted != MACH_PORT_NULL && !fake) { error (0, 0, "%s already mounted", fs->mntent.mnt_fsname); return EBUSY; } if (strcmp (fs->mntent.mnt_type, "auto") == 0) { #if HAVE_BLKID char *type = blkid_get_tag_value (NULL, "TYPE", fs->mntent.mnt_fsname); if (! type) { error (0, 0, "failed to detect file system type"); return EFTYPE; } else { if (strcmp (type, "vfat") == 0) fs->mntent.mnt_type = strdup ("fat"); else fs->mntent.mnt_type = strdup (type); if (! fs->mntent.mnt_type) error (3, ENOMEM, "failed to allocate memory"); } #else fs->mntent.mnt_type = strdup ("ext2"); if (! fs->mntent.mnt_type) error (3, ENOMEM, "failed to allocate memory"); #endif } err = fs_type (fs, &type); if (err) { error (0, err, "%s: cannot determine filesystem type", fs->mntent.mnt_fsname); return err; } if (type->program == 0) { error (0, 0, "%s: filesystem type `%s' unknown", fs->mntent.mnt_fsname, type->name); return EFTYPE; } /* Stick the translator program name in front of the option switches. */ err = argz_insert (&fsopts, &fsopts_len, fsopts, type->program); /* Now stick the device name on the end as the last argument. */ if (!err) err = argz_add (&fsopts, &fsopts_len, fs->mntent.mnt_fsname); if (err) error (3, ENOMEM, "collecting mount options"); /* Now we have a translator command line argz in FSOPTS. */ if (fake) { /* Fake the translator startup. */ mach_port_t underlying; mach_msg_type_name_t underlying_type; err = open_node (O_READ, &underlying, &underlying_type, 0, NULL); if (err) error (1, errno, "cannot mount on %s", fs->mntent.mnt_dir); mach_port_deallocate (mach_task_self (), underlying); /* See if the translator is at least executable. */ if (access(type->program, X_OK) == -1) error (1, errno, "can not execute %s", type->program); return 0; } explain ("settrans -a"); err = fshelp_start_translator (open_node, NULL, fsopts, fsopts, fsopts_len, timeout, &active_control); /* If ERR is due to a problem opening the translated node, we print that name, otherwise, the name of the translator. */ if (open_err) error (0, open_err, "cannot mount on %s", fs->mntent.mnt_dir); else if (err) error (0, err, "cannot start translator %s", fsopts); else { err = file_set_translator (node, 0, FS_TRANS_SET|FS_TRANS_EXCL, 0, 0, 0, active_control, MACH_MSG_TYPE_COPY_SEND); if (err == EBUSY) error (0, 0, "%s already mounted on", fs->mntent.mnt_dir); else if (err) error (0, err, "cannot set translator on %s", fs->mntent.mnt_dir); if (err) fsys_goaway (active_control, FSYS_GOAWAY_FORCE); mach_port_deallocate (mach_task_self (), active_control); } return err; }