void sig_handler_common_tt(int sig, void *sc_ptr) { struct sigcontext *sc = sc_ptr; struct tt_regs save_regs, *r; struct signal_info *info; int save_errno = errno, is_user; unprotect_kernel_mem(); r = &TASK_REGS(get_current())->tt; save_regs = *r; is_user = user_context(SC_SP(sc)); r->sc = sc; if(sig != SIGUSR2) r->syscall = -1; change_sig(SIGUSR1, 1); info = &sig_info[sig]; if(!info->is_irq) unblock_signals(); (*info->handler)(sig, (union uml_pt_regs *) r); if(is_user){ interrupt_end(); block_signals(); change_sig(SIGUSR1, 0); set_user_mode(NULL); } *r = save_regs; errno = save_errno; if(is_user) protect_kernel_mem(); }
/*! \brief MODE command handler * * \param source_p Pointer to allocated Client struct from which the message * originally comes from. This can be a local or remote client. * \param parc Integer holding the number of supplied arguments. * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL * pointers. * \note Valid arguments for this command are: * - parv[0] = command * - parv[1] = channel or nick name * - parv[2] = modes to be added or removed */ static int m_mode(struct Client *source_p, int parc, char *parv[]) { struct Channel *chptr = NULL; if (EmptyString(parv[1])) { sendto_one_numeric(source_p, &me, ERR_NEEDMOREPARAMS, "MODE"); return 0; } /* Now, try to find the channel in question */ if (!IsChanPrefix(*parv[1])) { /* If here, it has to be a non-channel name */ set_user_mode(source_p, parc, parv); return 0; } if ((chptr = hash_find_channel(parv[1])) == NULL) { sendto_one_numeric(source_p, &me, ERR_NOSUCHCHANNEL, parv[1]); return 0; } /* Now known the channel exists */ if (parc < 3) { char modebuf[MODEBUFLEN] = ""; char parabuf[MODEBUFLEN] = ""; channel_modes(chptr, source_p, modebuf, parabuf); sendto_one_numeric(source_p, &me, RPL_CHANNELMODEIS, chptr->name, modebuf, parabuf); sendto_one_numeric(source_p, &me, RPL_CREATIONTIME, chptr->name, chptr->creationtime); return 0; } /* * bounce all modes from people we deop on sjoin * servers have always gotten away with murder, * including telnet servers *g* - Dianora */ if (IsServer(source_p) || HasFlag(source_p, FLAGS_SERVICE)) set_channel_mode(source_p, chptr, NULL, parc - 2, parv + 2); else { struct Membership *member = find_channel_link(source_p, chptr); /* Finish the flood grace period... */ if (MyClient(source_p) && !IsFloodDone(source_p)) if (!((parc == 3) && (parv[2][0] == 'b') && (parv[2][1] == '\0'))) flood_endgrace(source_p); set_channel_mode(source_p, chptr, member, parc - 2, parv + 2); } return 0; }
int ms_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { struct Channel *chptr = 0; struct ModeBuf mbuf; struct Membership *member = 0; if (parc < 3) return need_more_params(sptr, "MODE"); if (IsLocalChannel(parv[1])) return 0; if (!(chptr = FindChannel(parv[1]))) return set_user_mode(cptr, sptr, parc, parv); ClrFlag(sptr, FLAG_TS8); if (IsServer(sptr)) { if (cli_uworld(sptr)) modebuf_init(&mbuf, sptr, cptr, chptr, (MODEBUF_DEST_CHANNEL | /* Send mode to clients */ MODEBUF_DEST_SERVER | /* Send mode to servers */ MODEBUF_DEST_HACK4)); /* Send a HACK(4) message */ else modebuf_init(&mbuf, sptr, cptr, chptr, (MODEBUF_DEST_CHANNEL | /* Send mode to clients */ MODEBUF_DEST_SERVER | /* Send mode to servers */ MODEBUF_DEST_HACK3)); /* Send a HACK(3) message */ mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2, (MODE_PARSE_SET | /* Set the mode */ MODE_PARSE_STRICT | /* Interpret it strictly */ MODE_PARSE_FORCE), NULL); /* And force it to be accepted */ } else { if (!IsChannelService(sptr) && (!(member = find_member_link(chptr, sptr)) || (!IsChanOp(member) && !IsHalfOp(member)))) { modebuf_init(&mbuf, sptr, cptr, chptr, (MODEBUF_DEST_SERVER | /* Send mode to server */ MODEBUF_DEST_HACK2 | /* Send a HACK(2) message */ MODEBUF_DEST_DEOP | /* Deop the source */ MODEBUF_DEST_BOUNCE)); /* And bounce the MODE */ mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2, (MODE_PARSE_STRICT | /* Interpret it strictly */ MODE_PARSE_BOUNCE), member); /* And bounce the MODE */ } else { modebuf_init(&mbuf, sptr, cptr, chptr, (MODEBUF_DEST_CHANNEL | /* Send mode to clients */ MODEBUF_DEST_SERVER)); /* Send mode to servers */ mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2, (MODE_PARSE_SET | /* Set the mode */ MODE_PARSE_STRICT | /* Interpret it strictly */ MODE_PARSE_FORCE), member); /* And force it to be accepted */ } } return modebuf_flush(&mbuf); }
void sig_handler_common_tt(int sig, void *sc_ptr) { struct sigcontext *sc = sc_ptr; struct tt_regs save_regs, *r; struct signal_info *info; int save_errno = errno, is_user; unprotect_kernel_mem(); /* This is done because to allow SIGSEGV to be delivered inside a SEGV * handler. This can happen in copy_user, and if SEGV is disabled, * the process will die. */ if(sig == SIGSEGV) change_sig(SIGSEGV, 1); /* This is done because to allow SIGSEGV to be delivered inside a SEGV * handler. This can happen in copy_user, and if SEGV is disabled, * the process will die. */ if(sig == SIGSEGV) change_sig(SIGSEGV, 1); r = &TASK_REGS(get_current())->tt; save_regs = *r; is_user = user_context(SC_SP(sc)); r->sc = sc; if(sig != SIGUSR2) r->syscall = -1; info = &sig_info[sig]; if(!info->is_irq) unblock_signals(); (*info->handler)(sig, (union uml_pt_regs *) r); if(is_user){ interrupt_end(); block_signals(); set_user_mode(NULL); } *r = save_regs; errno = save_errno; if(is_user) protect_kernel_mem(); }
void finish_fork_handler(int sig) { UPT_SC(¤t->thread.regs.regs) = (void *) (&sig + 1); suspend_new_thread(current->thread.mode.tt.switch_pipe[0]); force_flush_all(); if(current->thread.prev_sched != NULL) schedule_tail(current->thread.prev_sched); current->thread.prev_sched = NULL; enable_timer(); change_sig(SIGVTALRM, 1); local_irq_enable(); if(current->mm != current->parent->mm) protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1); task_protections((unsigned long) current_thread); free_page(current->thread.temp_stack); local_irq_disable(); change_sig(SIGUSR1, 0); set_user_mode(current); }
/* * m_mode - MODE command handler * parv[0] - sender * parv[1] - channel */ static void m_mode(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Channel *chptr = NULL; struct Membership *member; static char modebuf[MODEBUFLEN]; static char parabuf[MODEBUFLEN]; if (parv[1][0] == '\0') { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "MODE"); return; } /* Now, try to find the channel in question */ if (!IsChanPrefix(parv[1][0])) { /* if here, it has to be a non-channel name */ set_user_mode(client_p, source_p, parc, parv); return; } if (!check_channel_name(parv[1])) { sendto_one(source_p, form_str(ERR_BADCHANNAME), me.name, source_p->name, parv[1]); return; } chptr = hash_find_channel(parv[1]); if (chptr == NULL) { /* if chptr isn't found locally, it =could= exist * on the uplink. So ask. */ /* LazyLinks */ /* only send a mode upstream if a local client sent this request * -davidt */ if (MyClient(source_p) && !ServerInfo.hub && uplink && IsCapable(uplink, CAP_LL)) { sendto_one(uplink, ":%s MODE %s %s", ID_or_name(source_p, uplink), parv[1], (parv[2] ? parv[2] : "")); return; } else { sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), me.name, parv[0], parv[1]); return; } } /* Now known the channel exists */ if (parc < 3) { channel_modes(chptr, source_p, modebuf, parabuf); sendto_one(source_p, form_str(RPL_CHANNELMODEIS), me.name, parv[0], parv[1], modebuf, parabuf); sendto_one(source_p, form_str(RPL_CREATIONTIME), me.name, parv[0], parv[1], chptr->channelts); } /* bounce all modes from people we deop on sjoin * servers have always gotten away with murder, * including telnet servers *g* - Dianora * * XXX Is it worth the bother to make an ms_mode() ? - Dianora */ else if (IsServer(source_p)) { set_channel_mode(client_p, source_p, chptr, NULL, parc - 2, parv + 2, chptr->chname); } else { member = find_channel_link(source_p, chptr); if (!has_member_flags(member, CHFL_DEOPPED)) { /* Finish the flood grace period... */ if (MyClient(source_p) && !IsFloodDone(source_p)) { if (!((parc == 3) && (parv[2][0] == 'b') && (parv[2][1] == '\0'))) flood_endgrace(source_p); } set_channel_mode(client_p, source_p, chptr, member, parc - 2, parv + 2, chptr->chname); } } }
int m_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { struct Channel *chptr = 0; unsigned int hoflags = 0; struct ModeBuf mbuf; struct Membership *member = 0; if (parc < 2) return need_more_params(sptr, "MODE"); clean_channelname(parv[1]); if (!(chptr = FindChannel(parv[1]))) return set_user_mode(cptr, sptr, parc, parv); ClrFlag(sptr, FLAG_TS8); member = find_member_link(chptr, sptr); if (parc < 3) { char modebuf[MODEBUFLEN]; char parabuf[MODEBUFLEN]; *modebuf = *parabuf = '\0'; modebuf[1] = '\0'; channel_modes(sptr, modebuf, parabuf, sizeof(parabuf), chptr); send_reply(sptr, RPL_CHANNELMODEIS, chptr->chname, modebuf, parabuf); send_reply(sptr, RPL_CREATIONTIME, chptr->chname, chptr->creationtime); return 0; } if ((!member && !IsChannelService(sptr)) || (member && !IsChanOp(member) && !IsHalfOp(member))) { if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_MODE_LCHAN)) { modebuf_init(&mbuf, sptr, cptr, chptr, (MODEBUF_DEST_CHANNEL | /* Send mode to channel */ MODEBUF_DEST_HACK4)); /* Send HACK(4) notice */ mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2, (MODE_PARSE_SET | /* Set the mode */ MODE_PARSE_FORCE), NULL); /* Force it to take */ return modebuf_flush(&mbuf); } else mode_parse(0, cptr, sptr, chptr, parc - 2, parv + 2, (member ? MODE_PARSE_NOTOPER : MODE_PARSE_NOTMEMBER), NULL); return 0; } modebuf_init(&mbuf, sptr, cptr, chptr, (MODEBUF_DEST_CHANNEL | /* Send mode to channel */ MODEBUF_DEST_SERVER)); /* Send mode to servers */ if (member && IsChanOp(member)) hoflags = MODE_PARSE_SET; /* set unconditionally */ else if (member && IsHalfOp(member)) hoflags = MODE_PARSE_ISHALFOP|MODE_PARSE_SET|MODE_PARSE_NOTOPER; /* allowed to +v */ else hoflags = MODE_PARSE_NOTOPER; mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2, hoflags, member); return modebuf_flush(&mbuf); }
int ms_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { struct Channel *chptr = 0; struct ModeBuf mbuf; struct Membership *member; if (parc < 3) return need_more_params(sptr, "MODE"); if (IsLocalChannel(parv[1])) return 0; if (!(chptr = FindChannel(parv[1]))) { struct Client *acptr; acptr = FindUser(parv[1]); if (!acptr) { return 0; } else if (sptr != acptr) { sendwallto_group_butone(&me, WALL_WALLOPS, 0, "MODE for User %s from %s!%s", parv[1], cli_name(cptr), cli_name(sptr)); return 0; } return set_user_mode(cptr, sptr, parc, parv, ALLOWMODES_ANY); } ClrFlag(sptr, FLAG_TS8); if (IsServer(sptr)) { if (find_conf_byhost(cli_confs(cptr), cli_name(sptr), CONF_UWORLD)) modebuf_init(&mbuf, sptr, cptr, chptr, (MODEBUF_DEST_CHANNEL | /* Send mode to clients */ MODEBUF_DEST_SERVER | /* Send mode to servers */ MODEBUF_DEST_HACK4)); /* Send a HACK(4) message */ else if (!feature_bool(FEAT_OPLEVELS)) modebuf_init(&mbuf, sptr, cptr, chptr, (MODEBUF_DEST_CHANNEL | /* Send mode to clients */ MODEBUF_DEST_SERVER | /* Send mode to servers */ MODEBUF_DEST_HACK3)); /* Send a HACK(3) message */ else /* Servers need to be able to op people who join using the Apass * or upass, as well as people joining a zannel, therefore we do * not generate HACK3 when oplevels are on. */ modebuf_init(&mbuf, sptr, cptr, chptr, (MODEBUF_DEST_CHANNEL | /* Send mode to clients */ MODEBUF_DEST_SERVER)); /* Send mode to servers */ mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2, (MODE_PARSE_SET | /* Set the mode */ MODE_PARSE_STRICT | /* Interpret it strictly */ MODE_PARSE_FORCE), /* And force it to be accepted */ NULL); } else { if (!(member = find_member_link(chptr, sptr)) || !IsChanOp(member)) { modebuf_init(&mbuf, sptr, cptr, chptr, (MODEBUF_DEST_SERVER | /* Send mode to server */ MODEBUF_DEST_HACK2 | /* Send a HACK(2) message */ MODEBUF_DEST_DEOP | /* Deop the source */ MODEBUF_DEST_BOUNCE)); /* And bounce the MODE */ mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2, (MODE_PARSE_STRICT | /* Interpret it strictly */ MODE_PARSE_BOUNCE), /* And bounce the MODE */ member); } else { modebuf_init(&mbuf, sptr, cptr, chptr, (MODEBUF_DEST_CHANNEL | /* Send mode to clients */ MODEBUF_DEST_SERVER)); /* Send mode to servers */ mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2, (MODE_PARSE_SET | /* Set the mode */ MODE_PARSE_STRICT | /* Interpret it strictly */ MODE_PARSE_FORCE), /* And force it to be accepted */ member); } } return modebuf_flush(&mbuf); }
int m_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { struct Channel *chptr = 0; struct ModeBuf mbuf; struct Membership *member; if (parc < 2) return need_more_params(sptr, "MODE"); if (!IsChannelName(parv[1]) || !(chptr = FindChannel(parv[1]))) { struct Client *acptr; acptr = FindUser(parv[1]); if (!acptr) { send_reply(sptr, ERR_NOSUCHCHANNEL, parv[1]); return 0; } else if (sptr != acptr) { send_reply(sptr, ERR_USERSDONTMATCH); return 0; } return set_user_mode(cptr, sptr, parc, parv, ALLOWMODES_ANY); } ClrFlag(sptr, FLAG_TS8); member = find_member_link(chptr, sptr); if (parc < 3) { char modebuf[MODEBUFLEN]; char parabuf[MODEBUFLEN]; *modebuf = *parabuf = '\0'; modebuf[1] = '\0'; channel_modes(sptr, modebuf, parabuf, sizeof(parabuf), chptr, member); send_reply(sptr, RPL_CHANNELMODEIS, chptr->chname, modebuf, parabuf); send_reply(sptr, RPL_CREATIONTIME, chptr->chname, chptr->creationtime); return 0; } if (!member || !IsChanOp(member)) { if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_MODE_LCHAN)) { modebuf_init(&mbuf, sptr, cptr, chptr, (MODEBUF_DEST_CHANNEL | /* Send mode to channel */ MODEBUF_DEST_HACK4)); /* Send HACK(4) notice */ mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2, (MODE_PARSE_SET | /* Set the mode */ MODE_PARSE_FORCE), /* Force it to take */ member); return modebuf_flush(&mbuf); } else mode_parse(0, cptr, sptr, chptr, parc - 2, parv + 2, (member ? MODE_PARSE_NOTOPER : MODE_PARSE_NOTMEMBER), member); return 0; } modebuf_init(&mbuf, sptr, cptr, chptr, (MODEBUF_DEST_CHANNEL | /* Send mode to channel */ MODEBUF_DEST_SERVER)); /* Send mode to servers */ mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2, MODE_PARSE_SET, member); return modebuf_flush(&mbuf); }
/* * m_mode - MODE command handler * parv[0] - sender * parv[1] - channel */ static void m_mode(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Channel *chptr = NULL; struct Membership *member; static char modebuf[MODEBUFLEN]; static char parabuf[MODEBUFLEN]; if (EmptyString(parv[1])) { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "MODE"); return; } /* Now, try to find the channel in question */ if (!IsChanPrefix(*parv[1])) { /* if here, it has to be a non-channel name */ set_user_mode(client_p, source_p, parc, parv); return; } if ((chptr = hash_find_channel(parv[1])) == NULL) { sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL), ID_or_name(&me, source_p->from), ID_or_name(source_p, source_p->from), parv[1]); return; } /* Now known the channel exists */ if (parc < 3) { channel_modes(chptr, source_p, modebuf, parabuf); sendto_one(source_p, form_str(RPL_CHANNELMODEIS), me.name, source_p->name, chptr->chname, modebuf, parabuf); sendto_one(source_p, form_str(RPL_CREATIONTIME), me.name, source_p->name, chptr->chname, chptr->channelts); } /* bounce all modes from people we deop on sjoin * servers have always gotten away with murder, * including telnet servers *g* - Dianora * * XXX Is it worth the bother to make an ms_mode() ? - Dianora */ else if (IsServer(source_p)) { set_channel_mode(client_p, source_p, chptr, NULL, parc - 2, parv + 2, chptr->chname); } else { member = find_channel_link(source_p, chptr); if (!has_member_flags(member, CHFL_DEOPPED)) { /* Finish the flood grace period... */ if (MyClient(source_p) && !IsFloodDone(source_p)) { if (!((parc == 3) && (parv[2][0] == 'b') && (parv[2][1] == '\0'))) flood_endgrace(source_p); } set_channel_mode(client_p, source_p, chptr, member, parc - 2, parv + 2, chptr->chname); } } }
void do_oper(struct Client* cptr, struct Client* sptr, struct ConfItem* aconf) { struct Flags old_mode = cli_flags(sptr); char* modes; char* parv[2]; char* join[3]; char chan[CHANNELLEN-1]; char* ajoinchan; char* ajoinnotice; unsigned int snomask = 0; parv[0] = cli_name(sptr); parv[1] = NULL; SetOper(sptr); client_set_privs(sptr, aconf); ClearOper(sptr); snomask = ConfSnoMask(aconf) & SNO_ALL; snomask |= aconf->snomask & SNO_ALL; ajoinchan = ConfAjoinChan(aconf); ajoinnotice = ConfAjoinNotice(aconf); if (MyUser(sptr)) { SetLocOp(sptr); if (HasPriv(sptr, PRIV_PROPAGATE)) { ClearLocOp(sptr); SetOper(sptr); if (HasPriv(sptr, PRIV_ADMIN)) SetAdmin(sptr); if (!IsHideOper(sptr) && !IsChannelService(sptr) && !IsBot(sptr)) ++UserStats.opers; } cli_handler(sptr) = OPER_HANDLER; SetFlag(sptr, FLAG_WALLOP); SetFlag(sptr, FLAG_SERVNOTICE); SetFlag(sptr, FLAG_DEBUG); if (snomask) set_snomask(sptr, snomask, SNO_ADD); else set_snomask(sptr, feature_int(FEAT_SNOMASK_OPERDEFAULT), SNO_ADD); cli_max_sendq(sptr) = 0; /* Get the sendq from the oper's class */ cli_max_recvq(sptr) = 0; /* Get the recvq from the oper's class */ cli_lag_min(sptr) = -2; /* Get the fake lag minimum from the oper's class */ cli_lag_factor(sptr) = -2; /* Get the fake lag factor from the oper's class */ send_umode_out(sptr, sptr, &old_mode, HasPriv(sptr, PRIV_PROPAGATE)); } else { client_send_privs(&me, sptr, sptr); if (HasPriv(sptr, PRIV_PROPAGATE)) { modes = (HasPriv(sptr, PRIV_ADMIN) ? "aowsg" : "owsg"); } else { modes = "Owsg"; } sendcmdto_one(&me, CMD_MODE, sptr, "%s %s", cli_name(sptr), modes); } modes = ConfUmode(aconf); if (modes) { if (MyUser(sptr)) { char *umodev[] = { NULL, NULL, NULL, NULL }; umodev[1] = cli_name(sptr); umodev[2] = modes; old_mode = cli_flags(sptr); set_user_mode(sptr, sptr, 3, umodev, ALLOWMODES_ANY); send_umode(NULL, sptr, &old_mode, HasPriv(sptr, PRIV_PROPAGATE)); if ((cli_snomask(sptr) != feature_int(FEAT_SNOMASK_OPERDEFAULT)) && HasFlag(sptr, FLAG_SERVNOTICE)) send_reply(sptr, RPL_SNOMASK, cli_snomask(sptr), cli_snomask(sptr)); } else { if (snomask) sendcmdto_one(&me, CMD_MODE, sptr, "%s %s+s +%d", cli_name(sptr), modes, snomask); else sendcmdto_one(&me, CMD_MODE, sptr, "%s %s", cli_name(sptr), modes); } } send_reply(sptr, RPL_YOUREOPER); if ((feature_int(FEAT_HOST_HIDING_STYLE) == 1) || (feature_int(FEAT_HOST_HIDING_STYLE) == 3)) hide_hostmask(sptr); if (!EmptyString(ajoinchan)) { if (!EmptyString(ajoinnotice)) sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s", sptr, ajoinnotice); ircd_strncpy(chan, ajoinchan, CHANNELLEN-1); join[0] = cli_name(sptr); join[1] = chan; join[2] = NULL; m_join(sptr, sptr, 2, join); } if (!EmptyString(aconf->autojoinchan)) { if (!EmptyString(aconf->autojoinnotice)) sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s", sptr, aconf->autojoinnotice); ircd_strncpy(chan, aconf->autojoinchan, CHANNELLEN-1); join[0] = cli_name(sptr); join[1] = chan; join[2] = NULL; m_join(sptr, sptr, 2, join); } sendto_opmask_butone_global((MyUser(sptr) ? &me : NULL), SNO_OLDSNO, "%s (%s@%s) is now operator (%c)", cli_name(sptr), cli_user(sptr)->username, cli_user(sptr)->realhost, IsOper(sptr) ? 'O' : 'o'); if (feature_bool(FEAT_OPERMOTD)) m_opermotd(sptr, sptr, 1, parv); log_write(LS_OPER, L_INFO, 0, "OPER (%s) by (%#C)", aconf->name, sptr); }