2 * Copyright 2009 Oracle. All rights reserved.
4 * This file is part of nfs-utils.
6 * nfs-utils is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * nfs-utils is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with nfs-utils. If not, see <http://www.gnu.org/licenses/>.
23 * Callback information and NSM state is stored in files, usually
24 * under /var/lib/nfs. A database of information contained in local
25 * files stores NLM callback data and what remote peers to notify of
28 * For each monitored remote peer, a text file is created under the
29 * directory specified by NSM_MONITOR_DIR. The name of the file
30 * is a valid DNS hostname. The hostname string must be a valid
31 * ASCII DNS name, and must not contain slash characters, white space,
32 * or '\0' (ie. anything that might have some special meaning in a
35 * The contents of each file include seven blank-separated fields of
36 * text, finished with '\n'. The first field contains the network
37 * address of the NLM service to call back. The current implementation
38 * supports using only IPv4 addresses, so the only contents of this
39 * field are a network order IPv4 address expressed in 8 hexadecimal
42 * The next four fields are text strings of hexadecimal characters,
45 * 2. A 4 byte RPC program number of the NLM service to call back
46 * 3. A 4 byte RPC version number of the NLM service to call back
47 * 4. A 4 byte RPC procedure number of the NLM service to call back
48 * 5. A 16 byte opaque cookie that the NLM service uses to identify
51 * The sixth field is the monitored host's mon_name, passed to statd
52 * via an SM_MON request.
54 * The seventh field is the my_name for this peer, which is the
55 * hostname of the local NLM (currently on Linux, the result of
56 * `uname -n`). This can be used as the source address/hostname
57 * when sending SM_NOTIFY requests.
59 * The NSM protocol does not limit the contents of these strings
60 * in any way except that they must fit into 1024 bytes. Our
61 * implementation requires that these strings not contain
62 * white space or '\0'.
69 #include <sys/types.h>
70 #ifdef HAVE_SYS_CAPABILITY_H
71 #include <sys/capability.h>
73 #include <sys/prctl.h>
92 #define RPCARGSLEN (4 * (8 + 1))
93 #define LINELEN (RPCARGSLEN + SM_PRIV_SIZE * 2 + 1)
95 #define NSM_KERNEL_STATE_FILE "/proc/sys/fs/nfs/nsm_local_state"
97 static char nsm_base_dirname[PATH_MAX] = NSM_DEFAULT_STATEDIR;
99 #define NSM_MONITOR_DIR "sm"
100 #define NSM_NOTIFY_DIR "sm.bak"
101 #define NSM_STATE_FILE "state"
105 error_check(const int len, const size_t buflen)
107 return (len < 0) || ((size_t)len >= buflen);
111 exact_error_check(const ssize_t len, const size_t buflen)
113 return (len < 0) || ((size_t)len != buflen);
117 * Returns a dynamically allocated, '\0'-terminated buffer
118 * containing an appropriate pathname, or NULL if an error
119 * occurs. Caller must free the returned result with free(3).
121 __attribute__((__malloc__))
123 nsm_make_record_pathname(const char *directory, const char *hostname)
131 * Block hostnames that contain characters that have
132 * meaning to the file system (like '/'), or that can
133 * be confusing on visual inspection (like ' ').
135 for (c = hostname; *c != '\0'; c++)
136 if (*c == '/' || isspace((int)*c) != 0) {
137 xlog(D_GENERAL, "Hostname contains invalid characters");
141 size = strlen(nsm_base_dirname) + strlen(directory) + strlen(hostname) + 3;
142 if (size > PATH_MAX) {
143 xlog(D_GENERAL, "Hostname results in pathname that is too long");
149 xlog(D_GENERAL, "Failed to allocate memory for pathname");
153 len = snprintf(path, size, "%s/%s/%s",
154 nsm_base_dirname, directory, hostname);
155 if (error_check(len, size)) {
156 xlog(D_GENERAL, "Pathname did not fit in specified buffer");
165 * Returns a dynamically allocated, '\0'-terminated buffer
166 * containing an appropriate pathname, or NULL if an error
167 * occurs. Caller must free the returned result with free(3).
169 __attribute__((__malloc__))
171 nsm_make_pathname(const char *directory)
177 size = strlen(nsm_base_dirname) + strlen(directory) + 2;
185 len = snprintf(path, size, "%s/%s", nsm_base_dirname, directory);
186 if (error_check(len, size)) {
195 * Returns a dynamically allocated, '\0'-terminated buffer
196 * containing an appropriate pathname, or NULL if an error
197 * occurs. Caller must free the returned result with free(3).
199 __attribute__((__malloc__))
201 nsm_make_temp_pathname(const char *pathname)
207 size = strlen(pathname) + sizeof(".new") + 2;
215 len = snprintf(path, size, "%s.new", pathname);
216 if (error_check(len, size)) {
225 * Use "mktemp, write, rename" to update the contents of a file atomically.
227 * Returns true if completely successful, or false if some error occurred.
230 nsm_atomic_write(const char *path, const void *buf, const size_t buflen)
232 _Bool result = false;
237 temp = nsm_make_temp_pathname(path);
239 xlog(L_ERROR, "Failed to create new path for %s", path);
243 fd = open(temp, O_CREAT | O_TRUNC | O_SYNC | O_WRONLY, 0644);
245 xlog(L_ERROR, "Failed to create %s: %m", temp);
249 len = write(fd, buf, buflen);
250 if (exact_error_check(len, buflen)) {
251 xlog(L_ERROR, "Failed to write %s: %m", temp);
257 if (close(fd) == -1) {
258 xlog(L_ERROR, "Failed to close %s: %m", temp);
263 if (rename(temp, path) == -1) {
264 xlog(L_ERROR, "Failed to rename %s -> %s: %m",
270 /* Ostensibly, a sync(2) is not needed here because
271 * open(O_CREAT), write(O_SYNC), and rename(2) are
272 * already synchronous with persistent storage, for
273 * any file system we care about. */
283 * nsm_setup_pathnames - set up pathname
284 * @progname: C string containing name of program, for error messages
285 * @parentdir: C string containing pathname to on-disk state, or NULL
287 * This runs before logging is set up, so error messages are directed
290 * Returns true and sets up our pathnames, if @parentdir was valid
291 * and usable; otherwise false is returned.
294 nsm_setup_pathnames(const char *progname, const char *parentdir)
296 static char buf[PATH_MAX];
300 /* First: test length of name and whether it exists */
301 if (lstat(parentdir, &st) == -1) {
302 (void)fprintf(stderr, "%s: Failed to stat %s: %s",
303 progname, parentdir, strerror(errno));
307 /* Ensure we have a clean directory pathname */
308 strncpy(buf, parentdir, sizeof(buf));
311 (void)fprintf(stderr, "%s: Unusable directory %s",
312 progname, parentdir);
316 xlog(D_CALL, "Using %s as the state directory", parentdir);
317 strncpy(nsm_base_dirname, parentdir, sizeof(nsm_base_dirname));
322 * nsm_is_default_parentdir - check if parent directory is default
324 * Returns true if the active statd parent directory, set by
325 * nsm_change_pathname(), is the same as the built-in default
326 * parent directory; otherwise false is returned.
329 nsm_is_default_parentdir(void)
331 return strcmp(nsm_base_dirname, NSM_DEFAULT_STATEDIR) == 0;
335 * Clear all capabilities but CAP_NET_BIND_SERVICE. This permits
336 * callers to acquire privileged source ports, but all other root
337 * capabilities are disallowed.
339 * Returns true if successful, or false if some error occurred.
341 #ifdef HAVE_SYS_CAPABILITY_H
343 nsm_clear_capabilities(void)
347 caps = cap_from_text("cap_net_bind_service=ep");
349 xlog(L_ERROR, "Failed to allocate capability: %m");
353 if (cap_set_proc(caps) == -1) {
354 xlog(L_ERROR, "Failed to set capability flags: %m");
355 (void)cap_free(caps);
359 (void)cap_free(caps);
363 #define CAP_BOUND_PROCFILE "/proc/sys/kernel/cap-bound"
365 prune_bounding_set(void)
367 #ifdef PR_CAPBSET_DROP
373 * Prior to kernel 2.6.25, the capabilities bounding set was a global
374 * value. Check to see if /proc/sys/kernel/cap-bound exists and don't
375 * bother to clear the bounding set if it does.
377 ret = stat(CAP_BOUND_PROCFILE, &st);
379 xlog(L_WARNING, "%s exists. Not attempting to clear "
380 "capabilities bounding set.",
383 } else if (errno != ENOENT) {
384 /* Warn, but attempt to clear the bounding set anyway. */
385 xlog(L_WARNING, "Unable to stat %s: %m", CAP_BOUND_PROCFILE);
388 /* prune the bounding set to nothing */
389 for (i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >=0 ; ++i) {
390 ret = prctl(PR_CAPBSET_DROP, i, 0, 0, 0);
392 xlog(L_ERROR, "Unable to prune capability %lu from "
393 "bounding set: %m", i);
397 #endif /* PR_CAPBSET_DROP */
400 #else /* !HAVE_SYS_CAPABILITY_H */
402 nsm_clear_capabilities(void)
408 prune_bounding_set(void)
412 #endif /* HAVE_SYS_CAPABILITY_H */
415 * nsm_drop_privileges - drop root privileges
416 * @pidfd: file descriptor of a pid file
418 * Returns true if successful, or false if some error occurred.
420 * Set our effective UID and GID to that of our on-disk database.
423 nsm_drop_privileges(const int pidfd)
427 (void)umask(S_IRWXO);
430 * XXX: If we can't stat dirname, or if dirname is owned by
431 * root, we should use "statduser" instead, which is set up
432 * by configure.ac. Nothing in nfs-utils seems to use
433 * "statduser," though.
435 if (lstat(nsm_base_dirname, &st) == -1) {
436 xlog(L_ERROR, "Failed to stat %s: %m", nsm_base_dirname);
440 if (chdir(nsm_base_dirname) == -1) {
441 xlog(L_ERROR, "Failed to change working directory to %s: %m",
446 if (!prune_bounding_set())
449 if (st.st_uid == 0) {
450 xlog_warn("Running as root. "
451 "chown %s to choose different user", nsm_base_dirname);
456 * If the pidfile happens to reside on NFS, dropping privileges
457 * will probably cause us to lose access, even though we are
458 * holding it open. Chown it to prevent this.
461 if (fchown(pidfd, st.st_uid, st.st_gid) == -1)
462 xlog_warn("Failed to change owner of pidfile: %m");
465 * Don't clear capabilities when dropping root.
467 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1) {
468 xlog(L_ERROR, "prctl(PR_SET_KEEPCAPS) failed: %m");
472 if (setgroups(0, NULL) == -1) {
473 xlog(L_ERROR, "Failed to drop supplementary groups: %m");
480 * setgid(2) first, as setuid(2) may remove privileges needed
481 * to set the group id.
483 if (setgid(st.st_gid) == -1 || setuid(st.st_uid) == -1) {
484 xlog(L_ERROR, "Failed to drop privileges: %m");
488 xlog(D_CALL, "Effective UID, GID: %u, %u", st.st_uid, st.st_gid);
490 return nsm_clear_capabilities();
494 * nsm_get_state - retrieve on-disk NSM state number
496 * Returns an odd NSM state number read from disk, or an initial
497 * state number. Zero is returned if some error occurs.
500 nsm_get_state(_Bool update)
506 path = nsm_make_pathname(NSM_STATE_FILE);
508 xlog(L_ERROR, "Failed to allocate path for " NSM_STATE_FILE);
512 fd = open(path, O_RDONLY);
514 if (errno != ENOENT) {
515 xlog(L_ERROR, "Failed to open %s: %m", path);
519 xlog(L_NOTICE, "Initializing NSM state");
525 result = read(fd, &state, sizeof(state));
526 if (exact_error_check(result, sizeof(state))) {
527 xlog_warn("Failed to read %s: %m", path);
529 xlog(L_NOTICE, "Initializing NSM state");
535 if ((state & 1) == 0)
543 if (!nsm_atomic_write(path, &state, sizeof(state)))
553 * nsm_update_kernel_state - attempt to post new NSM state to kernel
554 * @state: NSM state number
558 nsm_update_kernel_state(const int state)
564 fd = open(NSM_KERNEL_STATE_FILE, O_WRONLY);
566 xlog(D_GENERAL, "Failed to open " NSM_KERNEL_STATE_FILE ": %m");
570 len = snprintf(buf, sizeof(buf), "%d", state);
571 if (error_check(len, sizeof(buf))) {
572 xlog_warn("Failed to form NSM state number string");
576 result = write(fd, buf, strlen(buf));
577 if (exact_error_check(result, strlen(buf)))
578 xlog_warn("Failed to write NSM state number: %m");
581 xlog(L_ERROR, "Failed to close NSM state file "
582 NSM_KERNEL_STATE_FILE ": %m");
586 * nsm_retire_monitored_hosts - back up all hosts from "sm/" to "sm.bak/"
588 * Returns the count of host records that were moved.
590 * Note that if any error occurs during this process, some monitor
591 * records may be left in the "sm" directory.
594 nsm_retire_monitored_hosts(void)
596 unsigned int count = 0;
601 path = nsm_make_pathname(NSM_MONITOR_DIR);
603 xlog(L_ERROR, "Failed to allocate path for " NSM_MONITOR_DIR);
610 xlog_warn("Failed to open " NSM_MONITOR_DIR ": %m");
614 while ((de = readdir(dir)) != NULL) {
618 if (de->d_name[0] == '.')
621 src = nsm_make_record_pathname(NSM_MONITOR_DIR, de->d_name);
623 xlog_warn("Bad monitor file name, skipping");
627 /* NB: not all file systems fill in d_type correctly */
628 if (lstat(src, &stb) == -1) {
629 xlog_warn("Bad monitor file %s, skipping: %m",
634 if (!S_ISREG(stb.st_mode)) {
635 xlog(D_GENERAL, "Skipping non-regular file %s",
641 dst = nsm_make_record_pathname(NSM_NOTIFY_DIR, de->d_name);
644 xlog_warn("Bad notify file name, skipping");
648 if (rename(src, dst) == -1)
649 xlog_warn("Failed to rename %s -> %s: %m",
652 xlog(D_GENERAL, "Retired record for mon_name %s",
666 * nsm_priv_to_hex - convert a NSM private cookie to a hex string.
668 * @priv: buffer holding the binary NSM private cookie
669 * @buf: output buffer for NULL terminated hex string
670 * @buflen: size of output buffer
672 * Returns the length of the resulting string or 0 on error
675 nsm_priv_to_hex(const char *priv, char *buf, const size_t buflen)
678 size_t remaining = buflen;
680 for (i = 0; i < SM_PRIV_SIZE; i++) {
681 len = snprintf(buf, remaining, "%02x",
682 (unsigned int)(0xff & priv[i]));
683 if (error_check(len, remaining))
686 remaining -= (size_t)len;
689 return buflen - remaining;
693 * Returns the length in bytes of the created record.
695 __attribute__((__noinline__))
697 nsm_create_monitor_record(char *buf, const size_t buflen,
698 const struct sockaddr *sap, const struct mon *m)
700 const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
701 size_t hexlen, remaining = buflen;
704 len = snprintf(buf, remaining, "%08x %08x %08x %08x ",
705 (unsigned int)sin->sin_addr.s_addr,
706 (unsigned int)m->mon_id.my_id.my_prog,
707 (unsigned int)m->mon_id.my_id.my_vers,
708 (unsigned int)m->mon_id.my_id.my_proc);
709 if (error_check(len, remaining))
712 remaining -= (size_t)len;
714 hexlen = nsm_priv_to_hex(m->priv, buf, remaining);
720 len = snprintf(buf, remaining, " %s %s\n",
721 m->mon_id.mon_name, m->mon_id.my_id.my_name);
722 if (error_check(len, remaining))
724 remaining -= (size_t)len;
726 return buflen - remaining;
730 nsm_append_monitored_host(const char *path, const char *line)
732 _Bool result = false;
739 if (stat(path, &stb) == -1) {
740 xlog(L_ERROR, "Failed to insert: "
741 "could not stat original file %s: %m", path);
744 buflen = (size_t)stb.st_size + strlen(line);
746 buf = malloc(buflen + 1);
748 xlog(L_ERROR, "Failed to insert: no memory");
751 memset(buf, 0, buflen + 1);
753 fd = open(path, O_RDONLY);
755 xlog(L_ERROR, "Failed to insert: "
756 "could not open original file %s: %m", path);
760 len = read(fd, buf, (size_t)stb.st_size);
761 if (exact_error_check(len, (size_t)stb.st_size)) {
762 xlog(L_ERROR, "Failed to insert: "
763 "could not read original file %s: %m", path);
771 if (nsm_atomic_write(path, buf, buflen))
780 * nsm_insert_monitored_host - write callback data for one host to disk
781 * @hostname: C string containing a hostname
782 * @sap: sockaddr containing NLM callback address
783 * @mon: SM_MON arguments to save
785 * Returns true if successful, otherwise false if some error occurs.
788 nsm_insert_monitored_host(const char *hostname, const struct sockaddr *sap,
791 static char buf[LINELEN + 1 + SM_MAXSTRLEN + 2];
793 _Bool result = false;
798 path = nsm_make_record_pathname(NSM_MONITOR_DIR, hostname);
800 xlog(L_ERROR, "Failed to insert: bad monitor hostname '%s'",
805 size = nsm_create_monitor_record(buf, sizeof(buf), sap, m);
807 xlog(L_ERROR, "Failed to insert: record too long");
812 * If exclusive create fails, we're adding a new line to an
815 fd = open(path, O_WRONLY | O_CREAT | O_EXCL | O_SYNC, S_IRUSR | S_IWUSR);
817 if (errno != EEXIST) {
818 xlog(L_ERROR, "Failed to insert: creating %s: %m", path);
822 result = nsm_append_monitored_host(path, buf);
827 len = write(fd, buf, size);
828 if (exact_error_check(len, size)) {
829 xlog_warn("Failed to insert: writing %s: %m", path);
834 if (close(fd) == -1) {
835 xlog(L_ERROR, "Failed to insert: closing %s: %m", path);
845 __attribute__((__noinline__))
847 nsm_parse_line(char *line, struct sockaddr_in *sin, struct mon *m)
853 c = strchr(line, '\n');
857 count = sscanf(line, "%8x %8x %8x %8x ",
858 (unsigned int *)&sin->sin_addr.s_addr,
859 (unsigned int *)&m->mon_id.my_id.my_prog,
860 (unsigned int *)&m->mon_id.my_id.my_vers,
861 (unsigned int *)&m->mon_id.my_id.my_proc);
865 c = line + RPCARGSLEN;
866 for (i = 0; i < SM_PRIV_SIZE; i++) {
867 if (sscanf(c, "%2x", &tmp) != 1)
869 m->priv[i] = (char)tmp;
874 m->mon_id.mon_name = c;
875 while (*c != '\0' && *c != ' ')
881 m->mon_id.my_id.my_name = c;
887 * Stuff a 'struct mon' with callback data, and call @func.
889 * Returns the count of in-core records created.
892 nsm_read_line(const char *hostname, const time_t timestamp, char *line,
895 struct sockaddr_in sin = {
896 .sin_family = AF_INET,
900 if (!nsm_parse_line(line, &sin, &m))
903 return func(hostname, (struct sockaddr *)(char *)&sin, &m, timestamp);
907 * Given a filename, reads data from a file under "directory"
908 * and invokes @func so caller can populate their in-core
909 * database with this data.
912 nsm_load_host(const char *directory, const char *filename, nsm_populate_t func)
914 char buf[LINELEN + 1 + SM_MAXSTRLEN + 2];
915 unsigned int result = 0;
920 path = nsm_make_record_pathname(directory, filename);
924 if (lstat(path, &stb) == -1) {
925 xlog(L_ERROR, "Failed to stat %s: %m", path);
928 if (!S_ISREG(stb.st_mode)) {
929 xlog(D_GENERAL, "Skipping non-regular file %s",
934 f = fopen(path, "r");
936 xlog(L_ERROR, "Failed to open %s: %m", path);
940 while (fgets(buf, (int)sizeof(buf), f) != NULL) {
941 buf[sizeof(buf) - 1] = '\0';
942 result += nsm_read_line(filename, stb.st_mtime, buf, func);
945 xlog(L_ERROR, "Failed to read monitor data from %s", path);
956 nsm_load_dir(const char *directory, nsm_populate_t func)
958 unsigned int count = 0;
963 path = nsm_make_pathname(directory);
965 xlog(L_ERROR, "Failed to allocate path for directory %s",
973 xlog(L_ERROR, "Failed to open directory %s: %m",
978 while ((de = readdir(dir)) != NULL) {
979 if (de->d_name[0] == '.')
982 count += nsm_load_host(directory, de->d_name, func);
990 * nsm_load_monitor_list - load list of hosts to monitor
991 * @func: callback function to create entry for one host
993 * Returns the count of hosts that were found in the directory.
996 nsm_load_monitor_list(nsm_populate_t func)
998 return nsm_load_dir(NSM_MONITOR_DIR, func);
1002 * nsm_load_notify_list - load list of hosts to notify
1003 * @func: callback function to create entry for one host
1005 * Returns the count of hosts that were found in the directory.
1008 nsm_load_notify_list(nsm_populate_t func)
1010 return nsm_load_dir(NSM_NOTIFY_DIR, func);
1014 nsm_delete_host(const char *directory, const char *hostname,
1015 const char *mon_name, const char *my_name)
1017 char line[LINELEN + 1 + SM_MAXSTRLEN + 2];
1018 char *outbuf = NULL;
1024 path = nsm_make_record_pathname(directory, hostname);
1026 xlog(L_ERROR, "Bad filename, not deleting");
1030 if (stat(path, &stb) == -1) {
1031 xlog(L_ERROR, "Failed to delete: "
1032 "could not stat original file %s: %m", path);
1035 remaining = (size_t)stb.st_size + 1;
1037 outbuf = malloc(remaining);
1038 if (outbuf == NULL) {
1039 xlog(L_ERROR, "Failed to delete: no memory");
1043 f = fopen(path, "r");
1045 xlog(L_ERROR, "Failed to delete: "
1046 "could not open original file %s: %m", path);
1051 * Walk the records in the file, and copy the non-matching
1052 * ones to our output buffer.
1055 while (fgets(line, (int)sizeof(line), f) != NULL) {
1056 struct sockaddr_in sin;
1060 if (!nsm_parse_line(line, &sin, &m)) {
1061 xlog(L_ERROR, "Failed to delete: "
1062 "could not parse original file %s", path);
1067 if (strcmp(mon_name, m.mon_id.mon_name) == 0 &&
1068 strcmp(my_name, m.mon_id.my_id.my_name) == 0)
1071 /* nsm_parse_line destroys the contents of line[], so
1072 * reconstruct the copy in our output buffer. */
1073 len = nsm_create_monitor_record(next, remaining,
1074 (struct sockaddr *)(char *)&sin, &m);
1076 xlog(L_ERROR, "Failed to delete: "
1077 "could not construct output record");
1088 * If nothing was copied when we're done, then unlink the file.
1089 * Otherwise, atomically update the contents of the file.
1091 if (next != outbuf) {
1092 if (!nsm_atomic_write(path, outbuf, strlen(outbuf)))
1093 xlog(L_ERROR, "Failed to delete: "
1094 "could not write new file %s: %m", path);
1096 if (unlink(path) == -1)
1097 xlog(L_ERROR, "Failed to delete: "
1098 "could not unlink file %s: %m", path);
1107 * nsm_delete_monitored_host - delete on-disk record for monitored host
1108 * @hostname: '\0'-terminated C string containing hostname of record to delete
1109 * @mon_name: '\0'-terminated C string containing monname of record to delete
1110 * @my_name: '\0'-terminated C string containing myname of record to delete
1114 nsm_delete_monitored_host(const char *hostname, const char *mon_name,
1115 const char *my_name)
1117 nsm_delete_host(NSM_MONITOR_DIR, hostname, mon_name, my_name);
1121 * nsm_delete_notified_host - delete on-disk host record after notification
1122 * @hostname: '\0'-terminated C string containing hostname of record to delete
1123 * @mon_name: '\0'-terminated C string containing monname of record to delete
1124 * @my_name: '\0'-terminated C string containing myname of record to delete
1128 nsm_delete_notified_host(const char *hostname, const char *mon_name,
1129 const char *my_name)
1131 nsm_delete_host(NSM_NOTIFY_DIR, hostname, mon_name, my_name);