Exemple #1
0
static int
nc_save_argv(int argc, char *const *argv)
{

    size_t     len;
    int  i;

    nc_os_argv = (char **) argv;
    nc_argc = argc;
    nc_argv = malloc((argc + 1) * sizeof(char *));
    if (nc_argv == NULL) {
        return NC_ERROR;
    }

    for (i = 0; i < argc; i++) {
        len = nc_strlen(argv[i]) + 1;

        nc_argv[i] = malloc(len);
        if (nc_argv[i] == NULL) {
            return NC_ERROR;
        }

        (void) nc_cpystrn((u_char *) nc_argv[i], (u_char *) argv[i], len);
    }

    nc_argv[i] = NULL;
    //nc_os_environ = environ;
    return NC_OK;
}
Exemple #2
0
struct server*
ffi_server_new(struct server_pool *pool, char *name, char *id, char *ip, int port)
{
    struct server *s;
    struct string address;
    rstatus_t status;

    s = nc_alloc(sizeof(struct server));
    if (s == NULL) {
        log_error("failed to allocate memory");
        return NULL;
    }

    s->owner = pool;
    s->idx = 0;
    s->weight = 1;
    /* set name */
    string_init(&s->name);
    string_copy(&s->name, (uint8_t*)name, (uint32_t)nc_strlen(name));
    string_init(&s->pname);
    string_copy(&s->pname, (uint8_t*)name, (uint32_t)nc_strlen(name));
    string_init(&address);
    string_copy(&address, (uint8_t*)ip, (uint32_t)nc_strlen(ip));
    /* set port */
    s->port = (uint16_t)port;

    status = nc_resolve(&address, s->port, &s->sockinfo);
    if (status != NC_OK) {
        log_error("conf: failed to resolve %.*s:%d", address.len, address.data, s->port);
        return NULL;
    }

    s->family = s->sockinfo.family;
    s->addrlen = s->sockinfo.addrlen;
    s->addr = (struct sockaddr *)&s->sockinfo.addr;

    s->ns_conn_q = 0;
    TAILQ_INIT(&s->s_conn_q);

    s->next_retry = 0LL;
    s->failure_count = 0;
    return s;
}
Exemple #3
0
int _ssl_init(nsp_state *N, TCP_SOCKET *sock, short srvmode, char *certfile, char *keyfile)
{
#define __FN__ __FILE__ ":_ssl_init()"
#if defined HAVE_OPENSSL
	SSL_load_error_strings();
	SSLeay_add_ssl_algorithms();
	if (srvmode) {
		sock->ssl_meth = (SSL_METHOD *)SSLv23_server_method();
	}
	else {
		sock->ssl_meth = (SSL_METHOD *)SSLv23_client_method();
	}
	sock->ssl_ctx = SSL_CTX_new(sock->ssl_meth);
	if (!sock->ssl_ctx) {
		n_warn(N, __FN__, "SSL Error");
		return -1;
	}
	if ((certfile == NULL) || (keyfile == NULL)) return 0;
	if (SSL_CTX_use_certificate_file(sock->ssl_ctx, certfile, SSL_FILETYPE_PEM) <= 0) {
		n_warn(N, __FN__, "SSL Error loading certificate '%s'", certfile);
		return -1;
	}
	if (SSL_CTX_use_PrivateKey_file(sock->ssl_ctx, keyfile, SSL_FILETYPE_PEM) <= 0) {
		n_warn(N, __FN__, "SSL Error loading private key '%s'", keyfile);
		return -1;
	}
	if (!SSL_CTX_check_private_key(sock->ssl_ctx)) {
		n_warn(N, __FN__, "Private key does not match the public certificate");
		return -1;
	}
	return 0;
#elif defined HAVE_MBEDTLS
	const char *pers = "ssl_server";
	int rc;

	mbedtls_ssl_config_init(&sock->conf);
	if ((rc = mbedtls_ssl_config_defaults(&sock->conf, srvmode ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
		n_warn(N, __FN__, "mbedtls_ssl_config_defaults failed.  error %d", rc);
		return -1;
	}
	mbedtls_ssl_conf_authmode(&sock->conf, MBEDTLS_SSL_VERIFY_NONE);
	mbedtls_entropy_init(&sock->entropy);
	mbedtls_ctr_drbg_init(&sock->ctr_drbg);
	if ((rc = mbedtls_ctr_drbg_seed(&sock->ctr_drbg, mbedtls_entropy_func, &sock->entropy, (const unsigned char *)pers, nc_strlen(pers))) != 0) {
		print_mbedtls_error(N, __FN__, rc);
		return -1;
	}
	mbedtls_ssl_conf_rng(&sock->conf, mbedtls_ctr_drbg_random, &sock->ctr_drbg);
	if ((certfile == NULL) || (keyfile == NULL)) {
		return 0;
		//if ((rc = mbedtls_x509_crt_parse(&sock->srvcert, (unsigned char *)mbedtls_test_srv_crt, nc_strlen(mbedtls_test_srv_crt))) != 0) {
		//	print_mbedtls_error(N, __FN__, rc);
		//	return -1;
		//}
		//if ((rc = mbedtls_x509_crt_parse(&sock->srvcert, (unsigned char *)mbedtls_test_ca_crt, nc_strlen(mbedtls_test_ca_crt))) != 0) {
		//	print_mbedtls_error(N, __FN__, rc);
		//	return -1;
		//}
		//if ((rc = mbedtls_pk_parse_key(&sock->pubkey, (unsigned char *)mbedtls_test_srv_key, nc_strlen(mbedtls_test_srv_key), NULL, 0)) != 0) {
		//	print_mbedtls_error(N, __FN__, rc);
		//	return -1;
		//}
	}
	else {
		if ((rc = mbedtls_x509_crt_parse_file(&sock->srvcert, certfile)) != 0) {
			//n_warn(N, __FN__, "x509_read_crtfile returned %08x", rc);
			print_mbedtls_error(N, __FN__, rc);
			return -1;
		}
		if ((rc = mbedtls_pk_parse_keyfile(&sock->pubkey, keyfile, NULL)) != 0) {
			//n_warn(N, __FN__, "x509_read_keyfile returned %08x", rc);
			print_mbedtls_error(N, __FN__, rc);
			return -1;
		}
	}
	mbedtls_ssl_conf_ca_chain(&sock->conf, sock->srvcert.next, NULL);
	if ((rc = mbedtls_ssl_conf_own_cert(&sock->conf, &sock->srvcert, &sock->pubkey)) != 0) {
		n_warn(N, __FN__, "mbedtls_ssl_conf_own_cert returned %08x", rc);
		return -1;
	}
	return 0;
#endif
#undef __FN__
}
Exemple #4
0
struct server *
sentinel_init(uint16_t sentinel_port, char *sentinel_ip)
{
    rstatus_t status;
    struct server *sentinel;
    struct string address;
    struct sockinfo info;
    char pname[NC_PNAME_MAXLEN];

    string_init(&address);

    sentinel_status = SENTINEL_CONN_DISCONNECTED;

    sentinel = (struct server *)nc_alloc(sizeof(*sentinel));
    if(sentinel == NULL) {
        goto error;
    }

    /* sentinel server don't have owner server pool */
    sentinel->owner = NULL;
    sentinel->ns_conn_q = 0;
    TAILQ_INIT(&sentinel->s_conn_q);
    sentinel->addr = NULL;
    string_init(&sentinel->pname);
    string_init(&sentinel->name);

    nc_snprintf(pname, NC_PNAME_MAXLEN, "%s:%d:0", sentinel_ip, sentinel_port);
    status = string_copy(&sentinel->pname, pname, (uint32_t)(nc_strlen(pname)));
    if (status != NC_OK) {
        goto error;
    }

    string_copy(&sentinel->name, pname, (uint32_t)(nc_strlen(pname)) - 2);
    if (status != NC_OK) {
        goto error;
    }

    sentinel->port = sentinel_port;

    status = string_copy(&address, sentinel_ip, (uint32_t)(nc_strlen(sentinel_ip)));
    if (status != NC_OK) {
        goto error;
    }

    status = nc_resolve(&address, sentinel_port, &info);
    if (status != NC_OK) {
        goto error;
    }

    sentinel->family = info.family;
    sentinel->addrlen = info.addrlen;
    sentinel->addr = (struct sockaddr*)nc_alloc(info.addrlen);
    if (sentinel->addr == NULL) {
        goto error;
    }
    nc_memcpy(sentinel->addr, &info.addr, info.addrlen);

done:
    string_deinit(&address);
    return sentinel;

error:
    sentinel_deinit(sentinel);
    sentinel = NULL;
    goto done;
}
Exemple #5
0
static rstatus_t
stats_master_send_rsp(int *psd)
{
    int n;
	ssize_t len;
    int sd;
	int i;
	nc_channel_msg_t     message;
	char buf[1000];
	memset(buf, 0, sizeof(char)*1000);
	char *snd_buf = NULL;

	memset(&message, 0, sizeof(nc_channel_msg_t));
	message.command = NC_CMD_GET_STATS;
	
	if (*psd) {
		sd = accept(*psd, NULL, NULL);
		if (sd < 0) {
	        log_error("accept on m %d failed: %s", sd, strerror(errno));
	        return NC_ERROR;
	    }
	}
	
	// still in reconfiguration process 
	if (nc_reload_start) {
		sprintf(buf, "%s", "no stats get due to still during reconfiguration period.");
		if (*psd) {
			len = nc_strlen(buf)+1;
			len = nc_sendn(sd, buf, len);
			if (len < 0) {
				log_error("send stats on sd %d failed: %s", sd, strerror(errno));

			}
			close(sd);
		}
		return NC_OK;
	}

	//broadcast
    for (i = 0; i < nc_last_process; i++) 
	{
        if (nc_processes[i].pid == -1 || nc_processes[i].pid == 0) 
		{
            continue;
        }
       
        if (nc_write_channel(nc_processes[i].channel[0],
                                  &message, sizeof(nc_channel_msg_t))
           == NC_OK)
        {
			if (nc_set_blocking(nc_processes[i].channel[0]) < 0) {
		    	log_error("set channel %d block failed while core timeout %s", 
		        nc_processes[i].channel[0] , strerror(errno));
				continue;
			}
		
			n = nc_read_channel(nc_processes[i].channel[0], &env_global.ctrl_msg, sizeof(nc_channel_msg_t));
			if (env_global.ctrl_msg.command != NC_CMD_GET_STATS || n < 0) {
				log_error("failure: get stats from worker %d receive length,  %s", 
		        nc_processes[i].channel[0] , strerror(errno));
			} else {
				log_error("success: get stats from worker %d receive length, %d", 
		        nc_processes[i].channel[0] , n);

				snd_buf = nc_alloc(n + n);				
				len = nc_recvn(nc_processes[i].channel[0], snd_buf, n);
				if (len < 0) {
					if (*psd) {
						log_error("recv stats on sd %d failed: %s", sd, strerror(errno));
					}
					nc_free(snd_buf);
					snd_buf = NULL;
        			continue;
				}
				if (*psd) {
					len = nc_sendn(sd, snd_buf, len);
					if (len < 0) {
						log_error("send stats on sd %d failed: %s", sd, strerror(errno));
						nc_free(snd_buf);
						snd_buf = NULL;
						continue;
					}
				}
	
				len = nc_write(env_global.stats_fd, snd_buf, len);
				if (len < 0) {
					log_error("nc_write %d failed: %s", env_global.stats_fd, strerror(errno));
					continue;
			    }

				
				nc_free(snd_buf);
				snd_buf = NULL;

			}

			

			if (nc_set_nonblocking(nc_processes[i].channel[0]) < 0) {
				log_error("set channel %d nonblock failed while core timeout %s", 
				        nc_processes[i].channel[0] , strerror(errno));
			}

        }
    }
	
	if (*psd) {
		shutdown(sd, SHUT_RDWR);
		close(sd);
	}
    return NC_OK;
}
Exemple #6
0
static rstatus_t
nc_get_options(int argc, char **argv, struct env_master *env)
{
    int c, value;
	int len;
	int cores;

    opterr = 0;
	//ASSERT(0);
	
    for (;;) {
        c = getopt_long(argc, argv, short_options, long_options, NULL);
        if (c == -1) {
            /* no more options */
            break;
        }

        switch (c) {
        case 'h':
            show_version = 1;
            show_help = 1;
            break;

        case 'V':
            show_version = 1;
            break;

        case 't':
            test_conf = 1;
            break;

        case 'd':
            daemonize = 1;
            break;

        case 'D':
            describe_stats = 1;
            show_version = 1;
            break;

        case 'v':
            value = nc_atoi(optarg, strlen(optarg));
            if (value < 0) {
                log_stderr("nutcracker: option -v requires a number");
                return NC_ERROR;
            }
            env->log_level = value;
            break;

        case 'o':
            env->log_filename = optarg;
			len = nc_strlen(optarg) + 1;
        	log_filename_global = malloc(len);
	        if (log_filename_global == NULL) {
	            return NC_ERROR;
	        }
            nc_cpystrn((u_char *) log_filename_global, (u_char *) optarg, len);
            break;

        case 'c':
            env->conf_filename = optarg;
			len = nc_strlen(optarg) + 1;
        	conf_filename_global = malloc(len);
	        if (conf_filename_global == NULL) {
	            return NC_ERROR;
	        }
            nc_cpystrn((u_char *) conf_filename_global, (u_char *) optarg, len);
			break;

        case 's':
            value = nc_atoi(optarg, strlen(optarg));
            if (value < 0) {
                log_stderr("nutcracker: option -s requires a number");
                return NC_ERROR;
            }
            if (!nc_valid_port(value)) {
                log_stderr("nutcracker: option -s value %d is not a valid "
                           "port", value);
                return NC_ERROR;
            }

            env->stats_port = (uint16_t)value;
            break;

        case 'i':
            value = nc_atoi(optarg, strlen(optarg));
            if (value < 0) {
                log_stderr("nutcracker: option -i requires a number");
                return NC_ERROR;
            }

            env->stats_interval = value;
            break;

        case 'a':
            env->stats_addr = optarg;
            break;

        case 'p':
            env->pid_filename = optarg;
            break;

        case 'm':
            value = nc_atoi(optarg, strlen(optarg));
            if (value <= 0) {
                log_stderr("nutcracker: option -m requires a non-zero number");
                return NC_ERROR;
            }

            if (value < NC_MBUF_MIN_SIZE || value > NC_MBUF_MAX_SIZE) {
                log_stderr("nutcracker: mbuf chunk size must be between %zu and" \
                           " %zu bytes", NC_MBUF_MIN_SIZE, NC_MBUF_MAX_SIZE);
                return NC_ERROR;
            }

            env->mbuf_chunk_size = (size_t)value;
            break;

		case 'n':
			value = nc_atoi(optarg, strlen(optarg));
            if (value <= 0) {
                log_stderr("nutcracker: option -n requires a non-zero number");
                return NC_ERROR;
            }
			
			cores = sysconf(_SC_NPROCESSORS_ONLN);
			
            if (value > cores || value < 1) {
                log_stderr("bilitw: bilitw worker process number should be between %d and" \
                           " %d", 1, cores);
                return NC_ERROR;
            }
            env->worker_processes= value;			
			break;
		case 'M':
			value = nc_atoi(optarg, strlen(optarg));
            if (value <= 0) {
                log_stderr("nutcracker: option -M requires a non-zero number");
                return NC_ERROR;
            }
			cores = sysconf(_SC_NPROCESSORS_ONLN);
			cores = (1<<cores) -1;

            if (value > cores || value < 1) {
                log_stderr("bilitw: bilitw worker process cpu mask should be set between %d and" \
                           " %d", 1, cores);
                return NC_ERROR;
            } 
			env->cpu_mask = value;
			break;

        case '?':
            switch (optopt) {
            case 'o':
            case 'c':
            case 'p':
                log_stderr("nutcracker: option -%c requires a file name",
                           optopt);
                break;

            case 'm':
            case 'v':
            case 's':
            case 'i':
			case 'n':
			case 'M':
                log_stderr("nutcracker: option -%c requires a number", optopt);
                break;

            case 'a':
                log_stderr("nutcracker: option -%c requires a string", optopt);
                break;

            default:
                log_stderr("nutcracker: invalid option -- '%c'", optopt);
                break;
            }
            return NC_ERROR;

        default:
            log_stderr("nutcracker: invalid option -- '%c'", optopt);
            return NC_ERROR;

        }
    }

    return NC_OK;
}
Exemple #7
0
uchar   *n_decompose(nsp_state *N, char *srcfile, uchar *srctext, uchar **dsttext, int *dstsize)
{
#define __FN__ __FILE__ ":n_decompose()"
	cstate state;
	obj_t *cobj, *tobj;
	unsigned short op;
	uchar *p, *p2;

	settrace();

	*dsttext = NULL;
	*dstsize = 0;

	if ((srctext[0] == 0x0D) && ((srctext[1] == 0xAC))) {
		n_warn(N, __FN__, "already chewed on this");
		return srctext;
	}
	nc_memset((char *)&state, 0, sizeof(state));
	state.lineno = 1;
	state.destmax = 1024;
	state.destbuf = (uchar *)n_alloc(N, state.destmax, 0);
	N->readptr = srctext;
	tobj = nsp_settable(N, &N->g, "decomped_script");
	nsp_freetable(N, tobj);
	state.tobj1 = nsp_settable(N, tobj, "code");
	n_decompose_sub(N, &state);
	/* header - 8 bytes */
	testgrow(8); /* safe portable use of sprintf is still considered dangerous according to openbsd */
	state.destbuf[state.offset++] = 0x0D;
	state.destbuf[state.offset++] = 0xAC;
	state.destbuf[state.offset++] = 0;
	state.destbuf[state.offset++] = 0;
	state.destbuf[state.offset++] = 0;
	state.destbuf[state.offset++] = 0;
	state.destbuf[state.offset++] = 0;
	state.destbuf[state.offset++] = 0;
	/* file size - 4 bytes */
	state.destbuf[state.offset++] = 0;
	state.destbuf[state.offset++] = 0;
	state.destbuf[state.offset++] = 0;
	state.destbuf[state.offset++] = 0;
	/* optab offset  - 4 bytes (little endian) */
	state.destbuf[state.offset++] = 0;
	state.destbuf[state.offset++] = 0;
	state.destbuf[state.offset++] = 0;
	state.destbuf[state.offset++] = 0;
	/* symtab offset - 4 bytes (little endian) */
	state.destbuf[state.offset++] = 0;
	state.destbuf[state.offset++] = 0;
	state.destbuf[state.offset++] = 0;
	state.destbuf[state.offset++] = 0;
	/* now write the ops */
	/* optab offset */
	writei4(state.offset, (state.destbuf + 12));
	/* set line number to 1 */
	testgrow((long)(5));
	state.destbuf[state.offset++] = OP_LINENUM;
	writei4(1, (state.destbuf + state.offset));
	state.offset += 4;

	for (cobj = state.tobj1->val->d.table.f; cobj; cobj = cobj->next) {
		op = (unsigned short)cobj->val->attr;
		cobj->val->attr = 0;
		if (op == OP_LINENUM) {
			testgrow((long)(5));
			state.destbuf[state.offset++] = op & 255;
			writei4((int)cobj->val->d.num, (state.destbuf + state.offset));
			state.offset += 4;
			continue;
		}
		if (!nsp_isstr(cobj)) break;
		if (op == OP_UNDEFINED) break;
		if (op == OP_POBRACE) {
			testgrow((long)(5));
			state.destbuf[state.offset++] = op & 255;
			writei4(0, (state.destbuf + state.offset));
			state.offset += 4;
			continue;
		}
		else if (op == OP_POPAREN) {
			testgrow((long)(3));
			state.destbuf[state.offset++] = op & 255;
			writei2(0, (state.destbuf + state.offset));
			state.offset += 2;
			continue;
		}
		else if (op == OP_STRDATA || op == OP_ESTRDATA) {
			testgrow((long)(6 + cobj->val->size));
			state.destbuf[state.offset++] = op & 255;
			writei4(cobj->val->size, (state.destbuf + state.offset));
			state.offset += 4;
			nc_memcpy((char *)state.destbuf + state.offset, cobj->val->d.str, cobj->val->size);
			state.offset += cobj->val->size;
			state.destbuf[state.offset++] = 0;
		}
		else if (op == OP_NUMDATA) {
			testgrow((long)(3 + cobj->val->size));
			state.destbuf[state.offset++] = op & 255;
			state.destbuf[state.offset++] = (uchar)(cobj->val->size & 255);
			nc_memcpy((char *)state.destbuf + state.offset, cobj->val->d.str, cobj->val->size);
			state.offset += cobj->val->size;
			state.destbuf[state.offset++] = 0;
		}
		else if (op == OP_LABEL) {
			testgrow((long)(3 + cobj->val->size));
			state.destbuf[state.offset++] = op & 255;
			state.destbuf[state.offset++] = (uchar)(cobj->val->size & 255);
			nc_memcpy((char *)state.destbuf + state.offset, cobj->val->d.str, cobj->val->size);
			state.offset += cobj->val->size;
			state.destbuf[state.offset++] = '\0';
		}
		else if (OP_ISMATH(op) || OP_ISKEY(op) || OP_ISPUNC(op)) {
			testgrow(1);
			state.destbuf[state.offset++] = op & 255;
			if (op == OP_KFUNC) {
				char *p = srcfile;

				//n_warn(N, __FN__, "'%s'", p);
				if (cobj->next->val->attr == OP_LABEL) {
					cobj = cobj->next;
					op = (unsigned short)cobj->val->attr;
					cobj->val->attr = 0;
					testgrow((long)(3 + cobj->val->size));
					state.destbuf[state.offset++] = op & 255;
					state.destbuf[state.offset++] = (uchar)(cobj->val->size & 255);
					nc_memcpy((char *)state.destbuf + state.offset, cobj->val->d.str, cobj->val->size);
					state.offset += cobj->val->size;
					state.destbuf[state.offset++] = '\0';
				}
				if (srcfile == NULL) p = "";
				testgrow((long)(3 + nc_strlen(p)));
				state.destbuf[state.offset++] = OP_LABEL;
				state.destbuf[state.offset++] = (uchar)(nc_strlen(p) & 255);
				nc_memcpy((char *)state.destbuf + state.offset, p, nc_strlen(p));
				state.offset += nc_strlen(p);
				state.destbuf[state.offset++] = '\0';
			}
		}
		else {
			n_warn(N, __FN__, "bad op?");
		}
	}
	/* file size */
	writei4(state.offset, (state.destbuf + 8));
	/* add some trailing nulls for fun... */
	testgrow(4); writei4(0, (state.destbuf + state.offset));
	state.offset += 4;
	/* n_dumpvars(N, &N->g, 0); */
	nsp_freetable(N, tobj);
	*dsttext = state.destbuf;
	*dstsize = state.destmax;
	for (p = *dsttext + 12; p < *dsttext + state.offset - 4;) {
		if (*p == OP_LINENUM) { p += 5; continue; }
		if (*p == OP_POBRACE) {
			p2 = n_seekop(N, p, 1);
			if (p2 <= p) {
				n_warn(N, __FN__, "pointer did not progress");
				break;
			}
			--p2;
			// if (*p2!=OP_PCBRACE) n_warn(N, __FN__, "no OP_PCBRACE? %d", (p+(p2-p)+5)[0]);
			if (*p2 != OP_PCBRACE) {
				/*
				int i;
				for (i=0;i<state.offset;i++) {
				if (i==p2-*dsttext) {
				printf("-----------------------\r\n[%d]\r\n-------------------", state.destbuf[i]);
				} else {
				if (state.destbuf[i]>=32 && state.destbuf[i]<128) {
				printf("'%c' %d\r\n", state.destbuf[i], state.destbuf[i]);
				} else {
				printf("%d\r\n", state.destbuf[i]);
				}
				}
				}
				*/
				n_warn(N, __FN__, "no OP_PCBRACE? %d .. %d %d %d %d [%d] %d %d", OP_PCBRACE, p2[-4], p2[-3], p2[-2], p2[-1], p2[0], p2[1], p2[2]);
				//n_decompile(N, *dsttext+12, *dsttext+state.offset-4, NULL, 0);
			}
			writei4((p2 - p - 5), (p + 1));
		}
		else if (*p == OP_POPAREN) {
			p2 = n_seekop(N, p, 1);
			if (p2 <= p) {
				n_warn(N, __FN__, "pointer did not progress");
				break;
			}
			--p2;
			if (*p2 != OP_PCPAREN) {
				n_warn(N, __FN__, "no OP_PCPAREN? %d .. %d %d %d %d [%d] %d %d", OP_PCPAREN, p2[-4], p2[-3], p2[-2], p2[-1], p2[0], p2[1], p2[2]);
			}
			writei2((p2 - p - 3), (p + 1));
		}
		p = n_seekop(N, p, 0);
	}
	return *dsttext;
#undef __FN__
}