|
|
Jump to this file's LXR Page |
|
|
File: [CENS] / emstar / fusd / fusdd / fusdd.c
(download)
/
(as text)
Revision: 1.20, Fri Feb 25 17:51:51 2005 UTC (4 years, 8 months ago) by girod Branch: MAIN CVS Tags: rdd_alpha_version_1, pregeonet, acoustic-05-18-06, PRE_TOSNIC_FIX, PRE_64BIT, MOTENIC_PRE_BUGFIX_20050415, LAURA_CALIBRATION_EXPERIMENTS, HEAD, ESS_RELEASE_3_5, ESS_RELEASE_3_4, ESS_RELEASE_3_3, ESS_RELEASE_3_2, ESS_RELEASE_3_1, ESS_RELEASE_3_0, ESS_RELEASE_2_0, ESS_CONNECTIVITY, ESS_CENTROUTE_TESTING, ESS2-CMS-V1_5_pretest, ESS2-CMS-V1_4cMergeSympathy_2, ESS2-CMS-V1_4c, ESS2-CMS-V1_4b, ESS2-CMS-V1_4a, ESS2-CMS-V1_3, ESS2-CMS-V1_2, ESS2-CMS-V1_1, ESS2-CMS-V1_0, EMSTAR_RELEASE_2_5, EMSTAR_RELEASE_2_1_BRANCH, EMSTAR_RELEASE_2_1, CYCLOPS_RELEASE_CANDIDATE_2_0, CYCLOPS_PRERELEASE_STABLE, CENTROUTE_EMSTAR_SOCKETS, BG_1_0, BANGLADESH_ARSENIC_1_2, BANGLADESH_ARSENIC_1_1, AMARSS_JR_DEPLOYMENT_6_05_07 Changes since 1.19: +18 -15 lines revised previous logging fixes. now, if a process uses -o to set loglevel locally, that info is correctly propagated back to emrun as a custom loglevel. |
/*
*
* Copyright (c) 2003 The Regents of the University of California. All
* rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/*
* FUSDd
*
* The user-space component of FUSD for non-DevFS Linux 2.4 systems
*
*/
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include "fusd.h"
#include "fusdd_i.h"
#include <fusd_msg.h>
#define FUSD_MAX_DEVS 20000
#define F_PATH_MAX (FUSD_MAX_NAME_LENGTH + 10)
extern int unlink_dirs;
struct dev {
char *name;
uint16_t major;
uint16_t minor;
int mark:1;
int del:1;
};
struct dev *dev_lookup(char *name);
void dev_insert(struct dev *add);
void dev_compress();
void dev_dump();
/* current active devices */
struct dev *active_devs=NULL;
int dev_count=0;
int dev_alloc=0;
int verbose=0;
#define DEV_TO_NUM(x) (makedev((x)->major, (x)->minor))
#define DEV_EQ(x,y) (((x)->major == (y)->major) && ((x)->minor == (y)->minor))
#define DEV_ZERO(x) (((x)->major == 0) && ((x)->minor == 0))
/*
* debug function
*/
void dev_dump()
{
int i;
printf("%d devs, %d alloc\n", dev_count, dev_alloc);
for (i=0; i<dev_count; i++) {
printf("%s %d\n", active_devs[i].name, active_devs[i].del);
}
printf("\n");
}
void dev_test()
{
struct dev d = {};
#define TESTI(s) d.name = strdup(s); dev_insert(&d); dev_dump();
#define TESTD(s) dev_lookup(s)->del = 1; dev_dump();
TESTI("b");
TESTI("d");
TESTI("f");
TESTI("a");
TESTI("aa");
TESTI("g");
TESTD("d");
TESTD("a");
TESTD("g");
dev_compress(); dev_dump();
TESTD("f");
dev_compress(); dev_dump();
}
/*
* device list manipulation
*/
int dev_cmp(const void *x, const void *y)
{
struct dev *xd = (struct dev *)x;
struct dev *yd = (struct dev *)y;
return strcmp(xd->name, yd->name);
}
struct dev *dev_lookup(char *name)
{
struct dev key = {
name: name
};
if (active_devs == NULL) return NULL;
return bsearch(&key, active_devs, dev_count, sizeof(struct dev), dev_cmp);
}
void dev_insert(struct dev *add)
{
int i;
dev_count++;
/* need to expand? */
if (dev_alloc < dev_count) {
dev_alloc *= 2;
if (dev_alloc == 0) dev_alloc = 64;
active_devs = realloc(active_devs, sizeof(struct dev)*dev_alloc);
}
/* locate position */
for (i=dev_count-1; i>0; i--) {
if (strcmp(add->name, active_devs[i-1].name) > 0) {
goto found;
}
active_devs[i] = active_devs[i-1];
}
found:
/* store */
active_devs[i] = *add;
}
void dev_compress()
{
int i;
int shift=0;
for (i=0; i<dev_count; i++) {
if (active_devs[i].del) {
free(active_devs[i].name);
shift++;
continue;
}
if (shift) active_devs[i-shift] = active_devs[i];
}
dev_count -= shift;
}
/*
* Prepend /dev.. careful.. static allocation!
*/
char *dev_path(char *name)
{
static char path[F_PATH_MAX+1];
/* prepend /dev */
strcpy(path, DEFAULT_DEV_ROOT);
strcat(path, name);
return path;
}
/*
* mkdir_with_parents: given a pathname, create a directory with that
* name and possibly any parents of that directory, if necessary.
*
* Returns:
* 0 if the directory was created successfully (or already existed)
* -1 with errno set appropriately if there was an error creating the
* directory or any of its parents
*/
int f_mkdir_with_parents(char *path_orig)
{
char path[F_PATH_MAX+1];
char *parent_end;
strcpy(path, path_orig);
/* skip over any leading slashes, then find the first slash after
* that */
parent_end = index(path + strspn(path, "/"), '/');
/* now, for each component of the path, create the dir */
while (parent_end != NULL) {
*parent_end = '\0';
if (mkdir(path, 0755) < 0 && errno != EEXIST) {
return -1;
}
*parent_end = '/';
parent_end = index(parent_end+1, '/');
}
return 0;
}
int clear_marks(void *data)
{
int i;
if (verbose) fprintf(stderr, "Clearing Marks\n");
/* clear the marks first */
for (i=0; i<dev_count; i++)
active_devs[i].mark=0;
return 0;
}
void dev_remove(struct dev *dev)
{
if (dev->name) {
if (verbose)
fprintf(stderr, "Unlinking unused device %s\n", dev->name);
unlink(dev_path(dev->name));
if (unlink_dirs) {
/* rmdir the enclosing directory */
char *tmp = strdup(dev->name);
char *slash;
while ((slash = strrchr(tmp, '/'))) {
*slash = 0;
if (verbose)
fprintf(stderr, "Removing dir %s\n", dev_path(tmp));
if (rmdir(dev_path(tmp)) < 0) {
if (verbose)
fprintf(stderr, "Unable to remove dir %s: %m\n", tmp);
break;
}
}
free(tmp);
}
}
dev->del = 1;
}
int unlink_unmarked(void *data)
{
int i;
if (verbose) fprintf(stderr, "Unlinking unmarked\n");
/* unlink any unmarked devices */
for (i=0; i<dev_count; i++) {
if (active_devs[i].mark == 0)
dev_remove(&active_devs[i]);
}
dev_compress();
return 0;
}
int process(fusd_status_t *fs, int count, void *data)
{
int i;
for (i=0; i<count; i++, fs++) {
struct stat s;
int fd;
struct dev *ptr = dev_lookup(fs->name);
char *path;
/* if zombie, remove if present */
if (fs->zombie) {
if (verbose)
fprintf(stderr, "ignoring zombie %s\n", fs->name);
continue;
}
/* if null device, remove if present */
if (DEV_ZERO(fs)) {
if (verbose)
fprintf(stderr, "ignoring non-device %s\n", fs->name);
continue;
}
/* if present, verify the device setting */
if (ptr) {
/* we're done if it matches out current state */
if (DEV_EQ(ptr,fs))
goto mark;
/* otherwise it will be updated after we succeed */
}
/*
* OK, now we have an entry that might need to be added
*/
path = dev_path(fs->name);
if (verbose)
fprintf(stderr, "checking '%s' -> %d,%d [%x]\n",
path, fs->major, fs->minor, (uint32_t)DEV_TO_NUM(fs));
/* Stat the device file. */
if (stat(path, &s) < 0) {
if (errno == ENOENT) {
/* create any subdirectories */
if (f_mkdir_with_parents(path) < 0) {
fprintf(stderr, "Unable to create directory components for device %s\n", path);
continue;
}
/* do the mknod */
goto create;
}
fprintf(stderr, "Stat of %s failed: %m\n", path);
continue;
}
/* Check the stat, see if it matches */
/* if this is a regular file, delete it! */
if (S_ISREG(s.st_mode)) {
fprintf(stderr, "Deleting existing regular file: %s\n", path);
if (unlink(path) < 0) {
fprintf(stderr, "Unable to unlink existing regular file %s\n", path);
goto remove;
}
goto create;
}
/* if this is not a chrdev, ignore it -- (this may hang the client)
* this might be a directory!!
* $$$ figure out a better thing to do here?? */
if (!S_ISCHR(s.st_mode)) {
if (S_ISDIR(s.st_mode))
fprintf(stderr, "Device overloading a directory!! NOT deleting: %s\n", path);
else
fprintf(stderr, "Device overloading a non-regular file.. NOT deleting: %s\n", path);
/* don't goto remove here because we don't want to delete this file! */
if (ptr) ptr->del = 1;
continue;
}
/* otherwise, if it's a chrdev, check the bits */
if (s.st_rdev != DEV_TO_NUM(fs)) {
/* delete it if they don't match */
if (unlink(path) < 0) {
fprintf(stderr, "Unable to unlink existing device file %s\n", path);
goto remove;
}
}
/* the existing inode is correct. */
else {
/* if it's marked unmade then do the open to set it 'made' */
if (fs->unmade)
goto do_open;
/* otherwise just mark it as OK */
goto mark;
}
create:
/* OK, now do the mknod! */
if (mknod(path, S_IFCHR | 0777, DEV_TO_NUM(fs)) < 0) {
fprintf(stderr, " *** Unable to mknod device %d.%d to %s\n",
fs->major, fs->minor, path);
goto remove;
}
if (verbose)
fprintf(stderr, " *** mknod'd device %d,%d (%x) dev %s\n",
fs->major, fs->minor, (uint32_t)DEV_TO_NUM(fs), path);
do_open:
/* open it to activate it! */
fd = open(path, O_RDONLY);
if (fd >= 0) {
fprintf(stderr, " *** What?? our open succeeded??\n");
close(fd);
}
else {
switch (errno) {
case ENOENT:
/* this happens if the device has already been deleted in the kernel */
/* if ptr is valid, we just don't mark it, it will be removed later */
if (ptr == NULL)
unlink(path);
goto remove;
case EXDEV:
/* this means we succeeded */
if (verbose)
fprintf(stderr, " *** Open should have 'made' dev %s\n", path);
break;
default:
fprintf(stderr, " *** Oops.. unexpected error opening dev %s: %m\n", path);
}
}
mark:
if (ptr) {
/* if key is already there, update the state */
ptr->major = fs->major;
ptr->minor = fs->minor;
ptr->mark = 1;
}
else {
struct dev key = {
name: strdup(fs->name),
major: fs->major,
minor: fs->minor,
mark: 1
};
dev_insert(&key);
}
continue;
remove:
if (ptr) dev_remove(ptr);
}
/* finalize deletions */
dev_compress();
return STATUS_OK;
}
void start_fusdd(int set_verbose)
{
int fd;
int status;
verbose = set_verbose;
fprintf(stderr, "fusdd: FUSDd Starting...%s\n", verbose ? " (Verbose Mode)" : "");
umask(0);
/* check UID */
if (geteuid()) {
fprintf(stderr, "fusdd: Sorry, I must run as root!\n");
exit(1);
}
/* modprobe kfusd */
status = system("/sbin/modprobe kfusd");
if (status < 0) {
fprintf(stderr, "fusdd: modprobe failed: %m\n");
}
else if (status) {
fprintf(stderr, "fusdd: modprobe returned '%d', can't find fusd? Continuing...\n",
status);
}
/* mknod the FUSD control channel etc */
f_mkdir_with_parents(FUSD_CONTROL_DEVNAME);
if (mknod(FUSD_CONTROL_DEVNAME, S_IFCHR | 0777,
makedev(FUSD_DEV_MAJOR, FUSD_CONTROL_MINOR)) < 0)
if (errno != EEXIST)
fprintf(stderr, "Unable to mknod FUSD control device: %m\n");
if (mknod(FUSD_STATUS_DEVNAME, S_IFCHR | 0777,
makedev(FUSD_DEV_MAJOR, FUSD_STATUS_MINOR)) < 0)
if (errno != EEXIST)
fprintf(stderr, "Unable to mknod FUSD status device: %m\n");
/* open the FUSD status device */
fd = open(FUSD_STATUS_DEVNAME, O_RDONLY);
if (fd < 0) {
fprintf(stderr, "fusdd: Can't open %s.. Make sure FUSD module is inserted: %m\n",
FUSD_STATUS_DEVNAME);
goto delete;
}
/* turn on binary mode */
if (ioctl(fd, FUSD_STATUS_USE_BINARY, NULL) < 0) {
fprintf(stderr, "fusd: BINARY_MODE ioctl() failed: %m\n");
exit(1);
}
/* daemonize? */
if (!verbose) {
int status = fork();
if (status < 0) {
fprintf(stderr, "fusdd: Unable to fork!\n");
exit(1);
}
if (status)
return;
/* child: daemonize */
setpgrp();
chdir("/");
close(0);
close(1);
}
/* Tell FUSD who we are */
if (ioctl(fd, FUSD_STATUS_I_AM_FUSDD, NULL) < 0) {
if (errno == 524) {
fprintf(stderr, "fusdd: This FUSD uses DevFS: daemon exiting.\n");
return;
}
fprintf(stderr, "fusd: I_AM_FUSDD ioctl() failed: %m\n");
goto delete;
}
if (!verbose)
close(2);
{
fusd_status_context_t fsctx = {
fd: fd,
new_data_cb: process,
begin_full_cb: clear_marks,
end_full_cb: unlink_unmarked,
};
/* Now we read! */
while (1) {
int status;
/* process it */
status = fusd_status_process(&fsctx);
switch (status) {
case STATUS_ERR:
fprintf(stderr, "fusd: Read failed: %m\n");
exit(1);
case STATUS_DONE:
if (fusd_status_wait(&fsctx) < 0) {
fprintf(stderr, "fusd: Poll failed: %m\n");
exit(1);
}
}
}
}
delete:
unlink(FUSD_CONTROL_DEVNAME);
unlink(FUSD_STATUS_DEVNAME);
exit(1);
}
| CENS CVS Mailing List |
Powered by ViewCVS 0.9.2 |