/* attempt to arrange a writeable parent directory for <path> * Result indicates success. Failure will be logged. * * NOTE: this routine must not call our own logging facilities to report * an error since those routines are not re-entrant and such a call * would be recursive. */ static bool ensure_writeable_parent_directory(char *path) { /* NOTE: a / in the first char of a path is not like any other. * That is why the strchr starts at path + 1. */ char *e = strrchr(path + 1, '/'); /* end of directory prefix */ bool happy = TRUE; if (e != NULL) { /* path has an explicit directory prefix: deal with it */ /* Treat a run of slashes as one. * Remember that a / in the first char is different. */ while (e > path+1 && e[-1] == '/') e--; *e = '\0'; /* carve off dirname part of path */ if (access(path, W_OK) == 0) { /* mission accomplished, with no work */ } else if (errno != ENOENT) { /* cannot write to this directory for some reason * other than a missing directory */ syslog(LOG_CRIT, "can not write to %s: %s", path, strerror(errno)); happy = FALSE; } else { /* missing directory: try to create one */ happy = ensure_writeable_parent_directory(path); if (happy) { if (mkdir(path, 0750) != 0) { syslog(LOG_CRIT, "can not create dir %s: %s" , path, strerror(errno)); happy = FALSE; } } } *e = '/'; /* restore path to original form */ } return happy; }
/* open the per-peer log * * NOTE: this routine must not call our own logging facilities to report * an error since those routines are not re-entrant and such a call * would be recursive. */ static void open_peerlog(struct connection *c) { /* syslog(LOG_INFO, "opening log file for conn %s", c->name); */ if (c->log_file_name == NULL) { char peername[ADDRTOT_BUF], dname[ADDRTOT_BUF]; int peernamelen, lf_len; addrtot(&c->spd.that.host_addr, 'Q', peername, sizeof(peername)); peernamelen = strlen(peername); /* copy IP address, turning : and . into / */ { char ch, *p, *q; p = peername; q = dname; do { ch = *p++; if (ch == '.' || ch == ':') ch = '/'; *q++ = ch; } while (ch != '\0'); } lf_len = peernamelen * 2 + strlen(base_perpeer_logdir) + sizeof("//.log") + 1; c->log_file_name = alloc_bytes(lf_len, "per-peer log file name"); #if 0 fprintf(stderr, "base dir |%s| dname |%s| peername |%s|", base_perpeer_logdir, dname, peername); #endif snprintf(c->log_file_name, lf_len, "%s/%s/%s.log", base_perpeer_logdir, dname, peername); /* syslog(LOG_DEBUG, "conn %s logfile is %s", c->name, c->log_file_name); */ } /* now open the file, creating directories if necessary */ c->log_file_err = !ensure_writeable_parent_directory(c->log_file_name); if (c->log_file_err) return; c->log_file = fopen(c->log_file_name, "w"); if (c->log_file == NULL) { if (c->log_file_err) { syslog(LOG_CRIT, "logging system can not open %s: %s", c->log_file_name, strerror(errno)); c->log_file_err = TRUE; } return; } /* look for a connection to close! */ while (perpeer_count >= MAX_PEERLOG_COUNT) { /* can not be NULL because perpeer_count > 0 */ passert(perpeer_list.cqh_last != (void *)&perpeer_list); perpeer_logclose(perpeer_list.cqh_last); } /* insert this into the list */ CIRCLEQ_INSERT_HEAD(&perpeer_list, c, log_link); passert(c->log_file != NULL); perpeer_count++; }