memlockd-1.3/0000755000175100017510000000000014142641310011566 5ustar etbeetbememlockd-1.3/Makefile0000644000175100017510000000035311512675254013243 0ustar etbeetbe all: memlockd WFLAGS=-Wall -W -Wshadow -Wpointer-arith -Wcast-align -Wwrite-strings -Wcast-qual -pedantic -ffor-scope memlockd: memlockd.cpp $(CXX) $(WFLAGS) $(CXXFLAGS) $(LDFLAGS) memlockd.cpp -o memlockd clean: rm -f memlockd memlockd-1.3/changes.txt0000777000175100017510000000000011512674340017037 2debian/changelogustar etbeetbememlockd-1.3/debian/0000755000175100017510000000000014142641306013015 5ustar etbeetbememlockd-1.3/debian/control0000644000175100017510000000144714002002345014413 0ustar etbeetbeSource: memlockd Section: admin Priority: optional Maintainer: Russell Coker Build-Depends: debhelper (>= 13) Standards-Version: 3.7.2 Package: memlockd Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, adduser Description: daemon to lock files into RAM When a system starts paging excessively it may be impossible for the sysadmin to login for the purpose of killing the runaway processes (sometimes the login program times out due to thrashing). Memlockd allows important system files (such as /bin/login, /bin/getty, and the admin shell) to be locked in memory so that there will be no delay in accessing executable pages. In my tests this can decrease the time required for the administrator to login on a thrashing system by a factor of more than 3. memlockd-1.3/debian/copyright0000644000175100017510000000067211513025710014747 0ustar etbeetbeThis package was debianized by Russell Coker on Fri, 9 Feb 2007 17:45:15 +1100. It was downloaded from http://www.coker.com.au/memlockd/ Upstream Author: Russell Coker Copyright: 2007-2011 Russell Coker License: GPL 3 The Debian packaging is (C) 2007, Russell Coker and is licensed under the GPL v3, see `/usr/share/common-licenses/GPL-3'. memlockd-1.3/debian/dirs0000644000175100017510000000011211767015255013703 0ustar etbeetbeusr/sbin etc/default etc/memlockd.d usr/share/man/man8 lib/systemd/system memlockd-1.3/debian/docs0000644000175100017510000000000010563014176013660 0ustar etbeetbememlockd-1.3/debian/init.d0000644000175100017510000000426511770320232014130 0ustar etbeetbe#! /bin/sh ### BEGIN INIT INFO # Provides: memlockd # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 ### END INIT INFO # # skeleton example file to build /etc/init.d/ scripts. # This file should be used to construct scripts for /etc/init.d. # # Written by Miquel van Smoorenburg . # Modified for Debian # by Ian Murdock . # # Version: @(#)skeleton 1.9 26-Feb-2001 miquels@cistron.nl # #include lsb functions . /lib/lsb/init-functions PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin DAEMON=/usr/sbin/memlockd NAME=memlockd DESC=memlockd test -x $DAEMON || exit 0 # Include memlockd defaults if available if [ -f /etc/default/memlockd ] ; then . /etc/default/memlockd fi set -e case "$1" in start) echo -n "Starting $DESC: " start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid \ --exec $DAEMON -- $DAEMON_OPTS echo "$NAME." ;; stop) echo -n "Stopping $DESC: " start-stop-daemon --stop --quiet --pidfile /var/run/$NAME.pid \ --exec $DAEMON echo "$NAME." ;; reload) # # If the daemon can reload its config files on the fly # for example by sending it SIGHUP, do it here. # # If the daemon responds to changes in its config file # directly anyway, make this a do-nothing entry. # echo "Reloading $DESC configuration files." start-stop-daemon --stop --signal 1 --quiet --pidfile \ /var/run/$NAME.pid --exec $DAEMON ;; force-reload) # # If the "reload" option is implemented, move the "force-reload" # option to the "reload" entry above. If not, "force-reload" is # just the same as "restart" except that it does nothing if the # daemon isn't already running. # check wether $DAEMON is running. If so, restart start-stop-daemon --stop --test --quiet --pidfile \ /var/run/$NAME.pid --exec $DAEMON \ && $0 restart \ || exit 0 ;; restart) $0 start && exit 0 echo -n "Restarting $DESC: " $DAEMON $DAEMON_OPTS echo "$NAME." ;; *) N=/etc/init.d/$NAME # echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2 echo "Usage: $N {start|stop|restart|force-reload}" >&2 exit 1 ;; esac exit 0 memlockd-1.3/debian/memlockd-default0000644000175100017510000000037110564740224016161 0ustar etbeetbe# Defaults for memlockd initscript # sourced by /etc/init.d/memlockd # installed at /etc/default/memlockd by the maintainer scripts # # This is a POSIX shell fragment # # Additional options that are passed to the Daemon. DAEMON_OPTS="-u memlockd" memlockd-1.3/debian/postrm0000644000175100017510000000173510564742246014303 0ustar etbeetbe#!/bin/sh # postrm script for memlockd # # see: dh_installdeb(1) set -e # summary of how this script can be called: # * `remove' # * `purge' # * `upgrade' # * `failed-upgrade' # * `abort-install' # * `abort-install' # * `abort-upgrade' # * `disappear' # # for details, see http://www.debian.org/doc/debian-policy/ or # the debian-policy package case "$1" in remove) update-rc.d -f memlockd remove > /dev/null ;; purge|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) ;; *) echo "postrm called with unknown argument \`$1'" >&2 exit 1 ;; esac # dh_installdeb will replace this with shell code automatically # generated by other debhelper scripts. #DEBHELPER# exit 0 memlockd-1.3/debian/watch0000644000175100017510000000125010564740360014050 0ustar etbeetbe# Example watch control file for uscan # Rename this file to "watch" and then you can run the "uscan" command # to check for upstream updates and more. # See uscan(1) for format # Compulsory line, this is a version 3 file version=3 # Uncomment to examine a Webpage # #http://www.coker.com.au/memlockd memlockd-(.*)\.tar\.gz # Uncomment to examine a Webserver directory http://www.coker.com.au/memlockd/memlockd-(.*)\.tar\.gz # Uncommment to examine a FTP server #ftp://ftp.example.com/pub/memlockd-(.*)\.tar\.gz debian uupdate # Uncomment to find new files on sourceforge, for debscripts >= 2.9 # http://sf.net/memlockd/memlockd-(.*)\.tar\.gz memlockd-1.3/debian/compat0000644000175100017510000000000314142632226014215 0ustar etbeetbe13 memlockd-1.3/debian/memlockd.service0000644000175100017510000000031511767005471016200 0ustar etbeetbe[Unit] Description=memlockd [Service] ExecStart=/usr/sbin/memlockd -f -u memlockd ExecReload=/bin/kill -HUP $MAINPID Type=simple StandardOutput=syslog Restart=always [Install] WantedBy=multi-user.target memlockd-1.3/debian/rules0000755000175100017510000000202114142640001014057 0ustar etbeetbe#!/usr/bin/make -f # See debhelper(7) (uncomment to enable) # output every command that modifies files on the build system. #export DH_VERBOSE = 1 # see FEATURE AREAS in dpkg-buildflags(1) #export DEB_BUILD_MAINT_OPTIONS = hardening=+all # see ENVIRONMENT in dpkg-buildflags(1) # package maintainers to append CFLAGS export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic # package maintainers to append LDFLAGS #export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed %: dh $@ install: build dh_installdirs cp memlockd debian/memlockd/usr/sbin cp memlockd.cfg debian/memlockd/etc cp debian/memlockd-default debian/memlockd/etc/default/memlockd dh_installsystemd --restart-after-upgrade memlockd.service dh_installchangelogs -X changes.txt dh_installdocs dh_installinit dh_installman memlockd.8 dh_installdeb dh_strip dh_compress # dh_make generated override targets # This is example for Cmake (See https://bugs.debian.org/641051 ) #override_dh_auto_configure: # dh_auto_configure -- \ # -DCMAKE_LIBRARY_PATH=$(DEB_HOST_MULTIARCH) memlockd-1.3/debian/postinst0000644000175100017510000000261414142640173014627 0ustar etbeetbe#!/bin/sh # postinst script for memlockd # # see: dh_installdeb(1) set -e # summary of how this script can be called: # * `configure' # * `abort-upgrade' # * `abort-remove' `in-favour' # # * `abort-remove' # * `abort-deconfigure' `in-favour' # `removing' # # for details, see http://www.debian.org/doc/debian-policy/ or # the debian-policy package case "$1" in configure) if ! getent group memlockd > /dev/null ; then addgroup --system --group memlockd > /dev/null fi if ! getent passwd memlockd > /dev/null ; then adduser --system --no-create-home --ingroup memlockd \ --gecos "memlockd system account" --no-create-home \ --disabled-login --home /usr/lib/memlockd --shell /bin/false \ --disabled-password memlockd > /dev/null fi update-rc.d memlockd defaults >/dev/null || true systemctl enable memlockd.service ;; abort-upgrade|abort-remove|abort-deconfigure) ;; *) echo "postinst called with unknown argument \`$1'" >&2 exit 1 ;; esac if which invoke-rc.d >/dev/null 2>&1; then invoke-rc.d memlockd restart else /etc/init.d/memlockd restart fi exit 0 memlockd-1.3/debian/changelog0000644000175100017510000001012214142640732014665 0ustar etbeetbememlockd (1.3-1) unstable; urgency=medium * Updated Debian packaging, closes: #999199 * Made it enable systemd unit, closes: #934389 * Removed the obsolete arguments to update-rc.d, closes: #980724 -- Russell Coker Wed, 10 Nov 2021 13:53:25 +1100 memlockd (1.2.1) unstable; urgency=medium * Remove build-depends on dh-systemd Closes: #958619 -- Russell Coker Wed, 20 Jan 2021 21:24:41 +1100 memlockd (1.2) unstable; urgency=low * debian/control: Add dh-systemd (>= 1.4) to Build-Depends - required to use dh_systemd helpers * debian/rules: Add dh_systemd_enable and dh_systemd_start in proper places Thanks Michał Zając for the above. Closes: #714957 * Changed to Debhelper compat level 9. * Removed readdir_r() as it's deprected and readdir() now does everything we need. * Added $ARCH as a config option for specifiying the host architecture according to uname(2). * Compile with -O2 -- Russell Coker Wed, 14 Dec 2016 13:55:24 +1100 memlockd (1.1.1) unstable; urgency=high * Made it work correctly with systemd, restarts via systemd and doesn't use a pidfile. Closes: #678161 -- Russell Coker Wed, 20 Jun 2012 20:06:20 +1000 memlockd (1.1) unstable; urgency=high * Use wheezy paths for shared objects on i386 and amd64. Also added a new config file option to not log file not found errors so we don't see i386 errors on amd64 and amd64 errors on i386. Closes: #660321, #480915 * Added systemd service file. Closes: #652386 * Added a run-parts style config directory, default is /etc/memlock.d and the config file uses a % to chain to another file or directory. Closes: #529265 -- Russell Coker Sat, 16 Jun 2012 15:43:44 +1000 memlockd (1.0) unstable; urgency=low * Changed the default config to have library names that work on AMD64 and to include killall and ps. * Better use of variables in the makefile. * Put a copyright statement in the main source file and change the license to GPLv3. * Version 1.0, with no serious changes for 3 years it's good for that. -- Russell Coker Tue, 11 Jan 2011 21:07:34 +1100 memlockd (0.05) unstable; urgency=low * Stopped including asm/page.h because we didn't use it since 0.03-0.2. Closes: #479968 -- Russell Coker Wed, 7 May 2008 22:06:00 +1000 memlockd (0.04-0.1) unstable; urgency=low * Non-maintainer upload to solve release goal. * Add LSB dependency header to init.d scripts (Closes: #468888). -- Petter Reinholdtsen Sat, 29 Mar 2008 14:22:03 +0100 memlockd (0.04) unstable; urgency=low * Include changes from Robert S. Edmonds * Fixed my email address in the Maintainer field. -- Russell Coker Sun, 27 Jan 2008 15:57:00 +1100 memlockd (0.03-0.2) unstable; urgency=low * Non-maintainer upload. * Compile with g++, not gcc -lstdc++; closes: #441449. -- Robert S. Edmonds Sun, 09 Sep 2007 17:17:20 -0400 memlockd (0.03-0.1) unstable; urgency=low * Non-maintainer upload. * Use sysconf(_SC_PAGESIZE) instead of PAGE_SIZE; closes: #418666. * Add dependency on adduser; closes: #431529. * Use invoke-rc.d; closes: #440574. -- Robert S. Edmonds Wed, 05 Sep 2007 19:34:22 -0400 memlockd (0.03) unstable; urgency=medium * Fixed section and description. * Made it write a pidfile, and also made the restart option of the init.d script start a new instance unconditionally so the new instance can kill the old. This means that there is no window where memlockd is not running. -- Russell Coker Tue, 13 Mar 2007 19:12:00 +1100 memlockd (0.02) unstable; urgency=medium * Made it not recursively call ldd. ldd does recursion. -- Russell Coker Thu, 22 Feb 2007 09:25:00 +1100 memlockd (0.01) unstable; urgency=medium * Initial release -- Russell Coker Fri, 16 Feb 2007 18:19:00 +1100 memlockd-1.3/memlockd.80000644000175100017510000000443011767016415013467 0ustar etbeetbe.TH memlockd 8 .SH NAME memlockd \- daemon to lock files in memory with mlock .SH SYNOPSIS \f3memlockd\f1 [ \f3\-c config-file\f1 ] [ \f3\-d\f1 ] [ \f3\-f\f1 ] [ \f3\-u user\f1 ] .br .SH DESCRIPTION This manual page documents briefly the .B memlockd command. .P It is used to lock system programs and config files in memory so that if a DOS attack is experienced then the chance of the sys\-admin regaining control of the system in a reasonable amount of time (and therefore having a reasonable chance of discovering the cause of the problem) is significantly increased. .SH OPTIONS The \f3\-c\f1 option is used to specify the fully-qualified path name to a config file that lists the names of files to lock, if the config file is not specified then it will default to \f3/etc/memlockd.cfg\f1. In any situation where a config file is used a directory can be used instead, for a directory every file ending in ".cfg" will be processed. The \f3\-d\f1 option specifies debugging mode, the program will not fork and will produce it's logging messages on stderr instead of via syslog. The \f3\-f\f1 option specifies foreground (non-daemon) mode, the program will not fork but will still log normally. The \f3\-u\f1 option specifies the name of a user to use for running ldd (for recursive operation). Note that locking shared objects that are writable by non\-root is not safe, but using a different UID will reduce the risk. The config file will contain a number of fully qualified names of files to lock in RAM. When locking shared objects and ELF binaries it is possible to prefix the file name with a \f3+\f1 character to indicate that memlockd should recursively lock all shared objects that the program requires and all shared objects that those objects require. When a file not found error doesn't matter (EG you want a single config file to have the file names for multiple architectures or systems) you can prefix the file name with a \f3?\f1 character, in that case errors such as EPERM will still be logged. If a line in the config file starts with a \f3%\f1 character it will be taken as the name of a config file or directory to process. Currently only one level of recursion is accepted. .TP .SH SEE ALSO .BR mlock (2), .BR mmap (1). .br .SH AUTHOR memlockd was written by Russell Coker memlockd-1.3/memlockd.cfg0000644000175100017510000000130613024121207014036 0ustar etbeetbe+/bin/bash +/usr/sbin/sshd +/bin/busybox +/sbin/getty +/bin/login /etc/passwd /etc/shadow /etc/group /etc/nsswitch.conf /etc/resolv.conf /etc/locale.alias /usr/lib/locale/locale-archive /etc/localtime ?+/lib/i386-linux-gnu/i686/nosegneg/libnss_files.so.2 ?+/lib/$ARCH-linux-gnu/libnss_files.so.2 /etc/ld.so.cache +/bin/ls +/bin/ps +/usr/bin/killall # even though I don't use NIS this is loaded ?+/lib/i386-linux-gnu/i686/nosegneg/libnss_nis.so.2 ?+/lib/$ARCH-linux-gnu/libnss_nis.so.2 /lib/$ARCH-linux-gnu/libnss_nis-2.24.so /lib/$ARCH-linux-gnu/libnss_files-2.24.so /lib/$ARCH-linux-gnu/libnss_compat-2.24.so /lib/$ARCH-linux-gnu/ld-2.24.so /usr/lib/$ARCH-linux-gnu/gconv/gconv-modules.cache %/etc/memlockd.d memlockd-1.3/memlockd.cpp0000644000175100017510000002475313024132145014077 0ustar etbeetbe/* * Copyright (C) 2007-2012 Russell Coker * Licensed under GPL v3 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MAX_FILES 1024 #define PIDFILE "/var/run/memlockd.pid" typedef struct file_data { char *name; int fd; struct stat sb; void *start; int map_size; } FILE_DATA; FILE_DATA files[MAX_FILES]; FILE_DATA new_files[MAX_FILES]; int num_files = 0; int num_new_files = 0; const char * config = "/etc/memlockd.cfg"; int debug = 0; int page_size = 0; uid_t uid = 0; gid_t gid = 0; #define BUF_SIZE 1024 void log(int priority, const char * const format, ...) { va_list argp; va_start(argp, format); if(debug) { vfprintf(stderr, format, argp); fprintf(stderr, "\n"); } else vsyslog(priority, format, argp); } void unmap_file(FILE_DATA *data) { munmap(data->start, data->sb.st_size); log(LOG_INFO, "Unmapped file %s", data->name); } void unmap_close_file(FILE_DATA *data) { unmap_file(data); free(data->name); data->name = NULL; close(data->fd); data->fd = -1; } // return 1 if a file is mapped int open_map(int fd, struct stat *sb, const char * const name) { new_files[num_new_files].start = mmap(NULL, sb->st_size, PROT_READ, MAP_SHARED, fd, 0); if(new_files[num_new_files].start == MAP_FAILED) { log(LOG_ERR, "Error mmaping %s: %s", name, strerror(errno)); close(fd); return 0; } if(mlock(new_files[num_new_files].start, sb->st_size) == -1) { log(LOG_ERR, "Can't lock memory for %s, error %s", name, strerror(errno)); munmap(new_files[num_new_files].start, sb->st_size); close(fd); return 0; } if(sb->st_size % page_size) new_files[num_new_files].map_size = sb->st_size - (sb->st_size % page_size) + page_size; else new_files[num_new_files].map_size = sb->st_size; new_files[num_new_files].fd = fd; memcpy(&new_files[num_new_files].sb, sb, sizeof(struct stat)); new_files[num_new_files].name = strdup(name); num_new_files++; log(LOG_INFO, "Mapped file %s", name); return 1; } const char *archname = NULL; // returns NULL if old name is OK. newname must be freed by caller char *make_new_name(const char *orig_name) { const char *tmp = strstr(orig_name, "$ARCH"); if(!tmp) return NULL; int offset = tmp - orig_name; char *newname = (char *)malloc(strlen(orig_name) + 1 + strlen(archname)); if(!newname) { log(LOG_ERR, "malloc() failure"); exit(1); } memcpy(newname, orig_name, offset); sprintf(newname + offset, "%s%s", archname, tmp + 5); return newname; } // return 0 for no file mapped and 1 for file mapped int open_file(const char *name, int no_error_non_exist) { char *newname = make_new_name(name); if(newname) { int rc = open_file(newname, no_error_non_exist); free(newname); return rc; } int fd = open(name, O_RDONLY); if(fd == -1 && no_error_non_exist && errno == ENOENT) return 0; if(fd == -1) { log(LOG_ERR, "Can't open file %s", name); return 0; } struct stat sb; if(fstat(fd, &sb) == -1) { log(LOG_ERR, "Can't stat file %s", name); close(fd); return 0; } int i; for(i = 0; i < num_files; i++) { if(files[i].fd != -1 && files[i].sb.st_dev == sb.st_dev && files[i].sb.st_ino == sb.st_ino) { if(files[i].sb.st_size == sb.st_size && files[i].sb.st_mtime == sb.st_mtime) { memcpy(&new_files[num_new_files], &files[i], sizeof(FILE_DATA)); files[i].fd = -1; files[i].name = NULL; num_new_files++; return 1; } else { memcpy(&new_files[num_new_files], &files[i], sizeof(FILE_DATA)); close(fd); num_new_files++; files[i].fd = -1; files[i].name = NULL; unmap_file(&new_files[num_new_files - 1]); open_map(new_files[num_new_files - 1].fd , &new_files[num_new_files - 1].sb, name); return 1; } } } for(i = 0; i < num_new_files; i++) { if(new_files[i].fd != -1 && new_files[i].sb.st_ino == sb.st_ino) { close(fd); return 0; } } return open_map(fd, &sb, name); } void map_file_dependencies(const char *name, int no_error_non_exist) { char *newname = make_new_name(name); if(newname) { map_file_dependencies(newname, no_error_non_exist); free(newname); return; } if(!uid || !gid) return; int pipe_fd[2]; if(pipe(pipe_fd) == -1) { log(LOG_ERR, "Can't create pipe, not recursing"); uid = 0; return; } int rc = fork(); if(rc == -1) { log(LOG_ERR, "Can't fork, not recursing"); uid = 0; return; } if(!rc) { char buf[4096]; close(pipe_fd[0]); close(1); if(dup2(pipe_fd[1], 1) == -1) { log(LOG_ERR, "Can't create pipe"); exit(1); } if(setresgid(gid, gid, gid) == -1 || setresuid(uid, uid, uid) == -1) { log(LOG_ERR, "Can't set UID and GID"); exit(1); } sprintf(buf, "/usr/bin/ldd %s", name); char *argv[3]; argv[0] = strdup("/usr/bin/ldd"); argv[1] = strdup(name); argv[2] = NULL; execv(argv[0], (char * const *)argv); log(LOG_ERR, "Can't exec ldd"); exit(1); } close(pipe_fd[1]); FILE *fp = fdopen(pipe_fd[0], "r"); if(!fp) return; char buf[4096]; while(fgets(buf, sizeof(buf), fp)) { char *tmp = strchr(buf, '/'); if(!tmp) continue; strtok(tmp, " "); open_file(tmp, no_error_non_exist); } fclose(fp); wait(&rc); } void parse_config_file(const char *config_name, int recurse_count) { char *newname = make_new_name(config_name); if(newname) { parse_config_file(newname, recurse_count); free(newname); return; } struct stat sbuf; if(stat(config_name, &sbuf)) { log(LOG_ERR, "Can't stat \"%s\"", config_name); exit(1); } if(S_ISDIR(sbuf.st_mode)) { log(LOG_INFO, "Entering config dir \"%s\"", config_name); DIR *dirp = opendir(config_name); if(!dirp) { log(LOG_ERR, "Can't open config file/dir %s", config_name); exit(1); } int rc; struct dirent *entry; errno = 0; while(NULL != (entry = readdir(dirp))) { int len = strlen(entry->d_name); if(len > 4 && !strcmp(".cfg", &entry->d_name[len - 4])) { char buf[1024]; snprintf(buf, sizeof(buf), "%s/%s", config_name, entry->d_name); parse_config_file(buf, recurse_count); } errno = 0; } if(0 != (rc = errno)) { log(LOG_ERR, "readdir() error \"%s\" for \"%s\"", strerror(rc), config_name); exit(1); } closedir(dirp); return; } log(LOG_INFO, "Parsing config file \"%s\"", config_name); FILE *fp = fopen(config_name, "r"); char buf[BUF_SIZE]; while(fgets(buf, BUF_SIZE, fp)) { int len = strlen(buf) - 1; if(buf[0] == '#') continue; if(buf[len] == '\n') buf[len] = 0; const char *ptr = buf; int map_dependencies = 0, no_error_non_exist = 0; if(*ptr == '%') { if(recurse_count > 1) { log(LOG_ERR, "Too much recursion, won't process \"%s\"", ptr+1); } else { ptr++; log(LOG_INFO, "Recursion, entering \"%s\"", ptr); parse_config_file(ptr, recurse_count + 1); continue; } } if(*ptr == '?') { ptr++; no_error_non_exist = 1; } if(*ptr == '+') { ptr++; map_dependencies = 1; } if(*ptr == '?') { ptr++; no_error_non_exist = 1; } if(*ptr != '/') continue; open_file(ptr, no_error_non_exist); if(map_dependencies) map_file_dependencies(ptr, no_error_non_exist); } fclose(fp); } void parse_config(int) { num_new_files = 0; parse_config_file(config, 0); for(int i = 0; i < num_files; i++) { if(files[i].fd != -1) unmap_close_file(&files[i]); } if(!num_new_files) { log(LOG_INFO, "No files to lock - exiting"); exit(0); } memcpy(files, new_files, sizeof(FILE_DATA) * num_new_files); num_files = num_new_files; num_new_files = 0; } void usage() { fprintf(stderr, "Usage: memlockd [-c config-file] [-d] [-f]\n" " -d is for debugging mode (running in foreground and no syslog)\n" " -f is for foreground mode with syslog logging\n"); exit(1); } int main(int argc, char **argv) { int c, foreground = 0; pid_t old_pid = 0; page_size = (int) sysconf(_SC_PAGESIZE); while(-1 != (c = getopt(argc, argv, "fdc:u:")) ) { switch(char(c)) { case '?': case ':': usage(); break; case 'c': config = optarg; break; case 'd': debug = 1; break; case 'f': foreground = 1; break; case 'u': struct passwd *pw = getpwnam(optarg); if(!pw) { log(LOG_ERR, "Can't look up user %s", optarg); exit(1); } uid = pw->pw_uid; gid = pw->pw_gid; endpwent(); break; } } openlog("memlockd", LOG_CONS | LOG_PID, LOG_DAEMON); int write_pidfile = 1; if(debug || foreground || getuid()) write_pidfile = 0; if(!debug && !foreground) daemon(0, 0); else chdir("/"); if(write_pidfile) { FILE *fp = fopen(PIDFILE, "r"); char buf[20]; if(fp) { if(fgets(buf, sizeof(buf), fp)) old_pid = atoi(buf); else log(LOG_ERR, "Can't read pidfile " PIDFILE); fclose(fp); } } if(mlockall(MCL_CURRENT|MCL_FUTURE) == -1) { log(LOG_ERR, "Can't lock memory, exiting"); exit(1); } struct utsname un; if(uname(&un)) { log(LOG_ERR, "Can't get architecture from uname(2), exiting"); exit(1); } archname = un.machine; parse_config(0); struct sigaction sa; sa.sa_sigaction = NULL; sa.sa_flags = SA_SIGINFO; sa.sa_handler = parse_config; if(sigaction(SIGHUP, &sa, NULL)) log(LOG_ERR, "Can't handle sighup"); if(write_pidfile) { FILE *fp = fopen(PIDFILE, "w"); if(fp) { if(fprintf(fp, "%d", (int)getpid()) <= 0) { log(LOG_ERR, "Can't write to " PIDFILE); unlink(PIDFILE); } fclose(fp); } else log(LOG_ERR, "Can't open " PIDFILE " for writing"); } if(old_pid) kill(old_pid, SIGKILL); while(1) sleep(3600); return 0; }