UUCPLock.c++
上传用户:weiyuanprp
上传日期:2020-05-20
资源大小:1169k
文件大小:9k
源码类别:

传真(Fax)编程

开发平台:

C/C++

  1. /* $Id: UUCPLock.c++,v 1.3 2008/04/26 22:34:28 faxguy Exp $ */
  2. /*
  3.  * Copyright (c) 1990-1996 Sam Leffler
  4.  * Copyright (c) 1991-1996 Silicon Graphics, Inc.
  5.  * HylaFAX is a trademark of Silicon Graphics
  6.  *
  7.  * Permission to use, copy, modify, distribute, and sell this software and 
  8.  * its documentation for any purpose is hereby granted without fee, provided
  9.  * that (i) the above copyright notices and this permission notice appear in
  10.  * all copies of the software and related documentation, and (ii) the names of
  11.  * Sam Leffler and Silicon Graphics may not be used in any advertising or
  12.  * publicity relating to the software without the specific, prior written
  13.  * permission of Sam Leffler and Silicon Graphics.
  14.  * 
  15.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  16.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  17.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  18.  * 
  19.  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  20.  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  21.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  22.  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  23.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  24.  * OF THIS SOFTWARE.
  25.  */
  26. #include "UUCPLock.h"
  27. #include "faxApp.h"
  28. #include "Sys.h"
  29. #include "config.h"
  30. #include <sys/param.h>
  31. #include <sys/types.h>
  32. #include <errno.h>
  33. #ifdef HAS_MKDEV
  34. extern "C" {
  35. #include <sys/mkdev.h>
  36. }
  37. #endif
  38. #include <pwd.h>
  39. /*
  40.  * UUCP Device Locking Support.
  41.  *
  42.  * NB: There is some implicit understanding of sizeof (pid_t).
  43.  */
  44. /*
  45.  * Lock files with ascii contents (System V style).
  46.  */
  47. class AsciiUUCPLock : public UUCPLock {
  48. private:
  49.     fxStr data; // data to write record in lock file
  50.     void setPID(pid_t);
  51.     bool writeData(int fd);
  52.     bool readData(int fd, pid_t& pid);
  53. public:
  54.     AsciiUUCPLock(const fxStr&, mode_t);
  55.     ~AsciiUUCPLock();
  56. };
  57. /*
  58.  * Lock files with binary contents (BSD style).
  59.  */
  60. class BinaryUUCPLock : public UUCPLock {
  61. private:
  62.     pid_t data; // data to write record in lock file
  63.     void setPID(pid_t);
  64.     bool writeData(int fd);
  65.     bool readData(int fd, pid_t& pid);
  66. public:
  67.     BinaryUUCPLock(const fxStr&, mode_t);
  68.     ~BinaryUUCPLock();
  69. };
  70. UUCPLock*
  71. UUCPLock::newLock(const char* type,
  72.     const fxStr& dir, const fxStr& device, mode_t mode)
  73. {
  74.     fxStr pathname(dir);
  75.     if (type[0] == '+') { // SVR4-style lockfile names
  76. #if defined(HAS_MKDEV) || (defined(major) && defined(minor))
  77. /*
  78.  * SVR4-style lockfile names are of the form LK.xxx.yyy.zzz
  79.  * where xxx is the major device of the filesystem on which
  80.  * the device resides and yyy and zzz are the major & minor
  81.  * numbers of the locked device.  This format is used if the
  82.  * lockfile type is specified with a leading '+'; e.g.
  83.  * ``+ascii'' or ``+binary''. 
  84.  */
  85. struct stat sb;
  86. Sys::stat(device, sb);
  87. pathname.append(fxStr::format("/LK.%03d.%03d.%03d",
  88.     major(sb.st_dev), major(sb.st_rdev), minor(sb.st_rdev)));
  89. type++;
  90. #else
  91. faxApp::fatal("No support for SVR4-style UUCP lockfiles");
  92. #endif
  93.     } else { // everybody else's lockfile names
  94. u_int l = device.nextR(device.length(), '/');
  95. pathname.append("/LCK.." | device.token(l, '/'));
  96. if (type[0] == '-') { // SCO-style lockfile names
  97.     /*
  98.      * Some systems (e.g. SCO) uses upper case letters on modem
  99.      * control devices, but require that the locking be done on
  100.      * the lower case device.  If the lock file type is specified
  101.      * as ``-ascii'' or ``-binary'', etc. then we convert the
  102.      * generated pathname to reflect this convention.
  103.      */
  104.     pathname.lowercase(dir.length()+6);
  105.     type++;
  106. }
  107.     }
  108.     if (streq(type, "ascii"))
  109. return new AsciiUUCPLock(pathname, mode);
  110.     else if (streq(type, "binary"))
  111. return new BinaryUUCPLock(pathname, mode);
  112.     else
  113. faxApp::fatal("Unknown UUCP lock file type "%s"", type);
  114.     return (NULL);
  115. }
  116. UUCPLock::UUCPLock(const fxStr& pathname, mode_t m) : file(pathname)
  117. {
  118.     mode = m;
  119.     locked = false;
  120.     setupIDs();
  121. }
  122. UUCPLock::~UUCPLock()
  123. {
  124.     unlock();
  125. }
  126. uid_t UUCPLock::UUCPuid = (uid_t) -1;
  127. gid_t UUCPLock::UUCPgid = (gid_t) -1;
  128. void
  129. UUCPLock::setupIDs()
  130. {
  131.     if (UUCPuid == (uid_t) -1) {
  132. const passwd *pwd = getpwnam("uucp");
  133. if (!pwd)
  134.     faxApp::fatal("Can not deduce identity of UUCP");
  135. UUCPuid = pwd->pw_uid;
  136. UUCPgid = pwd->pw_gid;
  137. endpwent(); // paranoia
  138.     }
  139. }
  140. uid_t UUCPLock::getUUCPUid() { setupIDs(); return UUCPuid; }
  141. gid_t UUCPLock::getUUCPGid() { setupIDs(); return UUCPgid; }
  142. time_t UUCPLock::lockTimeout = UUCP_LCKTIMEOUT;
  143. void UUCPLock::setLockTimeout(time_t t) { lockTimeout = t; }
  144. /*
  145.  * Create a lock file.
  146.  */
  147. bool
  148. UUCPLock::create()
  149. {
  150.     /*
  151.      * We create a separate file and link it to
  152.      * the destination to avoid a race condition.
  153.      */
  154.     fxStr templ = file.head(file.nextR(file.length(), '/'));
  155.     templ.append("/TM.faxXXXXXX");
  156.     char* buff = strcpy(new char[templ.length() + 1], templ);
  157.     int fd = Sys::mkstemp(buff);
  158.     if (fd >= 0) {
  159. writeData(fd);
  160. #if HAS_FCHMOD
  161. fchmod(fd, mode);
  162. #else
  163. Sys::chmod(buff, mode);
  164. #endif
  165. #if HAS_FCHOWN
  166. int ignore = fchown(fd, UUCPuid, UUCPgid);
  167. #else
  168. Sys::chown(buff, UUCPuid, UUCPgid);
  169. #endif
  170. Sys::close(fd);
  171. locked = (Sys::link(buff, file) == 0);
  172. Sys::unlink(buff);
  173.     }
  174.     delete [] buff;
  175.     return (locked);
  176. }
  177. /*
  178.  * Check if the lock file is
  179.  * newer than the specified age.
  180.  */
  181. bool
  182. UUCPLock::isNewer(time_t age)
  183. {
  184.     struct stat sb;
  185.     return (Sys::stat(file, sb) != 0 ? false : Sys::now() - sb.st_mtime < age);
  186. }
  187. /*
  188.  * Create a lock file.  If one already exists, the create
  189.  * time is checked for older than the age time (atime).
  190.  * If it is older, an attempt is made to unlink it and
  191.  * create a new one.
  192.  */
  193. bool
  194. UUCPLock::lock()
  195. {
  196.     if (locked)
  197. return (false);
  198.     uid_t ouid = geteuid();
  199.     seteuid(0); // need to be root
  200.     bool ok = create();
  201.     if (!ok)
  202. ok = check() && create();
  203.     seteuid(ouid);
  204.     return (ok);
  205. }
  206. /*
  207.  * Unlock the device.
  208.  */
  209. void
  210. UUCPLock::unlock()
  211. {
  212.     if (locked) {
  213. uid_t ouid = geteuid();
  214. seteuid(0); // need to be root
  215. Sys::unlink(file);
  216. seteuid(ouid);
  217. locked = false;
  218.     }
  219. }
  220. /*
  221.  * Set a particular owner process
  222.  * pid for an already locked device.
  223.  */
  224. bool
  225. UUCPLock::setOwner(pid_t pid)
  226. {
  227.     bool ok = false;
  228.     if (locked) {
  229. uid_t ouid = geteuid();
  230. seteuid(0); // need to be root
  231. int fd = Sys::open(file, O_WRONLY);
  232. if (fd != -1) {
  233.     if (pid)
  234. setPID(pid);
  235.     ok = writeData(fd);
  236.     Sys::close(fd);
  237. }
  238. seteuid(ouid);
  239.     }
  240.     return (ok);
  241. }
  242. /*
  243.  * Check if the owning process exists.
  244.  */
  245. bool
  246. UUCPLock::ownerExists(int fd)
  247. {
  248.     pid_t pid;
  249.     return (readData(fd, pid) && (kill(pid, 0) == 0 || errno != ESRCH));
  250. }
  251. /*
  252.  * Check to see if the lock exists and is still active.
  253.  * Locks are automatically expired after
  254.  * UUCPLock::lockTimeout seconds if the process owner
  255.  * is no longer around.
  256.  */
  257. bool
  258. UUCPLock::check()
  259. {
  260.     int fd = Sys::open(file, O_RDONLY);
  261.     if (fd != -1) {
  262. if (lockTimeout > 0) {
  263.     if (isNewer(lockTimeout) || ownerExists(fd)) {
  264. Sys::close(fd);
  265. return (false);
  266.     }
  267.     Sys::close(fd);
  268.     logInfo("Purge stale UUCP lock %s", (const char*) file);
  269.     return (Sys::unlink(file) == 0);
  270. } else {
  271.     Sys::close(fd);
  272.     return (false);
  273. }
  274.     }
  275.     return (true);
  276. }
  277. /*
  278.  * ASCII lock file interface.
  279.  */
  280. AsciiUUCPLock::AsciiUUCPLock(const fxStr& path, mode_t m)
  281.     : UUCPLock(path, m)
  282.     , data(UUCP_PIDDIGITS+2)
  283. { setPID(getpid()); }
  284. AsciiUUCPLock::~AsciiUUCPLock() {}
  285. void
  286. AsciiUUCPLock::setPID(pid_t pid)
  287. {
  288.     // XXX should this be %d or %ld? depends on pid_t
  289.     data = fxStr::format("%*dn", UUCP_PIDDIGITS, pid);
  290. }
  291. bool
  292. AsciiUUCPLock::writeData(int fd)
  293. {
  294.     return (Sys::write(fd, data, UUCP_PIDDIGITS+1) == (UUCP_PIDDIGITS+1));
  295. }
  296. bool
  297. AsciiUUCPLock::readData(int fd, pid_t& pid)
  298. {
  299.     char buf[UUCP_PIDDIGITS+1];
  300.     if (Sys::read(fd, buf, UUCP_PIDDIGITS) == UUCP_PIDDIGITS) {
  301. buf[UUCP_PIDDIGITS] = '';
  302. pid = atol(buf); // NB: assumes pid_t is <= 32-bits
  303. return (true);
  304.     } else
  305. return (false);
  306. }
  307. /*
  308.  * Binary lock file interface.
  309.  */
  310. BinaryUUCPLock::BinaryUUCPLock(const fxStr& path, mode_t m)
  311.     : UUCPLock(path, m)
  312. { setPID(getpid()); }
  313. BinaryUUCPLock::~BinaryUUCPLock() {}
  314. void
  315. BinaryUUCPLock::setPID(pid_t pid)
  316. {
  317.     data = pid; // binary pid of lock holder
  318. }
  319. bool
  320. BinaryUUCPLock::writeData(int fd)
  321. {
  322.     return (Sys::write(fd, (char*) &data, sizeof (data)) == sizeof (data));
  323. }
  324. bool
  325. BinaryUUCPLock::readData(int fd, pid_t& pid)
  326. {
  327.     pid_t data;
  328.     if (Sys::read(fd, (char*) &data, sizeof (data)) == sizeof (data)) {
  329. pid = data;
  330. return (true);
  331.     } else
  332. return (false);
  333. }