return path;
}
+/*
+ * Returns a dynamically allocated, '\0'-terminated buffer
+ * containing an appropriate pathname, or NULL if an error
+ * occurs. Caller must free the returned result with free(3).
+ */
+__attribute_malloc__
+static char *
+nsm_make_temp_pathname(const char *pathname)
+{
+ size_t size;
+ char *path;
+ int len;
+
+ size = strlen(pathname) + sizeof(".new") + 2;
+ if (size > PATH_MAX)
+ return NULL;
+
+ path = malloc(size);
+ if (path == NULL)
+ return NULL;
+
+ len = snprintf(path, size, "%s.new", pathname);
+ if (error_check(len, size)) {
+ free(path);
+ return NULL;
+ }
+
+ return path;
+}
+
+/*
+ * Use "mktemp, write, rename" to update the contents of a file atomically.
+ *
+ * Returns true if completely successful, or false if some error occurred.
+ */
+static _Bool
+nsm_atomic_write(const char *path, const void *buf, const size_t buflen)
+{
+ _Bool result = false;
+ ssize_t len;
+ char *temp;
+ int fd;
+
+ temp = nsm_make_temp_pathname(path);
+ if (temp == NULL) {
+ xlog(L_ERROR, "Failed to create new path for %s", path);
+ goto out;
+ }
+
+ fd = open(temp, O_CREAT | O_TRUNC | O_SYNC | O_WRONLY, 0644);
+ if (fd == -1) {
+ xlog(L_ERROR, "Failed to create %s: %m", temp);
+ goto out;
+ }
+
+ len = write(fd, buf, buflen);
+ if (exact_error_check(len, buflen)) {
+ xlog(L_ERROR, "Failed to write %s: %m", temp);
+ (void)close(fd);
+ (void)unlink(temp);
+ goto out;
+ }
+
+ if (close(fd) == -1) {
+ xlog(L_ERROR, "Failed to close %s: %m", temp);
+ (void)unlink(temp);
+ goto out;
+ }
+
+ if (rename(temp, path) == -1) {
+ xlog(L_ERROR, "Failed to rename %s -> %s: %m",
+ temp, path);
+ (void)unlink(temp);
+ goto out;
+ }
+
+ /* Ostensibly, a sync(2) is not needed here because
+ * open(O_CREAT), write(O_SYNC), and rename(2) are
+ * already synchronous with persistent storage, for
+ * any file system we care about. */
+
+ result = true;
+
+out:
+ free(temp);
+ return result;
+}
+
/**
* nsm_setup_pathnames - set up pathname
* @progname: C string containing name of program, for error messages
int fd, state = 0;
ssize_t result;
char *path = NULL;
- char *newpath = NULL;
path = nsm_make_pathname(NSM_STATE_FILE);
if (path == NULL) {
if (update) {
state += 2;
-
- newpath = nsm_make_pathname(NSM_STATE_FILE ".new");
- if (newpath == NULL) {
- xlog(L_ERROR,
- "Failed to create path for " NSM_STATE_FILE ".new");
- state = 0;
- goto out;
- }
-
- fd = open(newpath, O_CREAT | O_SYNC | O_WRONLY, 0644);
- if (fd == -1) {
- xlog(L_ERROR, "Failed to create %s: %m", newpath);
- state = 0;
- goto out;
- }
-
- result = write(fd, &state, sizeof(state));
- if (exact_error_check(result, sizeof(state))) {
- xlog(L_ERROR, "Failed to write %s: %m", newpath);
- (void)close(fd);
- (void)unlink(newpath);
+ if (!nsm_atomic_write(path, &state, sizeof(state)))
state = 0;
- goto out;
- }
-
- if (close(fd) == -1) {
- xlog(L_ERROR, "Failed to close %s: %m", newpath);
- (void)unlink(newpath);
- state = 0;
- goto out;
- }
-
- if (rename(newpath, path) == -1) {
- xlog(L_ERROR, "Failed to rename %s -> %s: %m",
- newpath, path);
- (void)unlink(newpath);
- state = 0;
- goto out;
- }
-
- /* Ostensibly, a sync(2) is not needed here because
- * open(O_CREAT), write(O_SYNC), and rename(2) are
- * already synchronous with persistent storage, for
- * any file system we care about. */
}
out:
- free(newpath);
free(path);
return state;
}
return count;
}
+/*
+ * nsm_priv_to_hex - convert a NSM private cookie to a hex string.
+ *
+ * @priv: buffer holding the binary NSM private cookie
+ * @buf: output buffer for NULL terminated hex string
+ * @buflen: size of output buffer
+ *
+ * Returns the length of the resulting string or 0 on error
+ */
+size_t
+nsm_priv_to_hex(const char *priv, char *buf, const size_t buflen)
+{
+ int i, len;
+ size_t remaining = buflen;
+
+ for (i = 0; i < SM_PRIV_SIZE; i++) {
+ len = snprintf(buf, remaining, "%02x",
+ (unsigned int)(0xff & priv[i]));
+ if (error_check(len, remaining))
+ return 0;
+ buf += len;
+ remaining -= (size_t)len;
+ }
+
+ return buflen - remaining;
+}
+
/*
* Returns the length in bytes of the created record.
*/
const struct sockaddr *sap, const struct mon *m)
{
const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
- size_t remaining = buflen;
- int i, len;
+ size_t hexlen, remaining = buflen;
+ int len;
len = snprintf(buf, remaining, "%08x %08x %08x %08x ",
(unsigned int)sin->sin_addr.s_addr,
buf += len;
remaining -= (size_t)len;
- for (i = 0; i < SM_PRIV_SIZE; i++) {
- len = snprintf(buf, remaining, "%02x",
- (unsigned int)(0xff & m->priv[i]));
- if (error_check(len, remaining))
- return 0;
- buf += len;
- remaining -= (size_t)len;
- }
+ hexlen = nsm_priv_to_hex(m->priv, buf, remaining);
+ if (hexlen == 0)
+ return 0;
+ buf += hexlen;
+ remaining -= hexlen;
len = snprintf(buf, remaining, " %s %s\n",
m->mon_id.mon_name, m->mon_id.my_id.my_name);