1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
|
/* vold. Daemon attemting to automatically mount devices such as CDROM.
* (c) David A. van Leeuwen, 1996--1997
*
* $Id: vold.cc,v 1.1 1997/12/21 17:02:43 david Exp $
* Currently, only implementation for CDROM is done. An attempt is made
* to mount the cdrom under
*
* /cdrom/<volume-name>
*
* In fact, the cdrom `root' /cdrom is read from a file /etc/voltab,
* which is analogous to /etc/fstab, but has entries of devices
* that can be mounted by this volume daemon.
* Note, that this daemon becomes really useful in case two or more
* cdrom players exist on the same machine. Multiple devices can in
* such case have the same `mount point' in voltab, e.g.,
*
* # /etc/voltab
* /dev/cm206cd /cdrom iso9660 ro
* /dev/hdb /cdrom iso9660 ro
*
* Currently, nfs-cdroms are not yet supported, although this has been the
* major reason for writing this program. We must change the pipe
* into a receiving socket, I guess. I am not good at sockets...
*
* I started this in C, and changed to C++ when i needed the `new' call.
* I am not particulary fond of (type *) malloc (... , sizeof(type))
* constructs. Slowly, this program migrates to C++, with String class etc.
*
* The program works as a daemon, accepting commands from a pipe
* /var/run/vold.pipe, and regularly checking devices listed in
* /etc/voltab. Commands should be given by an accompanying program
* `volq' (analogous to `amq'). After a line has been written to the
* pipe, a SIGUSR1 can be sent to this process, to wake up the process
* that may be sleeping. */
#include <sys/types.h>
#include <sys/stat.h> // mknod
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
#include <stdlib.h> // atoi(), exit
#include <errno.h> // strerror
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <String.h> // new string routines
#include <fstream.h>
#include <strstream.h>
#include <signal.h>
#include <stdio.h> // fdopen
#include "vold.h" // common data structures, Mntent.h
#define REVISION "$Revision: 1.1 $"
#define PERIOD 5 // delay between checks
#define MOUNTED_ MOUNTED "~" // lock file
int debug=0;
void usage(ostream& f, const String& s)
{
f << "Usage: " << s<< " [-hf] [-d [debug]] [-p pause]\n\n\t" <<
"-h print this message and copyright\n\t" <<
"-d [d] set debug level to d [1]\n\t" <<
"-f run on forground, don't fork\n\t" <<
"-p p set period between device checks p seconds [5]\n" <<
"-s use strict volume naming regex [A-Z_0-9]+\n" <<
"-_ convert blanks in volume name to '_'\n";
}
void perror(const String& call, int fatal=0)
{
cerr << "vold: " << call << ": " << strerror(errno) << "\n";
if (fatal) exit(errno);
}
int read_tab(const String& table, mel* & start) {
int nvol=0;
struct mntent * mep;
mel * tmp;
FILE* vt;
if ((vt = setmntent(table, "r")) == NULL) perror("setmntent",1);
while((mep = getmntent(vt))!=NULL) {
tmp = new(mel);
tmp->next = start; tmp->mounted=not_mounted;
start = tmp; tmp->mep = new Mntent(mep);
if (debug>1) cerr << "Added tab entry " << start->mep->dir << endl;
}
endmntent(vt);
return nvol;
}
// finds mount point or /etc/voltab entry
mel * find_entry(const String& dir, mel * tab)
{
mel * m;
for(m=tab; m; m=m->next) {
if (debug>2) cerr << "searching " << m->dir << ", " <<
m->mep->dir << endl;
if (m->dir == dir || m->mep->dir == dir) break;
}
return m;
}
mel * find_device_entry(const String& dev, mel * tab)
{
mel * m;
for(m=tab; m; m=m->next) {
if (debug>2) cerr << "searching " << m->mep->fsname << endl;
if (m->mep->fsname == dev) break;
}
return m;
}
void add_entry_mtab(const mel * m) // adds m->dir to mtab
{
int i, ok = -1;
FILE * f_mtab;
Mntent * Mep = m->mep; // private copy
String save;
for (i=0; i<10 && ok<0; i++)
if ((ok = creat(MOUNTED_, O_EXCL))<0) sleep(1);
if (ok<0) perror("lock file " MOUNTED_);
f_mtab = setmntent(MOUNTED, "a");
if (f_mtab == NULL) perror("setmntent");
save = Mep->dir;
Mep->dir = m->dir; // replace with full path
Mep->dir.gsub(" ", "_"); // no spaces in mtab!
if (!Mep->opts.contains("vold")) {
if (Mep->opts != "") Mep->opts += ",";
Mep->opts += "vold"; // say we were automatically mounted
}
if(addmntent(f_mtab, *Mep)) perror ("addmntent");
Mep->dir = save; // restore
endmntent(f_mtab);
close(ok);
unlink(MOUNTED_);
}
void remove_entry_mtab(const mel * m) // removes m->dir from mtab
{
int i, ok = -1;
FILE * f_mtab, *f_new_mtab;
mntent * mep;
String dir=m->dir; // local copy
dir.gsub(" ", "_"); // has no blanks
for (i=0; i<10 && ok<0; i++)
if ((ok = creat(MOUNTED_, O_EXCL | 0644))<0) sleep(1);
if (ok<0) perror("lock file " MOUNTED_);
f_mtab = setmntent(MOUNTED, "r");
f_new_mtab = fdopen(ok, "w"); // setmntent can't do fd/O_EXCL
while ((mep = getmntent(f_mtab))!=NULL)
if (String(mep->mnt_dir) != dir) addmntent(f_new_mtab, mep);
endmntent(f_new_mtab);
endmntent(f_mtab);
rename(MOUNTED_, MOUNTED);
}
mel * voltab =0;
void un_mount(String& w, int eject=0)
{
mel * entry;
if ((entry = find_entry(w, voltab)) == NULL) {
cerr << "Entry " << w << " not listed in " << VOLTAB "\n";
return;
}
if (entry->mounted == is_mounted) {
if (umount(entry->dir)<0) perror("umount");
if (rmdir(entry->dir)<0) perror("rmdir");
remove_entry_mtab(entry);
entry->mounted=un_mounted;
if (debug>0) cerr << entry->dir << " unmounted\n";
}
if (entry->mep->type == MNTTYPE_ISO9660)
after_unmount_isofs(entry, eject);
}
int cont=1; // continue or not
void parse_command(const String& line)
{
String word[2];
int nw = split(line, word, 2, RXwhite);
if (word[0] == "umount")
un_mount(word[1]);
else if (word[0] == "eject")
un_mount(word[1], 1);
else if (word[0] == "mount") {
mel * mep = find_entry(word[1], voltab);
if (mep != NULL && mep->mounted == un_mounted)
mep->mounted=not_mounted; // let main loop take care of mount
}
else if (word[0] == "quit") {
if (debug>0) cerr << "Exiting... ";
cont=0;
} else {
cerr << "unknown command" << line << "\n";
}
}
// signal routines
void do_nothing(int);
void close_down(int);
extern int convert_blanks_to_underscores; // command line option
extern String vol_regex;
main(int ac, char ** av)
{
extern int optind, optopt;
extern char * optarg;
int c, period=PERIOD, foreground=0;
while((c=getopt(ac, av, "d::fhp:_s"))!=EOF) {
switch(c) {
case 'd':
if (optarg!=NULL) debug=atoi(optarg); else debug=1;
cerr << "Debug level set to " << debug << endl;
break;
case 'f': foreground=1; break;
case 'p': period=atoi(optarg); break;
case 'h':
cout << "vold. A volume daemon for removable media devices.\n"
<< "(c) 1997 David A. van Leeuwen\n" REVISION "\n\n";
usage(cout, av[0]);
exit(0);
case '_': convert_blanks_to_underscores = 1;
break;
case 's': vol_regex = "^[A-Z_0-9]+";
break;
default:
usage(cerr, av[0]);
exit(-1);
}
}
ifstream pidfile(VOLPID, ios::in | ios::nocreate);
if (pidfile) {
pid_t pid;
pidfile >> pid;
cerr << VOLPID " exists, is vold already running (pid "
<< pid << ")?" << endl;
exit(-1);
}
int nvol = read_tab(VOLTAB, voltab);
mel * mtab = 0;
int nmounted=read_tab(MOUNTED, mtab);
for (mel * i=mtab; i; i = i->next) {
if (hasmntopt(*i->mep, "vold")) {
mel * e = find_device_entry(i->mep->fsname, voltab);
if (!e)
cerr << "Entry found in " MOUNTED " with vold option, "
"but not in " VOLTAB << ": " << i->mep->dir << endl;
else {
e->mounted=is_mounted;
e->dir=i->mep->dir;
}
if (debug>0) cerr << "Already mounted entry found: " <<
i->mep->dir << endl;
}
}
pid_t pid=0;
if (foreground) pid = getpid();
else {
pid = fork();
if (pid < 0) perror("fork", 1); // error
}
if (pid > 0) { // parent
ofstream pidfile(VOLPID);
pidfile << pid << endl; // PID of the child
if (foreground) signal(SIGINT, close_down);
else exit(0);
}
unlink(VOLPIPE);
if (mknod(VOLPIPE, S_IFIFO | 0644, 0)) perror ("mkfifo", 1);
int cfd=0; // control pipe
if ((cfd = open(VOLPIPE, O_RDONLY | O_NONBLOCK)) < 0)
perror ("open command pipe", 1);
cont=1;
signal(SIGTERM, close_down);
for(;cont;) {
int fd;
mel * i;
for(i=voltab; i; i = i->next) {
if (i->mep->type == MNTTYPE_ISO9660) {
check_isofs(i);
}
// else if(...)
// here a list of other removable medium devices
// can be checked...
}
// before trying to read from the command pipe, sleep for PERIOD
// seconds, but awake upon getting the SIGUSR1 signal.
signal(SIGALRM, do_nothing); signal(SIGUSR1, do_nothing);
alarm(period); pause();
char line[100];
int nread = read(cfd, line, 100);
if (nread>0) {
if (line[nread-1] == '\n') line[nread-1]='\0'; // chop
else line[nread] = '\0';
parse_command(line);
}
}
unlink(VOLPID);
unlink(VOLPIPE);
if (debug>0) cerr << "Exited\n";
}
void do_nothing(int sig)
{
if (sig == SIGUSR1 && debug>0) cerr << "Received pipe urge!\n";
}
void close_down(int sig)
{
if (debug>0) cerr << "Caught SIGTERM, closing down\n";
cont=0; // and stop
}
//
// Local variables:
// c-basic-offset: 4
// c-file-style: "K&R"
// compile-command: "make vold"
// End:
//
|