/* * Duplicate a file descriptor. */ int sys_dup(struct lwp *l, const struct sys_dup_args *uap, register_t *retval) { /* { syscallarg(int) fd; } */ int error, newfd, oldfd; file_t *fp; oldfd = SCARG(uap, fd); if ((fp = fd_getfile(oldfd)) == NULL) { return EBADF; } error = fd_dup(fp, 0, &newfd, false); fd_putfile(oldfd); *retval = newfd; return error; }
/* * The file control system call. */ int sys_fcntl(struct lwp *l, const struct sys_fcntl_args *uap, register_t *retval) { /* { syscallarg(int) fd; syscallarg(int) cmd; syscallarg(void *) arg; } */ int fd, i, tmp, error, cmd, newmin; filedesc_t *fdp; file_t *fp; struct flock fl; bool cloexec = false; fd = SCARG(uap, fd); cmd = SCARG(uap, cmd); fdp = l->l_fd; error = 0; switch (cmd) { case F_CLOSEM: if (fd < 0) return EBADF; while ((i = fdp->fd_lastfile) >= fd) { if (fd_getfile(i) == NULL) { /* Another thread has updated. */ continue; } fd_close(i); } return 0; case F_MAXFD: *retval = fdp->fd_lastfile; return 0; case F_SETLKW: case F_SETLK: case F_GETLK: error = copyin(SCARG(uap, arg), &fl, sizeof(fl)); if (error) return error; error = do_fcntl_lock(fd, cmd, &fl); if (cmd == F_GETLK && error == 0) error = copyout(&fl, SCARG(uap, arg), sizeof(fl)); return error; default: /* Handled below */ break; } if ((fp = fd_getfile(fd)) == NULL) return (EBADF); if ((cmd & F_FSCTL)) { error = fcntl_forfs(fd, fp, cmd, SCARG(uap, arg)); fd_putfile(fd); return error; } switch (cmd) { case F_DUPFD_CLOEXEC: cloexec = true; /*FALLTHROUGH*/ case F_DUPFD: newmin = (long)SCARG(uap, arg); if ((u_int)newmin >= l->l_proc->p_rlimit[RLIMIT_NOFILE].rlim_cur || (u_int)newmin >= maxfiles) { fd_putfile(fd); return EINVAL; } error = fd_dup(fp, newmin, &i, cloexec); *retval = i; break; case F_GETFD: *retval = fdp->fd_dt->dt_ff[fd]->ff_exclose; break; case F_SETFD: fd_set_exclose(l, fd, ((long)SCARG(uap, arg) & FD_CLOEXEC) != 0); break; case F_GETNOSIGPIPE: *retval = (fp->f_flag & FNOSIGPIPE) != 0; break; case F_SETNOSIGPIPE: if (SCARG(uap, arg)) atomic_or_uint(&fp->f_flag, FNOSIGPIPE); else atomic_and_uint(&fp->f_flag, ~FNOSIGPIPE); *retval = 0; break; case F_GETFL: *retval = OFLAGS(fp->f_flag); break; case F_SETFL: /* XXX not guaranteed to be atomic. */ tmp = FFLAGS((long)SCARG(uap, arg)) & FCNTLFLAGS; error = (*fp->f_ops->fo_fcntl)(fp, F_SETFL, &tmp); if (error) break; i = tmp ^ fp->f_flag; if (i & FNONBLOCK) { int flgs = tmp & FNONBLOCK; error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, &flgs); if (error) { (*fp->f_ops->fo_fcntl)(fp, F_SETFL, &fp->f_flag); break; } } if (i & FASYNC) { int flgs = tmp & FASYNC; error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, &flgs); if (error) { if (i & FNONBLOCK) { tmp = fp->f_flag & FNONBLOCK; (void)(*fp->f_ops->fo_ioctl)(fp, FIONBIO, &tmp); } (*fp->f_ops->fo_fcntl)(fp, F_SETFL, &fp->f_flag); break; } } fp->f_flag = (fp->f_flag & ~FCNTLFLAGS) | tmp; break; case F_GETOWN: error = (*fp->f_ops->fo_ioctl)(fp, FIOGETOWN, &tmp); *retval = tmp; break; case F_SETOWN: tmp = (int)(uintptr_t) SCARG(uap, arg); error = (*fp->f_ops->fo_ioctl)(fp, FIOSETOWN, &tmp); break; default: error = EINVAL; } fd_putfile(fd); return (error); }
/*! @decl void output(object obj, int|void start_pos) *! *! Add an output file object. */ static void pipe_output(INT32 args) { struct object *obj; struct output *o; int fd; struct stat s; struct buffer *b; if (args<1 || sp[-args].type != T_OBJECT || !sp[-args].u.object || !sp[-args].u.object->prog) Pike_error("Bad/missing argument 1 to pipe->output().\n"); if (args==2 && sp[1-args].type != T_INT) Pike_error("Bad argument 2 to pipe->output().\n"); if (THIS->fd==-1) /* no buffer */ { /* test if usable as buffer */ apply(sp[-args].u.object,"query_fd",0); if ((sp[-1].type==T_INT) && (fd=sp[-1].u.integer)>=0 && (fstat(fd,&s)==0) && S_ISREG(s.st_mode) && (THIS->fd=fd_dup(fd))!=-1 ) { /* keep the file pointer of the duped fd */ THIS->pos=fd_lseek(fd, 0L, SEEK_CUR); THIS->living_outputs++; while (THIS->firstbuffer) { b=THIS->firstbuffer; THIS->firstbuffer=b->next; fd_lseek(THIS->fd, THIS->pos, SEEK_SET); fd_write(THIS->fd,b->s->str,b->s->len); sbuffers-=b->s->len; nbuffers--; free_string(b->s); free((char *)b); } THIS->lastbuffer=NULL; /* keep the file pointer of the duped fd THIS->pos=0; */ push_int(0); apply(sp[-args-2].u.object,"set_id", 1); pop_n_elems(args+2); /* ... and from apply x 2 */ return; } pop_stack(); /* from apply */ } THIS->living_outputs++; /* add_ref(THISOBJ); */ /* Weird */ /* Allocate a new struct output */ obj=clone_object(output_program,0); o=(struct output *)(obj->storage); o->next=THIS->firstoutput; THIS->firstoutput=obj; noutputs++; o->obj=NULL; add_ref(o->obj=sp[-args].u.object); o->write_offset=find_identifier("write",o->obj->prog); o->set_nonblocking_offset=find_identifier("set_nonblocking",o->obj->prog); o->set_blocking_offset=find_identifier("set_blocking",o->obj->prog); if (o->write_offset<0 || o->set_nonblocking_offset<0 || o->set_blocking_offset<0) { free_object(o->obj); Pike_error("illegal file object%s%s%s\n", ((o->write_offset<0)?"; no write":""), ((o->set_nonblocking_offset<0)?"; no set_nonblocking":""), ((o->set_blocking_offset<0)?"; no set_blocking":"")); } o->mode=O_RUN; /* keep the file pointer of the duped fd o->pos=0; */ /* allow start position as 2nd argument for additional outputs o->pos=THIS->pos; */ if(args>=2) o->pos=sp[1-args].u.integer; else o->pos=THIS->pos; push_object(obj); /* Ok, David, this is probably correct, but I dare you to explain why :) */ apply(o->obj,"set_id",1); pop_stack(); push_int(0); push_callback(offset_output_write_callback); push_callback(offset_output_close_callback); apply_low(o->obj,o->set_nonblocking_offset,3); pop_stack(); pop_n_elems(args-1); }
void f_aap_log_as_commonlog_to_file(INT32 args) { struct log_entry *le; struct log *l = LTHIS->log; int n = 0; int mfd, ot=0; struct object *f; struct tm tm; FILE *foo; static const char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Oct", "Sep", "Nov", "Dec", }; get_all_args("log_as_commonlog_to_file", args, "%o", &f); f->refs++; pop_n_elems(args); apply(f, "query_fd", 0); mfd = fd_dup(sp[-1].u.integer); if(mfd < 1)Pike_error("Bad fileobject to ->log_as_commonlog_to_file\n"); pop_stack(); foo = fdopen( mfd, "w" ); if(!foo) Pike_error("Bad fileobject to ->log_as_commonlog_to_file\n"); THREADS_ALLOW(); mt_lock( &l->log_lock ); le = l->log_head; l->log_head = l->log_tail = 0; mt_unlock( &l->log_lock ); while(le) { int i; struct tm *tm_p; struct log_entry *l = le->next; /* remotehost rfc931 authuser [date] "request" status bytes */ if(le->t != ot) { time_t t = (time_t)le->t; #ifdef HAVE_GMTIME_R gmtime_r( &t, &tm ); #else #ifdef HAVE_GMTIME tm_p = gmtime( &t ); /* This will break if two threads run gmtime() at once. */ #else #ifdef HAVE_LOCALTIME tm_p = localtime( &t ); /* This will break if two threads run localtime() at once. */ #endif #endif if (tm_p) tm = *tm_p; #endif ot = le->t; } /* date format: [03/Feb/1998:23:08:20 +0000] */ /* GET [URL] HTTP/1.0 */ for(i=13; i<le->raw.len; i++) if(le->raw.str[i] == '\r') { le->raw.str[i] = 0; break; } #ifdef HAVE_INET_NTOP if(SOCKADDR_FAMILY(le->from) != AF_INET) { char buffer[64]; fprintf(foo, "%s - %s [%02d/%s/%d:%02d:%02d:%02d +0000] \"%s\" %d %ld\n", inet_ntop(SOCKADDR_FAMILY(le->from), SOCKADDR_IN_ADDR(le->from), buffer, sizeof(buffer)), /* hostname */ "-", /* remote-user */ tm.tm_mday, month[tm.tm_mon], tm.tm_year+1900, tm.tm_hour, tm.tm_min, tm.tm_sec, /* date */ le->raw.str, /* request line */ le->reply, /* reply code */ DO_NOT_WARN((long)le->sent_bytes)); /* bytes transfered */ } else #endif /* HAVE_INET_NTOP */ fprintf(foo, "%d.%d.%d.%d - %s [%02d/%s/%d:%02d:%02d:%02d +0000] \"%s\" %d %ld\n", ((unsigned char *)&le->from.ipv4.sin_addr)[ 0 ], ((unsigned char *)&le->from.ipv4.sin_addr)[ 1 ], ((unsigned char *)&le->from.ipv4.sin_addr)[ 2 ], ((unsigned char *)&le->from.ipv4.sin_addr)[ 3 ], /* hostname */ "-", /* remote-user */ tm.tm_mday, month[tm.tm_mon], tm.tm_year+1900, tm.tm_hour, tm.tm_min, tm.tm_sec, /* date */ le->raw.str, /* request line */ le->reply, /* reply code */ DO_NOT_WARN((long)le->sent_bytes)); /* bytes transfered */ free_log_entry( le ); n++; le = l; } fclose(foo); fd_close(mfd); THREADS_DISALLOW(); push_int(n); }