.PP
\fBservice [-b -c -n -p -r] (up|run|edit|update)\fR \fI<binary|self>\fR
[\fB-args\fR \fI<args>\fR] [\fB-dev\fR \fI<special>\fR]
-[\fB-devstyle\fR \fI<style>\fR] [\fB-period\fR \fI<ticks>\fR]
+[\fB-period\fR \fI<ticks>\fR]
[\fB-script\fR \fI<path>\fR] [\fB-label\fR \fI<name>\fR]
[\fB-config\fR \fI<path>\fR] [\fB-state\fR \fI<state>\fR]
[\fB-maxtime\fR \fI<time>\fR]
specifies the device file to associate to the system service (used only for
device drivers). The default is to associate no device file to the service.
.TP
-.BI \-devstyle " <style>"
-specifies the device style to associate to the system service (used only for
-device drivers). The list of supported device styles is available in
-the header file \fB<minix/dmap.h>\fR.
-The default is to associate no device style (\fBSTYLE_NDEV\fR) to the service.
-.TP
.BI \-period " <ticks>"
specifies the period to use for the system service.
When a period is specified, \fBRS\fR sends a ping request to
properties of any system service, including those contained in the
boot image (e.g. \fBVM\fR). There are a few exceptions to the properties
that can be actually overridden dynamically. For example, the device file
-and the device style associated to the service will no be updated. This
+associated to the service will no be updated. This
action takes the same options supported by the \fBup\fR action.
.PP
.SS
#define ARG_ARGS "-args" /* list of arguments to be passed */
#define ARG_DEV "-dev" /* major device number for drivers */
#define ARG_MAJOR "-major" /* major number */
-#define ARG_DEVSTYLE "-devstyle" /* device style */
#define ARG_PERIOD "-period" /* heartbeat period in ticks */
#define ARG_SCRIPT "-script" /* name of the script to restart a
* system service
static char *req_args = "";
static int req_major = 0;
static int devman_id = 0;
-static int req_dev_style = STYLE_NDEV;
static long req_period = 0;
static char *req_script = NULL;
static char *req_config = PATH_CONFIG;
fprintf(stderr, "Warning, %s\n", problem);
fprintf(stderr, "Usage:\n");
fprintf(stderr,
- " %s [%s %s %s %s] (up|run|edit|update) <binary|%s> [%s <args>] [%s <special>] [%s <style>] [%s <major_nr>] [%s <dev_id>] [%s <ticks>] [%s <path>] [%s <name>] [%s <path>] [%s <state>] [%s <time>]\n",
+ " %s [%s %s %s %s] (up|run|edit|update) <binary|%s> [%s <args>] [%s <special>] [%s <major_nr>] [%s <dev_id>] [%s <ticks>] [%s <path>] [%s <name>] [%s <path>] [%s <state>] [%s <time>]\n",
app_name, OPT_COPY, OPT_REUSE, OPT_NOBLOCK, OPT_REPLICA, SELF_BINARY,
- ARG_ARGS, ARG_DEV, ARG_DEVSTYLE, ARG_MAJOR, ARG_DEVMANID, ARG_PERIOD, ARG_SCRIPT,
+ ARG_ARGS, ARG_DEV, ARG_MAJOR, ARG_DEVMANID, ARG_PERIOD, ARG_SCRIPT,
ARG_LABELNAME, ARG_CONFIG, ARG_LU_STATE, ARG_LU_MAXTIME);
fprintf(stderr, " %s down <label>\n", app_name);
fprintf(stderr, " %s refresh <label>\n", app_name);
exit(EINVAL);
}
req_major = major(stat_buf.st_rdev);
- if(req_dev_style == STYLE_NDEV) {
- req_dev_style = STYLE_DEV;
- }
}
else if (strcmp(argv[i], ARG_MAJOR)==0) {
if (req_major != 0) {
} else {
exit(EINVAL);
}
- if(req_dev_style == STYLE_NDEV) {
- req_dev_style = STYLE_DEV;
- }
}
- else if (strcmp(argv[i], ARG_DEVSTYLE)==0) {
- char* dev_style_keys[] = { "STYLE_DEV", "STYLE_TTY",
- "STYLE_CTTY", NULL };
- int dev_style_values[] = { STYLE_DEV, STYLE_TTY,
- STYLE_CTTY };
- for(j=0;dev_style_keys[j]!=NULL;j++) {
- if(!strcmp(dev_style_keys[j], argv[i+1])) {
- break;
- }
- }
- if(dev_style_keys[j] == NULL) {
- print_usage(argv[ARG_NAME], "bad device style");
- exit(EINVAL);
- }
- req_dev_style = dev_style_values[j];
- }
else if (strcmp(argv[i], ARG_SCRIPT)==0) {
req_script = argv[i+1];
}
config.rs_start.rss_cmd= command;
config.rs_start.rss_cmdlen= strlen(command);
config.rs_start.rss_major= req_major;
- config.rs_start.rss_dev_style= req_dev_style;
config.rs_start.rss_period= req_period;
config.rs_start.rss_script= req_script;
config.rs_start.devman_id= devman_id;
int getnprocnr(pid_t pid);
int getpprocnr(void);
int _pm_findproc(char *proc_name, int *proc_nr);
-int mapdriver(char *label, int major, int style, int flags);
+int mapdriver(char *label, int major);
pid_t getnpid(endpoint_t proc_ep);
uid_t getnuid(endpoint_t proc_ep);
gid_t getngid(endpoint_t proc_ep);
#define LU_SYS_PROC 0x400 /* this is a live updated sys proc instance */
#define RST_SYS_PROC 0x800 /* this is a restarted sys proc instance */
-/* Bits for device driver flags managed by RS and VFS. */
-#define DRV_FORCED 0x01 /* driver is mapped even if not alive yet */
-
/* Values for the "verbose" boot monitor variable */
#define VERBOSEBOOT_QUIET 0
#define VERBOSEBOOT_BASIC 1
#include <minix/sys_config.h>
#include <minix/ipc.h>
-enum dev_style { STYLE_NDEV, STYLE_DEV, STYLE_TTY, STYLE_CTTY };
-#define IS_DEV_STYLE(s) (s>=STYLE_NDEV && s<=STYLE_CTTY)
-
/*===========================================================================*
* Major and minor device numbers *
*===========================================================================*/
int rss_priority;
int rss_quantum;
int rss_major;
- int rss_dev_style;
long rss_period;
char *rss_script;
size_t rss_scriptlen;
unsigned sys_flags; /* sys flags */
endpoint_t endpoint; /* process endpoint number */
- int dev_flags; /* device flags */
- dev_t dev_nr; /* major device number */
- int dev_style; /* device style */
- int dev_style2; /* device style for next major dev number */
+ dev_t dev_nr; /* major device number or NO_DEV */
char label[RS_MAX_LABEL_LEN]; /* label of this service */
char proc_name[RS_MAX_LABEL_LEN]; /* process name of this service */
#include <unistd.h>
-int mapdriver(label, major, dev_style, flags)
+int mapdriver(label, major)
char *label;
int major;
-int dev_style;
-int flags;
{
message m;
m.m2_p1 = label;
m.m2_l1 = strlen(label);
m.m2_i1 = major;
- m.m2_i2 = dev_style;
- m.m2_i3 = flags;
if (_syscall(VFS_PROC_NR, MAPDRIVER, &m) < 0) return(-1);
return(0);
}
prev_i = i;
}
-/*===========================================================================*
- * dmap_flags *
- *===========================================================================*/
-static char * dmap_flags(int flags)
-{
- static char fl[10];
- strlcpy(fl, "-----", sizeof(fl));
- if(flags & DRV_FORCED) fl[0] = 'F';
- return fl;
-}
-
-/*===========================================================================*
- * dmap_style *
- *===========================================================================*/
-static char * dmap_style(int dev_style)
-{
- switch(dev_style) {
- case STYLE_DEV: return "STYLE_DEV";
- case STYLE_TTY: return "STYLE_TTY";
- case STYLE_CTTY: return "STYLE_CTTY";
- default: return "UNKNOWN";
- }
-}
-
/*===========================================================================*
* dtab_dmp *
*===========================================================================*/
}
printf("File System (FS) device <-> driver mappings\n");
- printf(" Label Major Driver ept Flags Style \n");
- printf("------------- ----- ---------- ----- -------------\n");
+ printf(" Label Major Driver ept\n");
+ printf("------------- ----- ----------\n");
for (i=0; i<NR_DEVICES; i++) {
if (dmap[i].dmap_driver == NONE) continue;
- printf("%13s %5d %10d %s %-13s\n",
- dmap[i].dmap_label, i, dmap[i].dmap_driver,
- dmap_flags(dmap[i].dmap_flags), dmap_style(dmap[i].dmap_style));
+ printf("%13s %5d %10d\n", dmap[i].dmap_label, i, dmap[i].dmap_driver);
}
}
-
rpub = &rprocpub[i];
if (! (rp->r_flags & RS_IN_USE)) continue;
if (++n > 22) break;
- printf("%13s %9d %5d %6s %3d/%1d %3ld %8lu %5dx %s",
+ printf("%13s %9d %5d %6s %4d %4ld %8lu %5dx %s",
rpub->label, rpub->endpoint, rp->r_pid,
s_flags_str(rp->r_flags, rpub->sys_flags), rpub->dev_nr,
- rpub->dev_style, rp->r_period, rp->r_alive_tm, rp->r_restarts,
+ rp->r_period, rp->r_alive_tm, rp->r_restarts,
rp->r_args
);
printf("\n");
#define DSRV_SF (0) /* dynamic system services */
#define VM_SF (SRVR_SF) /* vm */
-/* Define device flags for the various process types. */
-#define SRV_DF (DRV_FORCED) /* system services */
-#define DSRV_DF (SRV_DF) /* dynamic system services */
-
/* Shorthands. */
#define SRV_OR_USR(rp, X, Y) (rp->r_priv.s_flags & SYS_PROC ? X : Y)
/*
* Set dev properties.
*/
- rpub->dev_flags = boot_image_dev->flags; /* device flags */
rpub->dev_nr = boot_image_dev->dev_nr; /* major device number */
- rpub->dev_style = boot_image_dev->dev_style; /* device style */
- rpub->dev_style2 = boot_image_dev->dev_style2; /* device style 2 */
/* Build command settings. This will also set the process name. */
strlcpy(rp->r_cmd, ip->proc_name, sizeof(rp->r_cmd));
*/
setuid(0);
- if (mapdriver(rpub->label, rpub->dev_nr, rpub->dev_style,
- rpub->dev_flags) != OK) {
+ if (mapdriver(rpub->label, rpub->dev_nr) != OK) {
return kill_service(rp, "couldn't map driver", errno);
}
}
rpub = rp->r_pub;
/* Device and PCI settings. These properties cannot change. */
- rpub->dev_flags = def_rpub->dev_flags;
rpub->dev_nr = def_rpub->dev_nr;
- rpub->dev_style = def_rpub->dev_style;
- rpub->dev_style2 = def_rpub->dev_style2;
rpub->pci_acl = def_rpub->pci_acl;
/* Immutable system and privilege flags. */
rp->r_uid= rs_start->rss_uid;
/* Initialize device driver settings. */
- rpub->dev_flags = DSRV_DF;
rpub->dev_nr = rs_start->rss_major;
- rpub->dev_style = rs_start->rss_dev_style;
rpub->devman_id = rs_start->devman_id;
- if(rpub->dev_nr && !IS_DEV_STYLE(rs_start->rss_dev_style)) {
- printf("RS: init_slot: bad device style\n");
- return EINVAL;
- }
- rpub->dev_style2 = STYLE_NDEV;
/* Initialize pci settings. */
if (rs_start->rss_nr_pci_id > RS_NR_PCI_DEVICE) {
/* Definition of the boot image dev table. */
struct boot_image_dev boot_image_dev_table[] = {
- /*endpoint, flags, dev_nr, dev_style, dev_style2 */
- { TTY_PROC_NR, SRV_DF, TTY_MAJOR, STYLE_TTY, STYLE_CTTY },
- { MEM_PROC_NR, SRV_DF, MEMORY_MAJOR, STYLE_DEV, STYLE_NDEV },
- { DEFAULT_BOOT_NR, SRV_DF, 0, STYLE_NDEV, STYLE_NDEV } /* default
- * entry
- */
+ /*endpoint, dev_nr */
+ { TTY_PROC_NR, TTY_MAJOR },
+ { MEM_PROC_NR, MEMORY_MAJOR },
+ { DEFAULT_BOOT_NR, 0 } /* default entry */
};
-
struct boot_image_dev {
endpoint_t endpoint; /* process endpoint number */
- int flags; /* device flags */
dev_t dev_nr; /* major device number */
- int dev_style; /* device style */
- int dev_style2; /* device style for next major device number */
};
/* Definition of an entry of the system process table. */
((rp)->r_old_rp || (rp)->r_prev_rp ? "+" : " "))
#if DEBUG
- sprintf(srv_string, "service '%s'%s%s(slot %d, ep %d, pid %d, cmd %s, script %s, proc %s, major %d, style %d, flags 0x%03x, sys_flags 0x%02x)",
+ sprintf(srv_string, "service '%s'%s%s(slot %d, ep %d, pid %d, cmd %s, script %s, proc %s, major %d, flags 0x%03x, sys_flags 0x%02x)",
rpub->label, srv_active_str(rp), srv_version_str(rp),
slot_nr, rpub->endpoint, rp->r_pid, srv_str(rp->r_cmd),
srv_str(rp->r_script), srv_str(rpub->proc_name), rpub->dev_nr,
- rpub->dev_style, rp->r_flags, rpub->sys_flags);
+ rp->r_flags, rpub->sys_flags);
#else
sprintf(srv_string, "service '%s'%s%s(slot %d, ep %d, pid %d)",
rpub->label, srv_active_str(rp), srv_version_str(rp),
int r;
struct dmap *dp;
+ /* For the CTTY_MAJOR case, we would actually have to lock the device
+ * entry being redirected to. However, the CTTY major only hosts a
+ * character device while this function is used only for block devices.
+ * Thus, we can simply deny the request immediately.
+ */
+ if (drv_e == CTTY_ENDPT) {
+ printf("VFS: /dev/tty is not a block device!\n");
+ return EIO;
+ }
+
if ((dp = get_dmap(drv_e)) == NULL)
panic("driver endpoint %d invalid", drv_e);
#define SEL_ERR CDEV_OP_ERR
#define SEL_NOTIFY CDEV_NOTIFY /* not a real select operation */
+/* special driver endpoint for CTTY_MAJOR; must be able to pass isokendpt() */
+#define CTTY_ENDPT VFS_PROC_NR
+
#endif
* bdev_close: close a block device
* bdev_reply: process the result of a block driver request
* bdev_up: a block driver has been mapped in
- * gen_opcl: generic call to a character driver to perform an open/close
- * gen_io: generic call to a character driver to initiate I/O
- * no_dev: open/close processing for devices that don't exist
- * no_dev_io: i/o processing for devices that don't exist
- * tty_opcl: perform tty-specific processing for open/close
- * ctty_opcl: perform controlling-tty-specific processing for open/close
- * ctty_io: perform controlling-tty-specific processing for I/O
- * pm_setsid: perform VFS's side of setsid system call
* do_ioctl: perform the IOCTL system call
*/
#include "vmnt.h"
#include "param.h"
+static int cdev_opcl(int op, dev_t dev, int flags);
static int block_io(endpoint_t driver_e, message *mess_ptr);
static cp_grant_id_t make_grant(endpoint_t driver_e, endpoint_t user_e, int op,
void *buf, unsigned long size);
-/*===========================================================================*
- * cdev_open *
- *===========================================================================*/
-int cdev_open(dev_t dev, int flags)
-{
-/* Open a character device. */
- devmajor_t major_dev;
- int r;
-
- /* Determine the major device number so as to call the device class specific
- * open/close routine. (This is the only routine that must check the
- * device number for being in range. All others can trust this check.)
- */
- major_dev = major(dev);
- if (major_dev < 0 || major_dev >= NR_DEVICES) return(ENXIO);
- if (dmap[major_dev].dmap_driver == NONE) return(ENXIO);
- r = (*dmap[major_dev].dmap_opcl)(CDEV_OPEN, dev, fp->fp_endpoint, flags);
- return(r);
-}
-
-
-/*===========================================================================*
- * cdev_close *
- *===========================================================================*/
-int cdev_close(dev_t dev)
-{
-/* Close a character device. */
- devmajor_t major_dev;
- int r;
-
- /* See if driver is roughly valid. */
- major_dev = major(dev);
- if (major_dev < 0 || major_dev >= NR_DEVICES) return(ENXIO);
- if (dmap[major_dev].dmap_driver == NONE) return(ENXIO);
- r = (*dmap[major_dev].dmap_opcl)(CDEV_CLOSE, dev, fp->fp_endpoint, 0);
- return(r);
-}
-
-
/*===========================================================================*
* bdev_open *
*===========================================================================*/
message dev_mess;
devmajor_t major_dev;
devminor_t minor_dev;
+ int r;
major_dev = major(dev);
minor_dev = minor(dev);
dev_mess.BDEV_ID = 0;
/* Call the task. */
- block_io(dp->dmap_driver, &dev_mess);
+ r = block_io(dp->dmap_driver, &dev_mess);
/* Clean up. */
if (GRANT_VALID(gid)) cpf_revoke(gid);
- if (dp->dmap_driver == NONE) {
- printf("VFS: block driver gone!?\n");
- return(EIO);
- }
-
/* Return the result. */
+ if (r != OK)
+ return(r);
+
return(dev_mess.BDEV_STATUS);
}
return gid;
}
+/*===========================================================================*
+ * cdev_get *
+ *===========================================================================*/
+static struct dmap *cdev_get(dev_t dev, devminor_t *minor_dev)
+{
+/* Obtain the dmap structure for the given device, if a valid driver exists for
+ * the major device. Perform redirection for CTTY_MAJOR.
+ */
+ devmajor_t major_dev;
+ struct dmap *dp;
+ int slot;
+
+ /* First cover one special case: /dev/tty, the magic device that translates
+ * to the controlling tty.
+ */
+ if (major(dev) == CTTY_MAJOR) {
+ /* No controlling terminal? Fail the request. */
+ if (fp->fp_tty == 0) return(NULL);
+
+ /* Substitute the controlling terminal device. */
+ dev = fp->fp_tty;
+ }
+
+ /* Determine task dmap. */
+ major_dev = major(dev);
+ if (major_dev < 0 || major_dev >= NR_DEVICES) return(NULL);
+
+ dp = &dmap[major_dev];
+
+ /* See if driver is roughly valid. */
+ if (dp->dmap_driver == NONE) return(NULL);
+
+ if (isokendpt(dp->dmap_driver, &slot) != OK) {
+ printf("VFS: cdev_get: old driver for major %x (%d)\n", major_dev,
+ dp->dmap_driver);
+ return(NULL);
+ }
+
+ /* Also return the (possibly redirected) minor number. */
+ *minor_dev = minor(dev);
+ return dp;
+}
/*===========================================================================*
* cdev_io *
)
{
/* Initiate a read, write, or ioctl to a character device. */
+ devminor_t minor_dev;
struct dmap *dp;
message dev_mess;
cp_grant_id_t gid;
- devmajor_t major_dev;
- devminor_t minor_dev;
- int r, slot;
+ int r;
assert(op == CDEV_READ || op == CDEV_WRITE || op == CDEV_IOCTL);
- /* Determine task dmap. */
- major_dev = major(dev);
- minor_dev = minor(dev);
- dp = &dmap[major_dev];
-
- /* See if driver is roughly valid. */
- if (dp->dmap_driver == NONE) return(ENXIO);
-
- if(isokendpt(dp->dmap_driver, &slot) != OK) {
- printf("VFS: dev_io: old driver for major %x (%d)\n", major_dev,
- dp->dmap_driver);
- return(ENXIO);
- }
+ /* Determine task map. */
+ if ((dp = cdev_get(dev, &minor_dev)) == NULL)
+ return(EIO);
/* Create a grant for the buffer provided by the user process. */
gid = make_grant(dp->dmap_driver, proc_e, op, buf, bytes);
dev_mess.CDEV_FLAGS |= CDEV_NONBLOCK;
/* Send the request to the driver. */
- r = (*dp->dmap_io)(dp->dmap_driver, &dev_mess);
-
- if (r != OK) {
- cpf_revoke(gid);
-
- return r;
- }
+ if ((r = asynsend3(dp->dmap_driver, &dev_mess, AMF_NOREPLY)) != OK)
+ panic("VFS: asynsend in cdev_io failed: %d", r);
/* Suspend the calling process until a reply arrives. */
wait_for(dp->dmap_driver);
/*===========================================================================*
- * clone_cdev *
+ * cdev_clone *
*===========================================================================*/
-static int cdev_clone(dev_t dev, endpoint_t proc_e, devminor_t new_minor)
+static int cdev_clone(dev_t dev, devminor_t new_minor)
{
/* A new minor device number has been returned. Request PFS to create a
* temporary device file to hold it.
struct node_details res;
int r;
- assert(proc_e == fp->fp_endpoint);
-
/* Device number of the new device. */
dev = makedev(major(dev), new_minor);
r = req_newnode(PFS_PROC_NR, fp->fp_effuid, fp->fp_effgid,
ALL_MODES | I_CHAR_SPECIAL, dev, &res);
if (r != OK) {
- (void) gen_opcl(CDEV_CLOSE, dev, proc_e, 0);
+ (void) cdev_opcl(CDEV_CLOSE, dev, 0);
return r;
}
/* Drop old node and use the new values */
if ((vp = get_free_vnode()) == NULL) {
req_putnode(PFS_PROC_NR, res.inode_nr, 1); /* is this right? */
- (void) gen_opcl(CDEV_CLOSE, dev, proc_e, 0);
+ (void) cdev_opcl(CDEV_CLOSE, dev, 0);
return(err_code);
}
lock_vnode(vp, VNODE_OPCL);
/*===========================================================================*
- * gen_opcl *
+ * cdev_opcl *
*===========================================================================*/
-int gen_opcl(
+static int cdev_opcl(
int op, /* operation, CDEV_OPEN or CDEV_CLOSE */
dev_t dev, /* device to open or close */
- endpoint_t proc_e, /* process to open/close for */
int flags /* mode bits and flags */
)
{
-/* Called from the dmap struct on opens & closes of special files.*/
- devmajor_t major_dev;
+/* Open or close a character device. */
devminor_t minor_dev, new_minor;
struct dmap *dp;
+ struct fproc *rfp;
message dev_mess;
int r, r2;
+ assert(op == CDEV_OPEN || op == CDEV_CLOSE);
+
/* Determine task dmap. */
- major_dev = major(dev);
- minor_dev = minor(dev);
- assert(major_dev >= 0 && major_dev < NR_DEVICES);
- dp = &dmap[major_dev];
- assert(dp->dmap_driver != NONE);
+ if ((dp = cdev_get(dev, &minor_dev)) == NULL)
+ return(ENXIO);
- assert(!IS_BDEV_RQ(op));
+ /* CTTY exception: do not actually send the open/close request for /dev/tty
+ * to the driver. This avoids the case that the actual device will remain
+ * open forever if the process calls setsid() after opening /dev/tty.
+ */
+ if (major(dev) == CTTY_MAJOR) return(OK);
+
+ /* Add O_NOCTTY to the access flags if this process is not a session leader,
+ * or if it already has a controlling tty, or if it is someone else's
+ * controlling tty. For performance reasons, only search the full process
+ * table if this driver has set controlling ttys before.
+ */
+ if (!(fp->fp_flags & FP_SESLDR) || fp->fp_tty != 0) {
+ flags |= O_NOCTTY;
+ } else if (!(flags & O_NOCTTY) && dp->dmap_seen_tty) {
+ for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++)
+ if (rfp->fp_pid != PID_FREE && rfp->fp_tty == dev)
+ flags |= O_NOCTTY;
+ }
/* Prepare the request message. */
memset(&dev_mess, 0, sizeof(dev_mess));
dev_mess.m_type = op;
dev_mess.CDEV_MINOR = minor_dev;
- dev_mess.CDEV_ID = proc_e;
+ dev_mess.CDEV_ID = who_e;
if (op == CDEV_OPEN) {
- dev_mess.CDEV_USER = proc_e;
+ dev_mess.CDEV_USER = who_e;
dev_mess.CDEV_ACCESS = 0;
if (flags & R_BIT) dev_mess.CDEV_ACCESS |= CDEV_R_BIT;
if (flags & W_BIT) dev_mess.CDEV_ACCESS |= CDEV_W_BIT;
if (flags & O_NOCTTY) dev_mess.CDEV_ACCESS |= CDEV_NOCTTY;
}
- /* Call the task. */
- r = (*dp->dmap_io)(dp->dmap_driver, &dev_mess);
-
- if (r != OK) return(r);
+ /* Send the request to the driver. */
+ if ((r = asynsend3(dp->dmap_driver, &dev_mess, AMF_NOREPLY)) != OK)
+ panic("VFS: asynsend in cdev_opcl failed: %d", r);
/* Block the thread waiting for a reply. */
fp->fp_task = dp->dmap_driver;
self->w_task = NONE;
self->w_drv_sendrec = NULL;
+ /* Process the reply. */
r = dev_mess.CDEV_STATUS;
- /* Some devices need special processing upon open. Such a device is "cloned",
- * i.e. on a succesful open it is replaced by a new device with a new unique
- * minor device number. This new device number identifies a new object (such
- * as a new network connection) that has been allocated within a task.
- */
if (op == CDEV_OPEN && r >= 0) {
+ /* Some devices need special processing upon open. Such a device is
+ * "cloned", i.e. on a succesful open it is replaced by a new device
+ * with a new unique minor device number. This new device number
+ * identifies a new object (such as a new network connection) that has
+ * been allocated within a driver.
+ */
if (r & CDEV_CLONED) {
new_minor = r & ~(CDEV_CLONED | CDEV_CTTY);
- r &= CDEV_CTTY;
- if ((r2 = cdev_clone(dev, proc_e, new_minor)) < 0)
- r = r2;
- } else
- r &= CDEV_CTTY;
- /* Upon success, we now return either OK or CDEV_CTTY. */
- }
-
- /* Return the result from the driver. */
- return(r);
-}
-
-/*===========================================================================*
- * tty_opcl *
- *===========================================================================*/
-int tty_opcl(
- int op, /* operation, CDEV_OPEN or CDEV_CLOSE */
- dev_t dev, /* device to open or close */
- endpoint_t proc_e, /* process to open/close for */
- int flags /* mode bits and flags */
-)
-{
-/* This procedure is called from the dmap struct on tty open/close. */
- int r;
- register struct fproc *rfp;
-
- assert(!IS_BDEV_RQ(op));
-
- /* Add O_NOCTTY to the flags if this process is not a session leader, or
- * if it already has a controlling tty, or if it is someone elses
- * controlling tty.
- */
- if (!(fp->fp_flags & FP_SESLDR) || fp->fp_tty != 0) {
- flags |= O_NOCTTY;
- } else {
- for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) {
- if(rfp->fp_pid == PID_FREE) continue;
- if (rfp->fp_tty == dev) flags |= O_NOCTTY;
+ if ((r2 = cdev_clone(dev, new_minor)) < 0)
+ return(r2);
}
- }
- r = gen_opcl(op, dev, proc_e, flags);
+ /* Did this call make the tty the controlling tty? */
+ if (r & CDEV_CTTY) {
+ fp->fp_tty = dev;
+ dp->dmap_seen_tty = TRUE;
+ }
- /* Did this call make the tty the controlling tty? */
- if (r >= 0 && (r & CDEV_CTTY)) {
- fp->fp_tty = dev;
r = OK;
}
+ /* Return the result from the driver. */
return(r);
}
/*===========================================================================*
- * ctty_opcl *
+ * cdev_open *
*===========================================================================*/
-int ctty_opcl(
- int op, /* operation, CDEV_OPEN or CDEV_CLOSE */
- dev_t UNUSED(dev), /* device to open or close */
- endpoint_t UNUSED(proc_e), /* process to open/close for */
- int UNUSED(flags) /* mode bits and flags */
-)
+int cdev_open(dev_t dev, int flags)
{
-/* This procedure is called from the dmap struct on opening or closing
- * /dev/tty, the magic device that translates to the controlling tty.
- */
-
- if (IS_BDEV_RQ(op))
- panic("ctty_opcl() called for block device request?");
+/* Open a character device. */
- return(fp->fp_tty == 0 ? ENXIO : OK);
+ return cdev_opcl(CDEV_OPEN, dev, flags);
}
/*===========================================================================*
- * pm_setsid *
+ * cdev_close *
*===========================================================================*/
-void pm_setsid(endpoint_t proc_e)
+int cdev_close(dev_t dev)
{
-/* Perform the VFS side of the SETSID call, i.e. get rid of the controlling
- * terminal of a process, and make the process a session leader.
- */
- register struct fproc *rfp;
- int slot;
+/* Close a character device. */
- /* Make the process a session leader with no controlling tty. */
- okendpt(proc_e, &slot);
- rfp = &fproc[slot];
- rfp->fp_flags |= FP_SESLDR;
- rfp->fp_tty = 0;
+ return cdev_opcl(CDEV_CLOSE, dev, 0);
}
int cdev_select(dev_t dev, int ops)
{
/* Initiate a select call on a device. Return OK iff the request was sent. */
- devmajor_t major_dev;
devminor_t minor_dev;
message dev_mess;
struct dmap *dp;
+ int r;
- major_dev = major(dev);
- minor_dev = minor(dev);
- dp = &dmap[major_dev];
-
- if (dp->dmap_driver == NONE) return ENXIO;
+ /* Determine task dmap. */
+ if ((dp = cdev_get(dev, &minor_dev)) == NULL)
+ return(EIO);
+ /* Prepare the request message. */
memset(&dev_mess, 0, sizeof(dev_mess));
dev_mess.m_type = CDEV_SELECT;
dev_mess.CDEV_MINOR = minor_dev;
dev_mess.CDEV_OPS = ops;
- /* Call the task. */
- return (*dp->dmap_io)(dp->dmap_driver, &dev_mess);
+ /* Send the request to the driver. */
+ if ((r = asynsend3(dp->dmap_driver, &dev_mess, AMF_NOREPLY)) != OK)
+ panic("VFS: asynsend in cdev_select failed: %d", r);
+
+ return(OK);
}
int cdev_cancel(dev_t dev)
{
/* Cancel an I/O request, blocking until it has been cancelled. */
- devmajor_t major_dev;
devminor_t minor_dev;
message dev_mess;
struct dmap *dp;
int r;
- major_dev = major(dev);
- minor_dev = minor(dev);
- dp = &dmap[major_dev];
+ /* Determine task dmap. */
+ if ((dp = cdev_get(dev, &minor_dev)) == NULL)
+ return(EIO);
+ /* Prepare the request message. */
memset(&dev_mess, 0, sizeof(dev_mess));
dev_mess.m_type = CDEV_CANCEL;
dev_mess.CDEV_MINOR = minor_dev;
dev_mess.CDEV_ID = fp->fp_endpoint;
- r = (*dp->dmap_io)(fp->fp_task, &dev_mess);
- if (r != OK) return r; /* ctty_io returned an error? should be impossible */
+ /* Send the request to the driver. */
+ if ((r = asynsend3(dp->dmap_driver, &dev_mess, AMF_NOREPLY)) != OK)
+ panic("VFS: asynsend in cdev_cancel failed: %d", r);
/* Suspend this thread until we have received the response. */
fp->fp_task = dp->dmap_driver;
do {
r = drv_sendrec(driver_e, mess_ptr);
- if (r == OK) {
- status = mess_ptr->BDEV_STATUS;
- if (status == ERESTART) {
- r = EDEADEPT;
- *mess_ptr = mess_retry;
- retry_count++;
- }
+ if (r != OK)
+ return r;
+
+ status = mess_ptr->BDEV_STATUS;
+ if (status == ERESTART) {
+ r = EDEADEPT;
+ *mess_ptr = mess_retry;
+ retry_count++;
}
} while (status == ERESTART && retry_count < 5);
/* If we failed to restart the request, return EIO */
- if (status == ERESTART && retry_count >= 5) {
- r = OK;
- mess_ptr->m_type = EIO;
- }
+ if (status == ERESTART && retry_count >= 5)
+ return EIO;
if (r != OK) {
if (r == EDEADSRCDST || r == EDEADEPT) {
printf("VFS: dead driver %d\n", driver_e);
dmap_unmap_by_endpt(driver_e);
- return(r);
+ return(EIO);
} else if (r == ELOCKED) {
printf("VFS: ELOCKED talking to %d\n", driver_e);
- return(r);
+ return(EIO);
}
panic("block_io: can't send/receive: %d", r);
}
}
-/*===========================================================================*
- * gen_io *
- *===========================================================================*/
-int gen_io(endpoint_t drv_e, message *mess_ptr)
-{
-/* Initiate I/O to a character driver. Do not wait for the reply. */
- int r;
-
- assert(!IS_BDEV_RQ(mess_ptr->m_type));
-
- r = asynsend3(drv_e, mess_ptr, AMF_NOREPLY);
-
- if (r != OK) panic("VFS: asynsend in gen_io failed: %d", r);
-
- return(OK);
-}
-
-
-/*===========================================================================*
- * ctty_io *
- *===========================================================================*/
-int ctty_io(
- endpoint_t UNUSED(task_nr), /* not used - for compatibility with dmap_t */
- message *mess_ptr /* pointer to message for task */
-)
-{
-/* This routine is only called for one device, namely /dev/tty. Its job
- * is to change the message to use the controlling terminal, instead of the
- * major/minor pair for /dev/tty itself.
- */
- struct dmap *dp;
- int slot;
-
- if (fp->fp_tty == 0) {
- /* No controlling tty present anymore, return an I/O error. */
- return(EIO);
- } else {
- /* Substitute the controlling terminal device. */
- dp = &dmap[major(fp->fp_tty)];
- mess_ptr->CDEV_MINOR = minor(fp->fp_tty);
-
- if (dp->dmap_driver == NONE) {
- printf("FS: ctty_io: no driver for dev\n");
- return(EIO);
- }
-
- if (isokendpt(dp->dmap_driver, &slot) != OK) {
- printf("VFS: ctty_io: old driver %d\n", dp->dmap_driver);
- return(EIO);
- }
-
- return (*dp->dmap_io)(dp->dmap_driver, mess_ptr);
- }
-}
-
-
-/*===========================================================================*
- * no_dev *
- *===========================================================================*/
-int no_dev(
- int UNUSED(op), /* operation, CDEV_OPEN or CDEV_CLOSE */
- dev_t UNUSED(dev), /* device to open or close */
- endpoint_t UNUSED(proc), /* process to open/close for */
- int UNUSED(flags) /* mode bits and flags */
-)
-{
-/* Called when opening a nonexistent device. */
- return(ENODEV);
-}
-
-/*===========================================================================*
- * no_dev_io *
- *===========================================================================*/
-int no_dev_io(endpoint_t UNUSED(proc), message *UNUSED(m))
-{
-/* Called when doing i/o on a nonexistent device. */
- printf("VFS: I/O on unmapped device number\n");
- return(EIO);
-}
-
-
/*===========================================================================*
* bdev_up *
*===========================================================================*/
org_self = worker_suspend();
- if ((r = mutex_lock(dp->dmap_lock_ref)) != 0)
+ if ((r = mutex_lock(&dp->dmap_lock)) != 0)
panic("unable to get a lock on dmap: %d\n", r);
worker_resume(org_self);
assert(dp != NULL);
- if ((r = mutex_unlock(dp->dmap_lock_ref)) != 0)
+ if ((r = mutex_unlock(&dp->dmap_lock)) != 0)
panic("unable to unlock dmap lock: %d\n", r);
}
+/*===========================================================================*
+ * map_driver *
+ *===========================================================================*/
+static int map_driver(label, major, proc_nr_e)
+const char label[LABEL_MAX]; /* name of the driver */
+int major; /* major number of the device */
+endpoint_t proc_nr_e; /* process number of the driver */
+{
+/* Add a new device driver mapping in the dmap table. If the proc_nr is set to
+ * NONE, we're supposed to unmap it.
+ */
+ size_t len;
+ struct dmap *dp;
+
+ /* Get pointer to device entry in the dmap table. */
+ if (major < 0 || major >= NR_DEVICES) return(ENODEV);
+ dp = &dmap[major];
+
+ /* Check if we're supposed to unmap it. */
+ if (proc_nr_e == NONE) {
+ /* Even when a driver is now unmapped and is shortly to be mapped in
+ * due to recovery, invalidate associated filps if they're character
+ * special files. More sophisticated recovery mechanisms which would
+ * reduce the need to invalidate files are possible, but would require
+ * cooperation of the driver and more recovery framework between RS,
+ * VFS, and DS.
+ */
+ invalidate_filp_by_char_major(major);
+ dp->dmap_driver = NONE;
+ return(OK);
+ }
+
+ if (label != NULL) {
+ len = strlen(label);
+ if (len+1 > sizeof(dp->dmap_label)) {
+ printf("VFS: map_driver: label too long: %d\n", len);
+ return(EINVAL);
+ }
+ strlcpy(dp->dmap_label, label, sizeof(dp->dmap_label));
+ }
+
+ /* Store driver I/O routines based on type of device */
+ dp->dmap_driver = proc_nr_e;
+
+ return(OK);
+}
+
/*===========================================================================*
* do_mapdriver *
*===========================================================================*/
* etc), and its label. This label is registered with DS, and allows us to
* retrieve the driver's endpoint.
*/
- int r, flags, major, style, slot;
+ int r, major, slot;
endpoint_t endpoint;
vir_bytes label_vir;
size_t label_len;
label_vir = (vir_bytes) job_m_in.md_label;
label_len = (size_t) job_m_in.md_label_len;
major = job_m_in.md_major;
- flags = job_m_in.md_flags;
- style = job_m_in.md_style;
/* Get the label */
if (label_len+1 > sizeof(label)) { /* Can we store this label? */
rfp->fp_flags |= FP_SRV_PROC;
/* Try to update device mapping. */
- return map_driver(label, major, endpoint, style, flags);
-}
-
-/*===========================================================================*
- * map_driver *
- *===========================================================================*/
-int map_driver(label, major, proc_nr_e, style, flags)
-const char label[LABEL_MAX]; /* name of the driver */
-int major; /* major number of the device */
-endpoint_t proc_nr_e; /* process number of the driver */
-int style; /* style of the device */
-int flags; /* device flags */
-{
-/* Add a new device driver mapping in the dmap table. If the proc_nr is set to
- * NONE, we're supposed to unmap it.
- */
-
- int slot, s;
- size_t len;
- struct dmap *dp;
-
- /* Get pointer to device entry in the dmap table. */
- if (major < 0 || major >= NR_DEVICES) return(ENODEV);
- dp = &dmap[major];
-
- /* Check if we're supposed to unmap it. */
- if (proc_nr_e == NONE) {
- /* Even when a driver is now unmapped and is shortly to be mapped in
- * due to recovery, invalidate associated filps if they're character
- * special files. More sophisticated recovery mechanisms which would
- * reduce the need to invalidate files are possible, but would require
- * cooperation of the driver and more recovery framework between RS,
- * VFS, and DS.
- */
- invalidate_filp_by_char_major(major);
- dp->dmap_opcl = no_dev;
- dp->dmap_io = no_dev_io;
- dp->dmap_driver = NONE;
- dp->dmap_flags = flags;
- dp->dmap_lock_ref = &dp->dmap_lock;
- return(OK);
- }
-
- /* Check process number of new driver if it was alive before mapping */
- s = isokendpt(proc_nr_e, &slot);
- if (s != OK) {
- /* This is not a problem only when we force this driver mapping */
- if (! (flags & DRV_FORCED))
- return(EINVAL);
- }
-
- if (label != NULL) {
- len = strlen(label);
- if (len+1 > sizeof(dp->dmap_label))
- panic("VFS: map_driver: label too long: %d", len);
- strlcpy(dp->dmap_label, label, LABEL_MAX);
- }
-
- /* Store driver I/O routines based on type of device */
- switch (style) {
- case STYLE_DEV:
- dp->dmap_opcl = gen_opcl;
- dp->dmap_io = gen_io;
- break;
- case STYLE_TTY:
- dp->dmap_opcl = tty_opcl;
- dp->dmap_io = gen_io;
- break;
- case STYLE_CTTY:
- dp->dmap_opcl = ctty_opcl;
- dp->dmap_io = ctty_io;
- break;
- break;
- default:
- return(EINVAL);
- }
-
- dp->dmap_driver = proc_nr_e;
- dp->dmap_flags = flags;
- dp->dmap_style = style;
-
- return(OK);
+ return map_driver(label, major, endpoint);
}
/*===========================================================================*
for (major = 0; major < NR_DEVICES; major++) {
if (dmap_driver_match(proc_e, major)) {
/* Found driver; overwrite it with a NULL entry */
- if ((r = map_driver(NULL, major, NONE, 0, 0)) != OK) {
+ if ((r = map_driver(NULL, major, NONE)) != OK) {
printf("VFS: unmapping driver %d for major %d failed:"
" %d\n", proc_e, major, r);
}
{
/* Map a new service by storing its device driver properties. */
int r, slot;
- struct dmap *fdp, *sdp;
struct fproc *rfp;
if (IS_RPUB_BOOT_USR(rpub)) return(OK);
if (rpub->dev_nr == NO_DEV) return(OK);
/* Map driver. */
- r = map_driver(rpub->label, rpub->dev_nr, rpub->endpoint, rpub->dev_style,
- rpub->dev_flags);
+ r = map_driver(rpub->label, rpub->dev_nr, rpub->endpoint);
if(r != OK) return(r);
- /* If driver has two major numbers associated, also map the other one. */
- if(rpub->dev_style2 != STYLE_NDEV) {
- r = map_driver(rpub->label, rpub->dev_nr+1, rpub->endpoint,
- rpub->dev_style2, rpub->dev_flags);
- if(r != OK) return(r);
-
- /* To ensure that future dmap lock attempts always lock the same driver
- * regardless of major number, refer the second dmap lock reference
- * to the first dmap entry.
- */
- fdp = get_dmap_by_major(rpub->dev_nr);
- sdp = get_dmap_by_major(rpub->dev_nr+1);
- assert(fdp != NULL);
- assert(sdp != NULL);
- assert(fdp != sdp);
- sdp->dmap_lock_ref = &fdp->dmap_lock;
- }
-
return(OK);
}
/*===========================================================================*
* init_dmap *
*===========================================================================*/
-void init_dmap()
+void init_dmap(void)
{
-/* Initialize the table with empty device <-> driver mappings. */
+/* Initialize the device mapping table. */
int i;
memset(dmap, 0, sizeof(dmap));
for (i = 0; i < NR_DEVICES; i++) {
- dmap[i].dmap_opcl = no_dev;
- dmap[i].dmap_io = no_dev_io;
dmap[i].dmap_driver = NONE;
- dmap[i].dmap_style = STYLE_NDEV;
dmap[i].dmap_servicing = INVALID_THREAD;
- }
-}
-
-/*===========================================================================*
- * init_dmap_locks *
- *===========================================================================*/
-void init_dmap_locks()
-{
- int i;
-
- for (i = 0; i < NR_DEVICES; i++) {
if (mutex_init(&dmap[i].dmap_lock, NULL) != 0)
panic("unable to initialize dmap lock");
- dmap[i].dmap_lock_ref = &dmap[i].dmap_lock;
}
+
+ /* CTTY_MAJOR is a special case, which is handled by VFS itself. */
+ if (map_driver("vfs", CTTY_MAJOR, CTTY_ENDPT) != OK)
+ panic("map_driver(CTTY_MAJOR) failed");
}
/*===========================================================================*
*/
extern struct dmap {
- int(*dmap_opcl) (int, dev_t, endpoint_t, int);
- int(*dmap_io) (endpoint_t, message *);
endpoint_t dmap_driver;
char dmap_label[LABEL_MAX];
- int dmap_flags;
- int dmap_style;
int dmap_sel_busy;
struct filp *dmap_sel_filp;
thread_t dmap_servicing;
mutex_t dmap_lock;
- mutex_t *dmap_lock_ref;
int dmap_recovering;
+ int dmap_seen_tty;
} dmap[];
#endif
mess.m_type = OK; /* tell PM that we succeeded */
s = send(PM_PROC_NR, &mess); /* send synchronization message */
- /* All process table entries have been set. Continue with initialization. */
- init_dmap(); /* Initialize device table. */
system_hz = sys_hz();
+ /* Subscribe to block and character driver events. */
+ s = ds_subscribe("drv\\.[bc]..\\..*", DSF_INITIAL | DSF_OVERWRITE);
+ if (s != OK) panic("VFS: can't subscribe to driver events (%d)", s);
+
+ /* Initialize worker threads */
+ worker_init();
+
+ /* Initialize global locks */
+ if (mthread_mutex_init(&bsf_lock, NULL) != 0)
+ panic("VFS: couldn't initialize block special file lock");
+
+ init_dmap(); /* Initialize device table. */
+
/* Map all the services in the boot image. */
if ((s = sys_safecopyfrom(RS_PROC_NR, info->rproctab_gid, 0,
(vir_bytes) rprocpub, sizeof(rprocpub))) != OK){
}
}
- /* Subscribe to block and character driver events. */
- s = ds_subscribe("drv\\.[bc]..\\..*", DSF_INITIAL | DSF_OVERWRITE);
- if (s != OK) panic("VFS: can't subscribe to driver events (%d)", s);
-
- /* Initialize worker threads */
- worker_init();
-
- /* Initialize global locks */
- if (mthread_mutex_init(&bsf_lock, NULL) != 0)
- panic("VFS: couldn't initialize block special file lock");
-
/* Initialize locks and initial values for all processes. */
for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) {
if (mutex_init(&rfp->fp_lock, NULL) != 0)
rfp->fp_wd = NULL;
}
- init_dmap_locks(); /* init dmap locks */
init_vnodes(); /* init vnodes */
init_vmnts(); /* init vmnt structures */
init_select(); /* init select() structures */
* do_fcntl: perform the FCNTL system call
* do_sync: perform the SYNC system call
* do_fsync: perform the FSYNC system call
+ * pm_setsid: perform VFS's side of setsid system call
* pm_reboot: sync disks and prepare for shutdown
* pm_fork: adjust the tables after PM has performed a FORK system call
* do_exec: handle files with FD_CLOEXEC on after PM has done an EXEC
tfp->fp_realuid = ruid;
}
+/*===========================================================================*
+ * pm_setsid *
+ *===========================================================================*/
+void pm_setsid(endpoint_t proc_e)
+{
+/* Perform the VFS side of the SETSID call, i.e. get rid of the controlling
+ * terminal of a process, and make the process a session leader.
+ */
+ struct fproc *rfp;
+ int slot;
+
+ /* Make the process a session leader with no controlling tty. */
+ okendpt(proc_e, &slot);
+ rfp = &fproc[slot];
+ rfp->fp_flags |= FP_SESLDR;
+ rfp->fp_tty = 0;
+}
+
/*===========================================================================*
* do_svrctl *
*===========================================================================*/
#define md_label m2_p1
#define md_label_len m2_l1
#define md_major m2_i1
-#define md_style m2_i2
-#define md_flags m2_i3
/* The following names are synonyms for the variables in the output message. */
#define reply_type m_type
int bdev_close(dev_t dev);
void bdev_reply(void);
void bdev_up(int major);
-int gen_opcl(int op, dev_t dev, endpoint_t task_nr, int flags);
-int gen_io(endpoint_t drv_e, message *mess_ptr);
-int no_dev(int op, dev_t dev, endpoint_t proc, int flags);
-int no_dev_io(endpoint_t, message *);
-int tty_opcl(int op, dev_t dev, endpoint_t proc, int flags);
-int ctty_opcl(int op, dev_t dev, endpoint_t proc, int flags);
-int clone_opcl(int op, dev_t dev, endpoint_t proc, int flags);
-int ctty_io(endpoint_t task_nr, message *mess_ptr);
int do_ioctl(message *m_out);
-void pm_setsid(endpoint_t proc_e);
/* dmap.c */
void lock_dmap(struct dmap *dp);
void unlock_dmap(struct dmap *dp);
int do_mapdriver(message *m_out);
void init_dmap(void);
-void init_dmap_locks(void);
int dmap_driver_match(endpoint_t proc, int major);
void dmap_endpt_up(endpoint_t proc_nr, int is_blk);
-void dmap_unmap_by_endpt(endpoint_t proc_nr);
struct dmap *get_dmap(endpoint_t proc_e);
struct dmap *get_dmap_by_major(int major);
-int map_service(struct rprocpub *rpub);
void dmap_unmap_by_endpt(endpoint_t proc_nr);
-int map_driver(const char *label, int major, endpoint_t proc_nr, int
- dev_style, int flags);
int map_service(struct rprocpub *rpub);
/* elf_core_dump.c */
void pm_setgid(endpoint_t proc_e, int egid, int rgid);
void pm_setuid(endpoint_t proc_e, int euid, int ruid);
void pm_setgroups(endpoint_t proc_e, int ngroups, gid_t *addr);
+void pm_setsid(endpoint_t proc_e);
int do_sync(message *m_out);
int do_fsync(message *m_out);
void pm_reboot(void);
int copy_name(size_t len, char *dest);
int fetch_name(vir_bytes path, size_t len, char *dest);
int no_sys(message *);
-int isokendpt_f(char *f, int l, endpoint_t e, int *p, int ft);
+int isokendpt_f(const char *f, int l, endpoint_t e, int *p, int ft);
int in_group(struct fproc *rfp, gid_t grp);
#define okendpt(e, p) isokendpt_f(__FILE__, __LINE__, (e), (p), 1)
/*===========================================================================*
* isokendpt_f *
*===========================================================================*/
-int isokendpt_f(char *file, int line, endpoint_t endpoint, int *proc,
+int isokendpt_f(const char *file, int line, endpoint_t endpoint, int *proc,
int fatal)
{
int failed = 0;