source: roaraudio/libroaross/libroaross.c @ 4487:8faad70bfa79

Last change on this file since 4487:8faad70bfa79 was 4487:8faad70bfa79, checked in by phi, 13 years ago

added a warning about O_EXCL

File size: 55.5 KB
Line 
1//libroaross.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010
5 *
6 *  This file is part of libroar a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  libroar is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
23 *
24 *  NOTE for everyone want's to change something and send patches:
25 *  read README and HACKING! There a addition information on
26 *  the license of this document you need to read before you send
27 *  any patches.
28 *
29 *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
30 *  or libpulse*:
31 *  The libs libroaresd, libroararts and libroarpulse link this lib
32 *  and are therefore GPL. Because of this it may be illigal to use
33 *  them with any software that uses libesd, libartsc or libpulse*.
34 */
35
36#include "roaraudio.h"
37#include "libroarlight/libroarlight.h"
38
39#if defined(ROAR_HAVE_OSS_BSD) || defined(ROAR_HAVE_OSS)
40#if defined(__OpenBSD__) || defined(__NetBSD__)
41#include <soundcard.h>
42#else
43#include <sys/soundcard.h>
44#endif
45#include <sys/ioctl.h>
46
47#ifdef ROAR_HAVE_H_SYS_TYPES
48#include <sys/types.h>
49#endif
50
51#ifdef ROAR_HAVE_H_FCNTL
52#include <fcntl.h>
53#endif
54
55#ifdef ROAR_HAVE_H_UNISTD
56#include <unistd.h>
57#endif
58
59#include <sys/stat.h>
60#include <dlfcn.h>
61#include <stdarg.h>
62
63#if defined(RTLD_NEXT)
64#define REAL_LIBC RTLD_NEXT
65#else
66#define REAL_LIBC ((void *) -1L)
67#endif
68
69#ifndef ENOTSUP
70#define ENOTSUP ENOSYS
71#endif
72
73#ifndef O_DIRECTORY
74#define O_DIRECTORY 0
75#endif
76
77#ifndef O_DIRECT
78#define O_DIRECT 0
79#endif
80
81#ifndef O_LARGEFILE
82#define O_LARGEFILE 0
83#endif
84
85#ifndef O_NOATIME
86#define O_NOATIME 0
87#endif
88
89#define _O_PARA_DIR (O_RDONLY|O_WRONLY|O_RDWR)
90#define _O_PARA_IGN (O_DIRECT|O_APPEND|O_LARGEFILE|O_NOATIME|O_NOCTTY|O_TRUNC)
91
92#if defined(ROAR_OS_NETBSD) && defined(ioctl)
93#define IOCTL_IS_ALIAS
94#endif
95
96#ifdef ROAR_OS_FREEBSD
97#define _VA_ARGS_MODE_T int
98#else
99#define _VA_ARGS_MODE_T mode_t
100#endif
101
102#ifdef ROAR_OS_FREEBSD
103#define _CREAT_ARG_PATHNAME path
104#else
105#define _CREAT_ARG_PATHNAME pathname
106#endif
107
108#ifdef ROAR_OS_NETBSD
109#define IOCTL() int _oss_ioctl __P((int fd, unsigned long com, void *argp))
110#define map_args int __fd = fd; unsigned long int __request = com
111#elif defined(ROAR_TARGET_CYGWIN)
112#define IOCTL() int ioctl (int __fd, int __cmd, ...)
113#define map_args unsigned long int __request = __cmd; void * argp
114#define va_argp
115#define ioctl_lastarg __cmd
116#else
117#define IOCTL() int ioctl (int __fd, unsigned long int __request, ...)
118#define map_args void * argp
119#define va_argp
120#define ioctl_lastarg __request
121#endif
122
123#define OSS_VOLUME_SCALE 100
124
125#define _MAX_POINTER  8
126
127// handle type:
128#define HT_NONE       0 /* Unused object */
129#define HT_STREAM     1 /* Stream with no specal handling needed */
130#define HT_MIXER      2 /* Mixer device */
131#define HT_WAVEFORM   3 /* Waveform device */
132#define HT_MIDI       4 /* MIDI device */
133#define HT_DMX        5 /* DMX512/DMX4Linux device */
134#define HT_VIO        6 /* General VIO object */
135#define HT_STATIC     7 /* Static file */
136
137struct session {
138 int refc;
139 struct roar_connection con;
140};
141
142static struct session _session = {.refc = 0};
143
144struct handle {
145 int refc; // refrence counter
146 struct session * session;
147 int type;
148 int sysio_flags;
149 struct roar_stream    stream;
150 struct roar_vio_calls stream_vio;
151 int                   stream_dir;
152 int                   stream_opened;
153 size_t                stream_buffersize;
154 size_t                readc, writec;
155 size_t                pos;
156 union {
157  struct {
158   char * data;
159   size_t len;
160  } sf;
161 } userdata;
162};
163
164static struct {
165 int     (*open)(const char *pathname, int flags, mode_t mode);
166 int     (*close)(int fd);
167 ssize_t (*write)(int fd, const void *buf, size_t count);
168 ssize_t (*read)(int fd, void *buf, size_t count);
169#ifndef IOCTL_IS_ALIAS
170 int     (*ioctl)(int d, int request, ...);
171#endif
172 off_t   (*lseek)(int fildes, off_t offset, int whence);
173 FILE   *(*fopen)(const char *path, const char *mode);
174 int     (*dup)(int oldfd);
175 int     (*dup2)(int oldfd, int newfd);
176 int     (*select)(int nfds, fd_set *readfds, fd_set *writefds,
177                   fd_set *exceptfds, struct timeval *timeout);
178 int     (*fcntl)(int fd, int cmd, ...);
179 int     (*access)(const char *pathname, int mode);
180 int     (*open64)(const char *__file, int __oflag, ...);
181 int     (*creat)(const char *_CREAT_ARG_PATHNAME, mode_t mode);
182 int     (*stat)(const char *path, struct stat *buf);
183 int     (*fstat)(int filedes, struct stat *buf);
184 int     (*lstat)(const char *path, struct stat *buf);
185} _os;
186
187static struct {
188 struct {
189  int volume;
190  int pcm;
191  int line;
192  int line1;
193  int line2;
194  int line3;
195  int digital1;
196  int digital2;
197  int digital3;
198 } sid;
199} _mix_settings = {
200                   .sid = {
201                           .volume   = -1,
202                           .pcm      = -1,
203                           .line     =  0,
204                           .line1    =  1,
205                           .line2    =  2,
206                           .line3    =  3,
207                           .digital1 =  1,
208                           .digital2 =  2,
209                           .digital3 =  3
210                          }
211                  };
212
213static struct pointer {
214 int fh;
215 struct handle * handle;
216} _ptr[_MAX_POINTER];
217
218
219static char _sf__dev_sndstat[] =
220 "Sound Driver:RoarAudio\n"
221 "Config options: 0\n"
222 "\n"
223 "Installed drivers:\n"
224 "Type 10: RoarAudio emulation\n"
225 "\n"
226 "Card config:\n"
227 "\n"
228 "Audio devices:\n"
229 "0: RoarAudio OSS emulation (DUPLEX)\n"
230 "\n"
231 "Midi devices:\n"
232 "0: RoarAudio OSS emulation MIDI\n"
233 "\n"
234 "Timers:\n"
235 "\n"
236 "Mixers:\n"
237 "0: RoarAudio OSS emulation Mixer\n"
238;
239
240static struct devices {
241  char * prefix;
242  int type;
243  size_t len;
244  void * userdata;
245  struct handle * (*open)(const char * file, int flags, mode_t mode, struct devices * ptr);
246} _device_list[] = {
247 {"/dev/dsp",           HT_WAVEFORM,  0, NULL, NULL},
248 {"/dev/dsp?",          HT_WAVEFORM,  0, NULL, NULL},
249 {"/dev/audio",         HT_WAVEFORM,  0, NULL, NULL},
250 {"/dev/audio?",        HT_WAVEFORM,  0, NULL, NULL},
251 {"/dev/sound/dsp",     HT_WAVEFORM,  0, NULL, NULL},
252 {"/dev/sound/dsp?",    HT_WAVEFORM,  0, NULL, NULL},
253 {"/dev/sound/audio",   HT_WAVEFORM,  0, NULL, NULL},
254 {"/dev/sound/audio?",  HT_WAVEFORM,  0, NULL, NULL},
255 {"/dev/mixer",         HT_MIXER,     0, NULL, NULL},
256 {"/dev/mixer?",        HT_MIXER,     0, NULL, NULL},
257 {"/dev/sound/mixer",   HT_MIXER,     0, NULL, NULL},
258 {"/dev/sound/mixer?",  HT_MIXER,     0, NULL, NULL},
259 {"/dev/midi",          HT_MIDI,      0, NULL, NULL},
260 {"/dev/midi?",         HT_MIDI,      0, NULL, NULL},
261 {"/dev/rmidi",         HT_MIDI,      0, NULL, NULL},
262 {"/dev/rmidi?",        HT_MIDI,      0, NULL, NULL},
263 {"/dev/sound/midi",    HT_MIDI,      0, NULL, NULL},
264 {"/dev/sound/midi?",   HT_MIDI,      0, NULL, NULL},
265 {"/dev/sound/rmidi",   HT_MIDI,      0, NULL, NULL},
266 {"/dev/sound/rmidi?",  HT_MIDI,      0, NULL, NULL},
267 {"/dev/dmx",           HT_DMX,       0, NULL, NULL},
268 {"/dev/dmx?",          HT_DMX,       0, NULL, NULL},
269 {"/dev/misc/dmx",      HT_DMX,       0, NULL, NULL},
270 {"/dev/misc/dmx?",     HT_DMX,       0, NULL, NULL},
271 {"/dev/dmxin",         HT_DMX,       0, NULL, NULL},
272 {"/dev/dmxin?",        HT_DMX,       0, NULL, NULL},
273 {"/dev/misc/dmxin",    HT_DMX,       0, NULL, NULL},
274 {"/dev/misc/dmxin?",   HT_DMX,       0, NULL, NULL},
275 {"/dev/sndstat",       HT_STATIC,    sizeof(_sf__dev_sndstat)-1, _sf__dev_sndstat, NULL},
276#ifdef ROAR_DEFAULT_OSS_DEV
277 {ROAR_DEFAULT_OSS_DEV, HT_WAVEFORM,  0, NULL, NULL},
278#endif
279#ifdef ROAR_DEFAULT_OSS_MIX_DEV
280 {ROAR_DEFAULT_OSS_MIX_DEV, HT_MIXER, 0, NULL, NULL},
281#endif
282 {NULL, HT_NONE, 0, NULL, NULL},
283};
284
285
286static int _update_nonblock (struct handle * handle);
287
288static void _init_os (void) {
289 memset(&_os, 0, sizeof(_os));
290
291 // if call roar_dl_getsym() here all applications will segfaul.
292 // why?
293
294 _os.open   = dlsym(REAL_LIBC, "open");
295 _os.close  = dlsym(REAL_LIBC, "close");
296 _os.write  = dlsym(REAL_LIBC, "write");
297 _os.read   = dlsym(REAL_LIBC, "read");
298#ifndef IOCTL_IS_ALIAS
299 _os.ioctl  = dlsym(REAL_LIBC, "ioctl");
300#endif
301 _os.lseek  = dlsym(REAL_LIBC, "lseek");
302 _os.fopen  = dlsym(REAL_LIBC, "fopen");
303 _os.dup    = dlsym(REAL_LIBC, "dup");
304 _os.dup2   = dlsym(REAL_LIBC, "dup2");
305 _os.select = dlsym(REAL_LIBC, "select");
306 _os.fcntl  = dlsym(REAL_LIBC, "fcntl");
307 _os.access = dlsym(REAL_LIBC, "access");
308 _os.open64 = dlsym(REAL_LIBC, "open64");
309 _os.creat  = dlsym(REAL_LIBC, "creat");
310 _os.stat   = dlsym(REAL_LIBC, "stat");
311 _os.fstat  = dlsym(REAL_LIBC, "fstat");
312 _os.lstat  = dlsym(REAL_LIBC, "lstat");
313}
314
315static void _init_ptr (void) {
316 int i;
317
318 for (i = 0; i < _MAX_POINTER; i++) {
319  _ptr[i].fh = -1;
320 }
321}
322
323static void _init (void) {
324 static int inited = 0;
325
326 if ( !inited ) {
327  _init_os();
328  _init_ptr();
329  roar_vio_select(NULL, 0, NULL, NULL);
330  inited++;
331 }
332}
333
334static void _find_volume_sid (struct session * session) {
335 int i;
336 int num;
337 int id[ROAR_STREAMS_MAX];
338 struct roar_stream s;
339 char name[1024];
340
341 ROAR_DBG("_find_volume_sid(session=%p) = ?", session);
342
343 if ( (num = roar_list_streams(&(session->con), id, ROAR_STREAMS_MAX)) == -1 ) {
344  return;
345 }
346
347 for (i = 0; i < num; i++) {
348  if ( roar_get_stream(&(session->con), &s, id[i]) == -1 )
349   continue;
350
351  if ( s.dir != ROAR_DIR_MIXING )
352   continue;
353
354  if ( roar_stream_get_name(&(session->con), &s, name, 1024) == -1 )
355   continue;
356
357  if ( !strcasecmp(name, "Waveform Mixer") ) {
358   _mix_settings.sid.volume = id[i];
359   ROAR_DBG("_find_volume_sid(session=%p): found waveform mixer at sid %i", session, id[i]);
360   ROAR_DBG("_find_volume_sid(session=%p) = (void)", session);
361   return;
362  }
363 }
364}
365
366static int _open_dummy (void) {
367 int p[2];
368
369 ROAR_DBG("_open_dummy(void) = ?");
370
371 if ( pipe(p) == -1 )
372  return -1;
373
374 close(p[1]);
375
376 ROAR_DBG("_open_dummy(void) = %i", p[0]);
377 return p[0];
378}
379
380static struct session * _open_session (char * server, char * name) {
381 struct session * ses = &_session;
382 int new_session = getenv("ROAR_OSS_NEW_SESSION") == NULL ? 0 : 1;
383
384 ROAR_DBG("_open_session(server='%s', name='%s') = ?", server, name);
385 ROAR_DBG("_open_session(server='%s', name='%s'): _session.refc=%i", server, name, _session.refc);
386
387 if ( new_session ) {
388  ses = roar_mm_malloc(sizeof(struct session));
389  if ( ses == NULL )
390   return NULL;
391
392  memset(ses, 0, sizeof(struct session));
393 }
394
395 if ( ses->refc == 0 ) {
396
397  if ( name == NULL )
398   name = getenv("ROAR_OSS_CLIENT_NAME");
399
400  if ( name == NULL )
401   name = "libroaross client";
402
403  if ( roar_simple_connect(&(ses->con), server, name) == -1 ) {
404   if ( new_session )
405    roar_mm_free(ses);
406
407   return NULL;
408  }
409
410  _find_volume_sid(ses);
411
412  if ( !new_session ) {
413   if ( getenv("ROAR_OSS_KEEP_SESSION") != NULL )
414    ses->refc++;
415  }
416 }
417
418 ses->refc++;
419
420 ROAR_DBG("_open_session(server='%s', name='%s') = %p", server, name, ses);
421 return ses;
422}
423
424static void _close_session(struct session * session) {
425 if ( session == NULL )
426  return;
427
428 session->refc--;
429
430 ROAR_DBG("_close_session(session=%p): session->refc=%i", session, session->refc);
431
432 if ( session->refc == 0 ) {
433  roar_disconnect(&(session->con));
434 }
435
436 if ( session != &_session )
437  roar_mm_free(session);
438}
439
440static struct handle * _open_handle(struct session * session) {
441 struct handle * handle;
442
443 ROAR_DBG("_open_handle(session=%p) = ?", session);
444
445 if ( (handle = roar_mm_malloc(sizeof(struct handle))) == NULL )
446  return NULL;
447
448 memset(handle, 0, sizeof(struct handle));
449
450 handle->refc = 1;
451 handle->session = session;
452
453 if ( session != NULL )
454  session->refc++; // TODO: better warp this
455
456 handle->type = HT_NONE;
457 handle->stream_dir = ROAR_DIR_PLAY;
458 roar_stream_new(&(handle->stream), ROAR_RATE_DEFAULT, ROAR_CHANNELS_DEFAULT, ROAR_BITS_DEFAULT, ROAR_CODEC_DEFAULT);
459
460 ROAR_DBG("_open_handle(session=%p) = %p", session, handle);
461 return handle;
462}
463
464static void _close_handle(struct handle * handle) {
465 int need_close = 0;
466
467 if (handle == NULL)
468  return;
469
470 handle->refc--;
471
472 ROAR_DBG("_close_handle(handle=%p): handle->refc=%i", handle, handle->refc);
473
474 if ( handle->refc == 0 ) {
475  switch (handle->type) {
476   case HT_VIO:
477     need_close = 1;
478    break;
479   case HT_STREAM:
480     if ( handle->stream_opened )
481      need_close = 1;
482    break;
483  }
484
485  if ( need_close )
486   roar_vio_close(&(handle->stream_vio));
487
488  if ( handle->session != NULL ) {
489   handle->session->refc--;
490
491   _close_session(handle->session);
492  }
493
494  roar_mm_free(handle);
495 }
496}
497
498static struct pointer * _get_pointer_by_fh_or_new (int fh) {
499 int i;
500
501 for (i = 0; i < _MAX_POINTER; i++) {
502  if ( _ptr[i].fh == fh )
503   return &(_ptr[i]);
504 }
505
506 return NULL;
507}
508
509static struct pointer * _get_pointer_by_fh (int fh) {
510 if ( fh == -1 )
511  return NULL;
512
513 return _get_pointer_by_fh_or_new(fh);
514}
515
516static struct pointer * _open_pointer(struct handle * handle) {
517 struct pointer * ret = _get_pointer_by_fh_or_new(-1);
518
519 ROAR_DBG("_open_pointer(handle=%p) = ?", handle);
520
521 if ( ret == NULL ) {
522  ROAR_DBG("_open_pointer(handle=%p) = NULL", handle);
523  return NULL;
524 }
525
526 if ( (ret->fh = _open_dummy()) == -1 ) {
527  ROAR_DBG("_open_pointer(handle=%p) = NULL", handle);
528  return NULL;
529 }
530
531 ret->handle = handle;
532
533 ROAR_DBG("_open_pointer(handle=%p) = %p", handle, ret);
534
535 return ret;
536}
537
538static struct pointer * _attach_pointer(struct handle * handle, int fh) {
539 struct pointer * ret = _get_pointer_by_fh_or_new(-1);
540
541 if ( ret == NULL )
542  return NULL;
543
544 if ( (ret->fh = fh) == -1 )
545  return NULL;
546
547 ret->handle = handle;
548
549 handle->refc++;
550
551 return ret;
552}
553
554static void _close_pointer(struct pointer * pointer) {
555 if ( pointer == NULL )
556  return;
557
558 _os.close(pointer->fh);
559
560 pointer->fh = -1;
561
562 _close_handle(pointer->handle);
563}
564
565// -------------------------------------
566// central function to find device:
567// -------------------------------------
568
569static struct devices * _get_device (const char * pathname) {
570 size_t len, pathlen;
571 int i;
572 int qm_match;
573
574 ROAR_DBG("_get_device(pathname='%s') = ?", pathname);
575
576 pathlen = strlen(pathname);
577
578 for (i = 0; _device_list[i].prefix != NULL; i++) {
579  len = strlen(_device_list[i].prefix);
580
581  qm_match = 0;
582
583  if ( _device_list[i].prefix[len-1] == '*' ) {
584   len--;
585  } else if ( _device_list[i].prefix[len-1] == '?' ) {
586   qm_match = 1;
587   len--;
588  } else {
589   len++;
590  }
591
592  if ( !strncmp(pathname, _device_list[i].prefix, len) ) {
593   if ( !qm_match || pathlen == (len + 1) )
594    return &(_device_list[i]);
595  }
596 }
597
598 ROAR_DBG("_get_device(pathname='%s') = NULL", pathname);
599 return NULL;
600}
601
602// -------------------------------------
603// central open function:
604// -------------------------------------
605
606static int _open_file (const char *pathname, int flags) {
607 struct session * session;
608 struct handle  * handle;
609 struct pointer * pointer;
610 struct devices * ptr = NULL;
611
612 ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = ?", pathname, flags);
613
614/*
615 * Flags we ignore:
616 * O_DIRECT, O_APPEND, O_LARGEFILE, O_NOATIME, O_NOCTTY, O_TRUNC
617 */
618
619 if ( (ptr = _get_device(pathname)) == NULL ) {
620  ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -2", pathname, flags);
621  return -2;
622 }
623
624 ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = ?", pathname, flags);
625
626
627#ifdef O_ASYNC
628 if ( flags & O_ASYNC ) {
629  ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1 // not supported O_ASYNC", pathname, flags);
630  errno = ENOSYS;
631  return -1;
632 }
633#endif
634
635 if ( flags & O_DIRECTORY ) {
636  ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1 // invalid flags (O_DIRECTORY)", pathname, flags);
637  errno = EINVAL;
638  return -1;
639 }
640
641 if ( flags & O_EXCL ) {
642  ROAR_WARN("_open_file(pathname='%s', flags=0x%x): This application is asked us for exclusive device access.", pathname, flags);
643  ROAR_WARN("_open_file(pathname='%s', flags=0x%x): This is maybe not what you want.", pathname, flags);
644  ROAR_WARN("_open_file(pathname='%s', flags=0x%x): We reject this according to OSS specs.", pathname, flags);
645  ROAR_WARN("_open_file(pathname='%s', flags=0x%x): There should be a option in the application to switch this off.", pathname, flags);
646  ROAR_WARN("_open_file(pathname='%s', flags=0x%x) = -1 // invalid flags (O_EXCL)", pathname, flags);
647  errno = EINVAL;
648  return -1;
649 }
650
651 ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = ?", pathname, flags);
652
653 if ( ptr->type == HT_STATIC || ptr->type == HT_VIO ) { // non-session handles
654  session = NULL;
655 } else {
656  if ( (session = _open_session(NULL, NULL)) == NULL ) {
657   ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
658   return -1;
659  }
660 }
661
662 if ( ptr->open != NULL ) {
663  // TODO: Add support to pass mode (perms) to open.
664  if ( (handle = ptr->open(pathname, flags, 0000, ptr)) == NULL ) {
665   _close_session(session);
666   ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
667   return -1;
668  }
669 } else {
670  if ( (handle = _open_handle(session)) == NULL ) {
671   _close_session(session);
672   ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
673   return -1;
674  }
675
676  handle->type        = ptr->type;
677  handle->sysio_flags = flags;
678  handle->stream_dir  = -1;
679 }
680
681 switch (flags & _O_PARA_DIR) {
682  case O_RDONLY:
683    switch (ptr->type) {
684     case HT_WAVEFORM:
685       handle->stream_dir = ROAR_DIR_MONITOR;
686      break;
687     case HT_MIDI:
688       handle->stream_dir = ROAR_DIR_MIDI_OUT;
689      break;
690     case HT_DMX:
691       handle->stream_dir = ROAR_DIR_LIGHT_OUT;
692      break;
693     case HT_MIXER:
694     case HT_STATIC:
695      break;
696     default:
697       ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
698       return -1;
699    }
700   break;
701  case O_WRONLY:
702    switch (ptr->type) {
703     case HT_WAVEFORM:
704       handle->stream_dir = ROAR_DIR_PLAY;
705      break;
706     case HT_MIDI:
707       handle->stream_dir = ROAR_DIR_MIDI_IN;
708      break;
709     case HT_DMX:
710       handle->stream_dir = ROAR_DIR_LIGHT_IN;
711      break;
712     case HT_MIXER:
713     case HT_STATIC:
714      break;
715     default:
716       ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
717       return -1;
718    }
719   break;
720  case O_RDWR:
721    switch (ptr->type) {
722     case HT_WAVEFORM:
723       handle->stream_dir = ROAR_DIR_BIDIR;
724      break;
725     case HT_MIXER:
726     case HT_STATIC:
727      break;
728     default:
729       ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
730       return -1;
731    }
732   break;
733 }
734
735 switch (handle->type) {
736  case HT_WAVEFORM:
737    handle->type = HT_STREAM;
738   break;
739  case HT_MIDI:
740    handle->type = HT_STREAM;
741    handle->stream.info.rate     = 0;
742    handle->stream.info.bits     = ROAR_MIDI_BITS;
743    handle->stream.info.channels = ROAR_MIDI_CHANNELS_DEFAULT;
744    handle->stream.info.codec    = ROAR_CODEC_MIDI;
745   break;
746  case HT_DMX:
747    handle->stream.info.rate     = 0;
748    handle->stream.info.bits     = ROAR_LIGHT_BITS;
749    handle->stream.info.channels = 512;
750    handle->stream.info.codec    = ROAR_CODEC_ROARDMX;
751   break;
752  case HT_STATIC:
753    handle->userdata.sf.len      = ptr->len;
754    handle->userdata.sf.data     = ptr->userdata;
755   break;
756 }
757
758 ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = ?", pathname, flags);
759
760 if ( (pointer = _open_pointer(handle)) == NULL ) {
761  _close_handle(handle);
762  ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
763  return -1;
764 }
765
766 ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = %i", pathname, flags, pointer->fh);
767
768 return pointer->fh;
769}
770
771// -------------------------------------
772// VIO open function:
773// -------------------------------------
774
775int libroaross_open_vio(struct handle ** handleret, struct roar_vio_calls ** vio, int flags) {
776 struct handle  * handle;
777 struct pointer * pointer;
778
779 _init();
780
781 if ( vio == NULL )
782  return -1;
783
784 if ( (handle = _open_handle(NULL)) == NULL ) {
785  return -1;
786 }
787
788 handle->type        = HT_VIO;
789 handle->sysio_flags = flags;
790
791 if ( roar_vio_init_calls(&(handle->stream_vio)) == -1 ) {
792  _close_handle(handle);
793  return -1;
794 }
795
796 *vio = &(handle->stream_vio);
797
798 if ( handleret != NULL )
799  *handleret = handle;
800
801 if ( (pointer = _open_pointer(handle)) == NULL ) {
802  _close_handle(handle);
803  return -1;
804 }
805
806 return pointer->fh;
807}
808
809// -------------------------------------
810// open function for streams:
811// -------------------------------------
812
813static int _open_stream (struct handle * handle) {
814  // FIXME: this should be re-written much more cleanly:
815
816 if ( handle == NULL )
817  return -1;
818
819 if ( roar_vio_simple_new_stream_obj(&(handle->stream_vio),
820                                     &(handle->session->con), &(handle->stream),
821                                     handle->stream.info.rate,
822                                     handle->stream.info.channels,
823                                     handle->stream.info.bits,
824                                     handle->stream.info.codec,
825                                     handle->stream_dir
826                                    ) == -1 )
827  return -1;
828
829 handle->stream_opened++;
830
831 _mix_settings.sid.pcm = roar_stream_get_id(&(handle->stream));
832
833 _update_nonblock(handle);
834
835 return 0;
836}
837
838// -------------------------------------
839// function to update O_NONBLOCK:
840// -------------------------------------
841
842static int _update_nonblock (struct handle * handle) {
843 int opened = 0;
844 int state  = handle->sysio_flags & O_NONBLOCK ? ROAR_SOCKET_NONBLOCK : ROAR_SOCKET_BLOCK;
845
846 switch (handle->type) {
847  case HT_NONE:
848  case HT_STATIC:
849  case HT_MIXER:
850    // we can ignore setting of nonblock flag here.
851    return 0;
852   break;
853  case HT_VIO:
854    opened = 1;
855   break;
856  case HT_STREAM:
857  case HT_WAVEFORM:
858  case HT_MIDI:
859  case HT_DMX:
860    opened = handle->stream_opened;
861   break;
862 }
863
864 if ( opened ) {
865  return roar_vio_nonblock(&(handle->stream_vio), state);
866 }
867
868 return 0;
869}
870
871// -------------------------------------
872// function to parse format:
873// -------------------------------------
874
875static int _ioctl_stream_format (struct handle * handle, int format) {
876 struct roar_audio_info * info = &(handle->stream.info);
877
878 switch (format) {
879  case AFMT_S8:
880    info->bits  = 8;
881    info->codec = ROAR_CODEC_PCM_S_LE;
882   break;
883  case AFMT_U8:
884    info->bits  = 8;
885    info->codec = ROAR_CODEC_PCM_U_LE;
886   break;
887  case AFMT_S16_BE:
888    info->bits  = 16;
889    info->codec = ROAR_CODEC_PCM_S_BE;
890   break;
891  case AFMT_S16_LE:
892    info->bits  = 16;
893    info->codec = ROAR_CODEC_PCM_S_LE;
894   break;
895  case AFMT_U16_BE:
896    info->bits  = 16;
897    info->codec = ROAR_CODEC_PCM_U_BE;
898   break;
899  case AFMT_U16_LE:
900    info->bits  = 16;
901    info->codec = ROAR_CODEC_PCM_U_LE;
902   break;
903#ifdef AFMT_S32_BE
904  case AFMT_S32_BE:
905    info->bits  = 32;
906    info->codec = ROAR_CODEC_PCM_S_BE;
907   break;
908#endif
909#ifdef AFMT_S32_LE
910  case AFMT_S32_LE:
911    info->bits  = 32;
912    info->codec = ROAR_CODEC_PCM_S_LE;
913   break;
914#endif
915  case AFMT_A_LAW:
916    info->bits  = 8;
917    info->codec = ROAR_CODEC_ALAW;
918   break;
919  case AFMT_MU_LAW:
920    info->bits  = 8;
921    info->codec = ROAR_CODEC_MULAW;
922   break;
923#ifdef AFMT_VORBIS
924  case AFMT_VORBIS:
925    info->codec = ROAR_CODEC_OGG_VORBIS;
926   break;
927#endif
928  default:
929    ROAR_DBG("_ioctl_stream_format(*): unsupported format");
930    errno = ENOSYS;
931    return -1;
932   break;
933 }
934
935 return 0;
936}
937
938static inline int _ioctl_stream_format_list (void) {
939 int format = 0;
940
941 format |= AFMT_S8;
942 format |= AFMT_U8;
943
944 format |= AFMT_S16_BE;
945 format |= AFMT_S16_LE;
946
947 format |= AFMT_U16_BE;
948 format |= AFMT_U16_LE;
949
950#ifdef AFMT_S32_BE
951 format |= AFMT_S32_BE;
952#endif
953#ifdef AFMT_S32_LE
954 format |= AFMT_S32_LE;
955#endif
956
957 format |= AFMT_A_LAW;
958 format |= AFMT_MU_LAW;
959
960#ifdef AFMT_VORBIS
961 format |= AFMT_VORBIS;
962#endif
963
964 return format;
965}
966
967// -------------------------------------
968// mixer ioctls:
969// -------------------------------------
970
971static int _ioctl_mixer (struct handle * handle, long unsigned int req, void * vp) {
972 mixer_info * info;
973 int channels;
974 struct roar_mixer_settings mixer;
975 int o_w    =  0;
976 int o_sid  = -1;
977 int * ip   = vp;
978#if defined(DEBUG) && defined(DEBUG_IOCTL_NAMES)
979 char * name = NULL;
980#endif
981
982#if defined(DEBUG) && defined(DEBUG_IOCTL_NAMES)
983 switch (req) {
984#if 0
985  case SNDCTL_MIX_DESCRIPTION: name = "SNDCTL_MIX_DESCRIPTION"; break;
986  case SNDCTL_MIX_ENUMINFO:    name = "SNDCTL_MIX_ENUMINFO";    break;
987  case SNDCTL_MIX_EXTINFO:     name = "SNDCTL_MIX_EXTINFO";     break;
988  case SNDCTL_MIX_NREXT:       name = "SNDCTL_MIX_NREXT";       break;
989  case SNDCTL_MIX_NRMIX:       name = "SNDCTL_MIX_NRMIX";       break;
990  case SNDCTL_MIX_READ:        name = "SNDCTL_MIX_READ";        break;
991  case SNDCTL_MIX_WRITE:       name = "SNDCTL_MIX_WRITE";       break;
992#endif
993//  case SOUND_MIXER_INFO:             name = "SOUND_MIXER_INFO";             break;
994  case SOUND_OLD_MIXER_INFO:         name = "SOUND_OLD_MIXER_INFO";         break;
995  case SOUND_MIXER_ACCESS:           name = "SOUND_MIXER_ACCESS";           break;
996  case SOUND_MIXER_AGC:              name = "SOUND_MIXER_AGC";              break;
997  case SOUND_MIXER_3DSE:             name = "SOUND_MIXER_3DSE";             break;
998  case SOUND_MIXER_GETLEVELS:        name = "SOUND_MIXER_GETLEVELS";        break;
999  case SOUND_MIXER_SETLEVELS:        name = "SOUND_MIXER_SETLEVELS";        break;
1000  case SOUND_MIXER_PRIVATE1:         name = "SOUND_MIXER_PRIVATE1";         break;
1001  case SOUND_MIXER_PRIVATE2:         name = "SOUND_MIXER_PRIVATE2";         break;
1002  case SOUND_MIXER_PRIVATE3:         name = "SOUND_MIXER_PRIVATE3";         break;
1003  case SOUND_MIXER_PRIVATE4:         name = "SOUND_MIXER_PRIVATE4";         break;
1004  case SOUND_MIXER_PRIVATE5:         name = "SOUND_MIXER_PRIVATE5";         break;
1005  case OSS_GETVERSION:               name = "OSS_GETVERSION";               break;
1006//  case SOUND_MIXER_READ_CAPS:        name = "SOUND_MIXER_READ_CAPS";        break;
1007  case SOUND_MIXER_READ_MUTE:        name = "SOUND_MIXER_READ_MUTE";        break;
1008/*
1009  case :     name = "";     break;
1010  case :     name = "";     break;
1011*/
1012 }
1013 if ( name != NULL ) {
1014  ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p): unspported mixer command %s", handle, req, ip, name);
1015  ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p) = -1 // errno = ENOSYS", handle, req, ip);
1016  errno = ENOSYS;
1017  return -1;
1018 }
1019#endif
1020
1021 switch (req) {
1022  case SOUND_MIXER_READ_VOLUME:    o_w = 0; o_sid = _mix_settings.sid.volume;   break;
1023  case SOUND_MIXER_READ_LINE:      o_w = 0; o_sid = _mix_settings.sid.line;     break;
1024  case SOUND_MIXER_READ_LINE1:     o_w = 0; o_sid = _mix_settings.sid.line1;    break;
1025  case SOUND_MIXER_READ_LINE2:     o_w = 0; o_sid = _mix_settings.sid.line2;    break;
1026  case SOUND_MIXER_READ_LINE3:     o_w = 0; o_sid = _mix_settings.sid.line3;    break;
1027#if 0
1028  case SOUND_MIXER_READ_DIGITAL1:  o_w = 0; o_sid = _mix_settings.sid.digital1; break;
1029  case SOUND_MIXER_READ_DIGITAL2:  o_w = 0; o_sid = _mix_settings.sid.digital2; break;
1030  case SOUND_MIXER_READ_DIGITAL3:  o_w = 0; o_sid = _mix_settings.sid.digital3; break;
1031#endif
1032  case SOUND_MIXER_WRITE_VOLUME:   o_w = 1; o_sid = _mix_settings.sid.volume;   break;
1033  case SOUND_MIXER_WRITE_LINE:     o_w = 1; o_sid = _mix_settings.sid.line;     break;
1034  case SOUND_MIXER_WRITE_LINE1:    o_w = 1; o_sid = _mix_settings.sid.line1;    break;
1035  case SOUND_MIXER_WRITE_LINE2:    o_w = 1; o_sid = _mix_settings.sid.line2;    break;
1036  case SOUND_MIXER_WRITE_LINE3:    o_w = 1; o_sid = _mix_settings.sid.line3;    break;
1037#if 0
1038  case SOUND_MIXER_WRITE_DIGITAL1: o_w = 1; o_sid = _mix_settings.sid.digital1; break;
1039  case SOUND_MIXER_WRITE_DIGITAL2: o_w = 1; o_sid = _mix_settings.sid.digital2; break;
1040  case SOUND_MIXER_WRITE_DIGITAL3: o_w = 1; o_sid = _mix_settings.sid.digital3; break;
1041#endif
1042  // we handle PCM seperatly as we want to be abled to abled to handle it on a stream (not mixer), too:
1043  case SOUND_MIXER_READ_PCM:
1044    o_w = 0;
1045    if ( handle->type == HT_STREAM ) {
1046     o_sid = roar_stream_get_id(&(handle->stream));
1047    } else {
1048     o_sid = _mix_settings.sid.pcm;
1049    }
1050   break;
1051  case SOUND_MIXER_WRITE_PCM:
1052    o_w = 1;
1053    if ( handle->type == HT_STREAM ) {
1054     o_sid = roar_stream_get_id(&(handle->stream));
1055    } else {
1056     o_sid = _mix_settings.sid.pcm;
1057    }
1058   break;
1059 }
1060 if ( o_sid != -1 ) {
1061  // set/get volume
1062  if ( o_w ) {
1063   mixer.scale    = OSS_VOLUME_SCALE;
1064   mixer.mixer[0] = ( *ip       & 0xFF);
1065   mixer.mixer[1] = ((*ip >> 8) & 0xFF);
1066   if ( roar_set_vol(&(handle->session->con), o_sid, &mixer, 2) == -1 ) {
1067    errno = EIO;
1068    return -1;
1069   }
1070   return 0;
1071  } else {
1072   if ( roar_get_vol(&(handle->session->con), o_sid, &mixer, &channels) == -1 ) {
1073    errno = EIO;
1074    return -1;
1075   }
1076   *ip = ((OSS_VOLUME_SCALE*mixer.mixer[0])/mixer.scale) | (((OSS_VOLUME_SCALE*mixer.mixer[0])/mixer.scale)<<8);
1077   return 0;
1078  }
1079 }
1080
1081 switch (req) {
1082  case SOUND_MIXER_READ_STEREODEVS: /* FIXME: check the streams for channel config */
1083  case SOUND_MIXER_READ_DEVMASK:
1084    *ip = 0;
1085
1086    if ( _mix_settings.sid.volume != -1 )
1087     *ip |= SOUND_MASK_VOLUME;
1088    if ( _mix_settings.sid.pcm != -1 )
1089     *ip |= SOUND_MASK_PCM;
1090    if ( _mix_settings.sid.line != -1 )
1091     *ip |= SOUND_MASK_LINE;
1092    if ( _mix_settings.sid.line1 != -1 )
1093     *ip |= SOUND_MASK_LINE1;
1094    if ( _mix_settings.sid.line2 != -1 )
1095     *ip |= SOUND_MASK_LINE2;
1096    if ( _mix_settings.sid.line3 != -1 )
1097     *ip |= SOUND_MASK_LINE3;
1098    if ( _mix_settings.sid.digital1 != -1 )
1099#if 0
1100     *ip |= SOUND_MASK_DIGITAL1;
1101    if ( _mix_settings.sid.digital2 != -1 )
1102     *ip |= SOUND_MASK_DIGITAL2;
1103    if ( _mix_settings.sid.digital3 != -1 )
1104     *ip |= SOUND_MASK_DIGITAL3;
1105#endif
1106
1107    return 0;
1108   break;
1109  case SOUND_MIXER_READ_RECMASK:
1110  case SOUND_MIXER_READ_RECSRC:
1111    *ip = SOUND_MASK_VOLUME; // we can currently only read from mixer
1112    return 0;
1113   break;
1114  case SOUND_MIXER_WRITE_RECSRC:
1115    if ( *ip == SOUND_MASK_VOLUME ) {
1116     return  0;
1117    } else {
1118     errno = ENOTSUP;
1119     return -1;
1120    }
1121   break;
1122  case SOUND_MIXER_READ_CAPS:
1123    *ip = 0;
1124    return 0;
1125   break;
1126  case SOUND_MIXER_INFO:
1127    info = vp;
1128    memset(info, 0, sizeof(*info));
1129    strcpy(info->id, "RoarAudio");
1130    strcpy(info->name, "RoarAudio");
1131    return 0;
1132   break;
1133 }
1134
1135 ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p): unknown mixer CTL", handle, req, ip);
1136// _os.ioctl(-1, req, ip);
1137 ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p) = -1 // errno = ENOSYS", handle, req, ip);
1138 errno = ENOSYS;
1139 return -1;
1140}
1141
1142// -------------------------------------
1143// buffer size calculation:
1144// -------------------------------------
1145
1146static size_t _get_stream_buffersize (struct handle * handle) {
1147 if ( handle->stream_buffersize )
1148  return handle->stream_buffersize;
1149
1150 return handle->stream_buffersize = handle->stream.info.rate     *
1151                                    handle->stream.info.channels *
1152                                    handle->stream.info.bits     / 800;
1153}
1154
1155// -------------------------------------
1156// emulated functions follow:
1157// -------------------------------------
1158
1159int     open(const char *pathname, int flags, ...) {
1160 int     ret;
1161 mode_t  mode = 0;
1162 va_list args;
1163
1164 _init();
1165
1166 if ( pathname == NULL ) {
1167  errno = EFAULT;
1168  return -1;
1169 }
1170
1171 ROAR_DBG("open(pathname='%s', flags=%x, ...) = ?\n", pathname, flags);
1172 ret = _open_file(pathname, flags);
1173
1174 switch (ret) {
1175  case -2:       // continue as normal, use _op.open()
1176    ROAR_DBG("open(pathname='%s', flags=%x, ...): is not handled by us, pass to kernel\n", pathname, flags);
1177   break;
1178  case -1:       // pass error to caller
1179    return -1;
1180   break;
1181  default:       // return successfully opened pointer to caller
1182    return ret;
1183   break;
1184 }
1185
1186 if (flags & O_CREAT) {
1187  va_start(args, flags);
1188  mode = va_arg(args, _VA_ARGS_MODE_T);
1189  va_end(args);
1190 }
1191
1192 return _os.open(pathname, flags, mode);
1193}
1194
1195int    open64(const char *__file, int __oflag, ...) {
1196 int     ret;
1197 mode_t  mode = 0;
1198 va_list args;
1199
1200 _init();
1201
1202 if ( __file == NULL ) {
1203  errno = EFAULT;
1204  return -1;
1205 }
1206
1207 ROAR_DBG("open64(__file='%s', __oflags=%x, ...) = ?", __file, __oflag);
1208 ret = _open_file(__file, __oflag);
1209
1210 switch (ret) {
1211  case -2:       // continue as normal, use _op.open()
1212    ROAR_DBG("open64(__file='%s', __oflags=%x, ...): not for us, passing to kernel", __file, __oflag);
1213   break;
1214  case -1:       // pass error to caller
1215    return -1;
1216   break;
1217  default:       // return successfully opened pointer to caller
1218    ROAR_DBG("open64(__file='%s', __oflags=%x, ...) = %i", __file, __oflag, ret);
1219    return ret;
1220   break;
1221 }
1222
1223 if (__oflag & O_CREAT) {
1224  va_start(args, __oflag);
1225  mode = va_arg(args, _VA_ARGS_MODE_T);
1226  va_end(args);
1227 }
1228
1229 if ( _os.open64 != NULL ) {
1230  return _os.open64(__file, __oflag, mode);
1231 } else {
1232#ifdef O_LARGEFILE
1233  return _os.open(__file, __oflag | O_LARGEFILE, mode);
1234#else
1235  return _os.open(__file, __oflag, mode);
1236#endif
1237 }
1238}
1239
1240int     close(int fd) {
1241 struct pointer * pointer;
1242 _init();
1243
1244 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
1245  _close_pointer(pointer);
1246  return 0;
1247 }
1248
1249 return _os.close(fd);
1250}
1251
1252ssize_t write(int fd, const void *buf, size_t count) {
1253 struct roar_roardmx_message roardmxmsg;
1254 struct pointer * pointer;
1255 ssize_t ret;
1256 size_t i;
1257
1258 _init();
1259
1260 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
1261  ROAR_DBG("write(fd=%i, buf=%p, count=%lu) = ? // pointer write", fd, buf, (long unsigned int) count);
1262  switch (pointer->handle->type) {
1263   case HT_STREAM: // handle stream specific stuff
1264     if ( pointer->handle->stream_opened == 0 ) {
1265      if ( _open_stream(pointer->handle) == -1 ) {
1266       errno = EIO;
1267       return -1;
1268      }
1269     }
1270   case HT_VIO: // from here we only look at the VIO object of streams, or handle simple VIOs
1271     ret = roar_vio_write(&(pointer->handle->stream_vio), (char*)buf, count);
1272     if ( ret > 0 )
1273      pointer->handle->writec += ret;
1274     return ret;
1275    break;
1276   case HT_DMX: // DMX need specal handling as we need to convert the protocol
1277     if ( pointer->handle->stream_opened == 0 ) {
1278      if ( _open_stream(pointer->handle) == -1 ) {
1279       errno = EIO;
1280       return -1;
1281      }
1282     }
1283     if ( count > 0 ) {
1284      if ( roar_roardmx_message_new_sset(&roardmxmsg) == -1 ) {
1285       errno = EIO;
1286       return -1;
1287      }
1288      for (i = 0; i < count; i++) {
1289       if ( roar_roardmx_message_add_chanval(&roardmxmsg, pointer->handle->pos + i, ((unsigned char*)buf)[i]) == -1 ) {
1290#ifdef EMSGSIZE
1291        errno = EMSGSIZE;
1292#else
1293        errno = EIO;
1294#endif
1295        return -1;
1296       }
1297      }
1298      if ( roar_roardmx_message_send(&roardmxmsg, &(pointer->handle->stream_vio)) == -1 ) {
1299       errno = EIO;
1300       return -1;
1301      }
1302     }
1303     pointer->handle->pos += count;
1304     return count;
1305    break;
1306   default: // we don't know what to do with other types
1307     errno = EINVAL;
1308     return -1;
1309    break;
1310  }
1311 }
1312
1313 return _os.write(fd, buf, count);
1314}
1315
1316ssize_t read(int fd, void *buf, size_t count) {
1317 struct pointer * pointer;
1318 ssize_t ret;
1319
1320 _init();
1321
1322 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
1323  ROAR_DBG("read(fd=%i, buf=%p, count=%lu) = ? // pointer read", fd, buf, (long unsigned int)count);
1324
1325  switch (pointer->handle->type) {
1326   case HT_STREAM:
1327     if ( pointer->handle->stream_opened == 0 ) {
1328      if ( _open_stream(pointer->handle) == -1 ) {
1329       errno = EIO;
1330       return -1;
1331      }
1332     }
1333   case HT_VIO:
1334     ret = roar_vio_read(&(pointer->handle->stream_vio), buf, count);
1335     if ( ret > 0 )
1336      pointer->handle->readc += ret;
1337     return ret;
1338    break;
1339   case HT_STATIC:
1340     ROAR_DBG("read(fd=%i, buf=%p, count=%lu) = ? // type=HT_STATIC", fd, buf, (long unsigned int)count);
1341     ret = pointer->handle->pos + count; // calc the end of the read
1342
1343     if ( ret > (ssize_t)pointer->handle->userdata.sf.len ) {
1344      count = pointer->handle->userdata.sf.len - pointer->handle->pos;
1345     }
1346
1347     memcpy(buf, pointer->handle->userdata.sf.data + pointer->handle->pos, count);
1348     pointer->handle->pos += count;
1349     return count;
1350    break;
1351   default:
1352     errno = EINVAL;
1353     return -1;
1354    break;
1355  }
1356 }
1357
1358 return _os.read(fd, buf, count);
1359}
1360
1361off_t lseek(int fildes, off_t offset, int whence) {
1362 struct pointer * pointer;
1363 ssize_t tmp;
1364
1365 _init();
1366
1367 if ( (pointer = _get_pointer_by_fh(fildes)) != NULL ) {
1368  switch (pointer->handle->type) {
1369   case HT_DMX:
1370     switch (whence) {
1371      case SEEK_SET:
1372        pointer->handle->pos  = offset;
1373       break;
1374      case SEEK_CUR:
1375        pointer->handle->pos += offset;
1376       break;
1377      case SEEK_END:
1378      default:
1379        errno = EINVAL;
1380        return -1;
1381       break;
1382     }
1383     return pointer->handle->pos;
1384    break;
1385   case HT_VIO:
1386     return roar_vio_lseek(&(pointer->handle->stream_vio), offset, whence);
1387    break;
1388   case HT_STATIC:
1389     switch (whence) {
1390      case SEEK_SET:
1391        if ( offset < 0 || offset > (ssize_t)pointer->handle->userdata.sf.len ) {
1392         errno = EINVAL;
1393         return -1;
1394        }
1395        pointer->handle->pos  = offset;
1396       break;
1397      case SEEK_CUR:
1398        tmp = pointer->handle->pos + offset;
1399        if ( tmp < 0 || tmp > (ssize_t)pointer->handle->userdata.sf.len ) {
1400         errno = EINVAL;
1401         return -1;
1402        }
1403        pointer->handle->pos = tmp;
1404       break;
1405      case SEEK_END:
1406        tmp = pointer->handle->userdata.sf.len + offset;
1407        if ( tmp < 0 || tmp > (ssize_t)pointer->handle->userdata.sf.len ) {
1408         errno = EINVAL;
1409         return -1;
1410        }
1411        pointer->handle->pos = tmp;
1412       break;
1413      default:
1414        errno = EINVAL;
1415        return -1;
1416       break;
1417     }
1418    break;
1419   default:
1420     errno = EINVAL;
1421     return -1;
1422    break;
1423  }
1424 }
1425
1426 return _os.lseek(fildes, offset, whence);
1427}
1428
1429IOCTL() {
1430 map_args;
1431 struct pointer * pointer;
1432 struct handle  * handle;
1433 int * ip = NULL;
1434 size_t tmp;
1435 audio_buf_info * bi;
1436 count_info     * ci;
1437#ifdef __FIXME__
1438 char * nosys_reqname = NULL;
1439#endif
1440#ifdef va_argp
1441 va_list args;
1442#endif
1443
1444 _init();
1445
1446 ROAR_DBG("ioctl(__fd=%i, __request=0x%lX) = ?", __fd, (long unsigned int) __request);
1447
1448#ifdef va_argp
1449 va_start (args, ioctl_lastarg);
1450 argp = va_arg (args, void *);
1451 va_end (args);
1452#endif
1453
1454// ROAR_DBG("ioctl(fh=%i, request=%i, ...) = ?", __fd, __request);
1455
1456 ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): argp=%p", __fd, (long unsigned int) __request, argp);
1457
1458 if ( (pointer = _get_pointer_by_fh(__fd)) != NULL ) {
1459  ip = argp;
1460//  ROAR_DBG("ioctl(__fd=%i, __request=0x%lx): ip=%p", __fd, (long unsigned int) __request, ip);
1461#ifdef __FIXME__
1462  switch (__request) {
1463   case SOUND_PCM_READ_RATE: nosys_reqname     = "SOUND_PCM_READ_RATE";     break;
1464   case SOUND_PCM_READ_CHANNELS: nosys_reqname = "SOUND_PCM_READ_CHANNELS"; break;
1465   case SOUND_PCM_READ_BITS: nosys_reqname     = "SOUND_PCM_READ_BITS";     break;
1466   case SOUND_PCM_READ_FILTER: nosys_reqname   = "SOUND_PCM_READ_FILTER";   break;
1467   case SNDCTL_COPR_RESET: nosys_reqname       = "SNDCTL_COPR_RESET";       break;
1468   case SNDCTL_COPR_LOAD: nosys_reqname        = "SNDCTL_COPR_LOAD";        break;
1469   case SNDCTL_COPR_HALT: nosys_reqname        = "SNDCTL_COPR_HALT";        break;
1470   case SNDCTL_COPR_RDATA: nosys_reqname       = "SNDCTL_COPR_RDATA";       break;
1471   case SNDCTL_COPR_RCODE: nosys_reqname       = "SNDCTL_COPR_RCODE";       break;
1472   case SNDCTL_COPR_WDATA: nosys_reqname       = "SNDCTL_COPR_WDATA";       break;
1473   case SNDCTL_COPR_WCODE: nosys_reqname       = "SNDCTL_COPR_WCODE";       break;
1474   case SNDCTL_COPR_RUN: nosys_reqname         = "SNDCTL_COPR_RUN";         break;
1475   case SNDCTL_COPR_SENDMSG: nosys_reqname     = "SNDCTL_COPR_SENDMSG";     break;
1476   case SNDCTL_COPR_RCVMSG: nosys_reqname      = "SNDCTL_COPR_RCVMSG";      break;
1477   case SNDCTL_DSP_GETCAPS: nosys_reqname      = "SNDCTL_DSP_GETCAPS";      break;
1478   default: nosys_reqname = "<<<UNKNOWN>>>"; break;
1479/*
1480   case : nosys_reqname = ""; break;
1481   case : nosys_reqname = ""; break;
1482   case : nosys_reqname = ""; break;
1483*/
1484  }
1485#endif
1486  switch ((handle = pointer->handle)->type) {
1487   case HT_STREAM:
1488     switch (__request) {
1489      case SNDCTL_DSP_RESET:
1490      case SNDCTL_DSP_POST:
1491      case SNDCTL_DSP_SYNC: // ignore for the moment.
1492      case SNDCTL_DSP_SETFRAGMENT: // any fragments should be ok for us...
1493      case SNDCTL_DSP_SETTRIGGER: // we should implement this using PAUSE flag.
1494        return 0;
1495       break;
1496      case SNDCTL_DSP_SPEED:
1497        handle->stream.info.rate = *ip;
1498        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): rate=%i", __fd, (long unsigned int) __request, *ip);
1499        return 0;
1500       break;
1501      case SNDCTL_DSP_CHANNELS:
1502        handle->stream.info.channels = *ip;
1503        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): channels=%i", __fd, (long unsigned int) __request, *ip);
1504        return 0;
1505       break;
1506      case SNDCTL_DSP_STEREO:
1507        handle->stream.info.channels = *ip ? 2 : 1;
1508        return 0;
1509       break;
1510      case SNDCTL_DSP_GETBLKSIZE:
1511        *ip = _get_stream_buffersize(handle);
1512        return 0;
1513       break;
1514      case SNDCTL_DSP_SETFMT:
1515        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): fmt=0x%x", __fd, (long unsigned int) __request, *ip);
1516        return _ioctl_stream_format(handle, *ip);
1517       break;
1518      case SNDCTL_DSP_GETFMTS:
1519//        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): ip=%p", __fd, (long unsigned int) __request, ip);
1520        *ip = _ioctl_stream_format_list();
1521        return 0;
1522       break;
1523      case SNDCTL_DSP_GETOSPACE:
1524      case SNDCTL_DSP_GETISPACE:
1525        bi = argp;
1526        memset(bi, 0, sizeof(*bi));
1527        bi->bytes      = _get_stream_buffersize(handle);
1528        bi->fragments  = 1;
1529        bi->fragsize   = bi->bytes;
1530        bi->fragstotal = 1;
1531        return 0;
1532       break;
1533      case SNDCTL_DSP_GETOPTR:
1534        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): writec=%lu", __fd, (long unsigned int) __request, (long unsigned int) handle->writec);
1535        ci = argp;
1536        memset(ci, 0, sizeof(*ci));
1537        ci->bytes  = handle->writec;
1538        ci->blocks = ci->bytes / (tmp = _get_stream_buffersize(handle));
1539        ci->ptr    = ci->bytes % tmp;
1540        return 0;
1541       break;
1542      case SNDCTL_DSP_GETIPTR:
1543        ci = argp;
1544        memset(ci, 0, sizeof(*ci));
1545        ci->bytes  = handle->readc;
1546        ci->blocks = ci->bytes / (tmp = _get_stream_buffersize(handle));
1547        ci->ptr    = ci->bytes % tmp;
1548        return 0;
1549       break;
1550#ifdef SNDCTL_DSP_GETPLAYVOL
1551      case SNDCTL_DSP_GETPLAYVOL:
1552        return _ioctl_mixer(handle, SOUND_MIXER_READ_PCM, argp);
1553       break;
1554#endif
1555#ifdef SNDCTL_DSP_SETPLAYVOL
1556      case SNDCTL_DSP_SETPLAYVOL:
1557        return _ioctl_mixer(handle, SOUND_MIXER_WRITE_PCM, argp);
1558       break;
1559#endif
1560#ifdef SNDCTL_DSP_NONBLOCK
1561      case SNDCTL_DSP_NONBLOCK:
1562        return fcntl(__fd, F_SETFL, handle->sysio_flags|O_NONBLOCK);
1563       break;
1564#endif
1565      default:
1566#ifdef __FIXME__
1567        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX (%s)) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request, nosys_reqname);
1568#else
1569        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request);
1570#endif
1571        errno = ENOSYS;
1572        return -1;
1573     }
1574    break;
1575   case HT_MIXER:
1576     return _ioctl_mixer(handle, __request, argp);
1577    break;
1578   default:
1579     ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): unknown handle type: no ioctl()s supported", __fd, (long unsigned int) __request);
1580     ROAR_DBG("ioctl(__fd=%i, __request=0x%lX) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request);
1581     errno = EINVAL;
1582     return -1;
1583    break;
1584  }
1585 }
1586
1587#ifdef IOCTL_IS_ALIAS
1588 errno = ENOSYS;
1589 return -1;
1590#else
1591 ROAR_DBG("ioctl(__fd=%i, __request=0x%lX, argp=%p): not for us, passing to kernel", __fd, (long unsigned int) __request, argp);
1592 return _os.ioctl(__fd, __request, argp);
1593#endif
1594}
1595
1596int dup(int oldfd) {
1597 struct pointer * pointer;
1598 int ret;
1599
1600 _init();
1601
1602 ret = _os.dup(oldfd);
1603
1604 if (ret == -1)
1605  return -1;
1606
1607 if ( (pointer = _get_pointer_by_fh(oldfd)) != NULL ) {
1608  if ( _attach_pointer(pointer->handle, ret) == NULL ) {
1609   _os.close(ret);
1610   return -1;
1611  }
1612 }
1613
1614 return ret;
1615}
1616
1617int dup2(int oldfd, int newfd) {
1618 struct pointer * pointer;
1619 int ret;
1620
1621 _init();
1622
1623 ret = _os.dup2(oldfd, newfd);
1624
1625 if (ret == -1)
1626  return -1;
1627
1628 if ( (pointer = _get_pointer_by_fh(oldfd)) != NULL ) {
1629  if ( _attach_pointer(pointer->handle, ret) == NULL ) {
1630   _os.close(ret);
1631   return -1;
1632  }
1633 }
1634
1635 return ret;
1636}
1637
1638int select(int nfds, fd_set *readfds, fd_set *writefds,
1639           fd_set *exceptfds, struct timeval *timeout) {
1640 struct roar_vio_selecttv rtv;
1641 struct roar_vio_select * sv  = NULL;
1642 struct pointer * pointer;
1643 struct handle  * handle;
1644 ssize_t ret;
1645 size_t num = 0;
1646 size_t idx;
1647 int i;
1648 int i_r, i_w, i_e;
1649 int max_index = -1;
1650 static volatile int is_critical = 0;
1651
1652 _init();
1653
1654 if ( is_critical )
1655  return _os.select(nfds, readfds, writefds, exceptfds, timeout);
1656
1657 ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = ?", nfds, readfds, writefds, exceptfds, timeout);
1658
1659 if ( nfds == 0 ) {
1660  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = 0", nfds, readfds, writefds, exceptfds, timeout);
1661  return 0;
1662 }
1663
1664 if ( readfds == NULL && writefds == NULL && exceptfds == NULL ) {
1665  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = 0", nfds, readfds, writefds, exceptfds, timeout);
1666  return 0;
1667 }
1668
1669 if ( timeout != NULL ) {
1670  rtv.sec = timeout->tv_sec;
1671  rtv.nsec = timeout->tv_usec*1000;
1672 }
1673
1674 // count number of handles:
1675 for (i = 0; i < nfds; i++) {
1676  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p): i=%i, EXISTS", nfds, readfds, writefds, exceptfds, timeout, i);
1677  if ( (readfds   != NULL && FD_ISSET(i, readfds  )) ||
1678       (writefds  != NULL && FD_ISSET(i, writefds )) ||
1679       (exceptfds != NULL && FD_ISSET(i, exceptfds))
1680     ) {
1681   ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p): i=%i, EXISTS", nfds, readfds, writefds, exceptfds, timeout, i);
1682   num++;
1683   max_index = i;
1684  }
1685 }
1686
1687 if ( num == 0 ) {
1688  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = 0", nfds, readfds, writefds, exceptfds, timeout);
1689  return 0;
1690 }
1691
1692 nfds = max_index + 1;
1693
1694 // create sv;
1695 sv = roar_mm_malloc(sizeof(struct roar_vio_select)*num);
1696 if ( sv == NULL ) {
1697  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = -1", nfds, readfds, writefds, exceptfds, timeout);
1698  return -1;
1699 }
1700
1701 memset(sv, 0, sizeof(struct roar_vio_select)*num);
1702
1703 for (i = 0, idx = 0; i < nfds; i++) {
1704  if ( idx >= num ) {
1705   roar_mm_free(sv);
1706   errno = EFAULT;
1707   ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = -1 // i=%i, idx=%i, num=%i", nfds, readfds, writefds, exceptfds, timeout, i, (int)idx, (int)num);
1708   return -1;
1709  }
1710  i_r = readfds   != NULL && FD_ISSET(i, readfds);
1711  i_w = writefds  != NULL && FD_ISSET(i, writefds);
1712  i_e = exceptfds != NULL && FD_ISSET(i, exceptfds);
1713
1714  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p): i=%i, i_r=%i, i_w=%i, i_e=%i", nfds, readfds, writefds, exceptfds, timeout, i, i_r, i_w, i_e);
1715
1716  if ( i_r || i_w || i_e ) {
1717   // TODO: use VIO for pointers...
1718   if ( (pointer = _get_pointer_by_fh(i)) != NULL ) {
1719    handle = pointer->handle;
1720    sv[idx].vio     = NULL;
1721    sv[idx].fh      = -1;
1722    switch (handle->type) {
1723     case HT_DMX:
1724     case HT_STREAM:
1725       if ( ! handle->stream_opened ) {
1726        // implement this as statichly return OK
1727        errno = ENOSYS;
1728        return -1;
1729       }
1730     case HT_VIO:
1731       sv[idx].vio = &(handle->stream_vio);
1732      break;
1733     default: /* non supported type */
1734       errno = EINVAL;
1735       return -1;
1736      break;
1737    }
1738   } else {
1739    sv[idx].vio     = NULL;
1740    sv[idx].fh      = i;
1741   }
1742
1743   sv[idx].ud.si   = i;
1744   sv[idx].eventsq = (i_r ? ROAR_VIO_SELECT_READ   : 0) |
1745                     (i_w ? ROAR_VIO_SELECT_WRITE  : 0) |
1746                     (i_e ? ROAR_VIO_SELECT_EXCEPT : 0);
1747   idx++;
1748  }
1749 }
1750
1751 is_critical++;
1752 ret = roar_vio_select(sv, num, timeout == NULL ? NULL : &rtv, NULL);
1753 is_critical--;
1754
1755 if ( ret < 1 ) {
1756  roar_mm_free(sv);
1757  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = %i", nfds, readfds, writefds, exceptfds, timeout, (int)ret);
1758
1759  if ( ret == 0 ) {
1760   if ( readfds != NULL ) {
1761    FD_ZERO(readfds);
1762   }
1763   if ( writefds != NULL ) {
1764    FD_ZERO(writefds);
1765   }
1766   if ( exceptfds != NULL ) {
1767    FD_ZERO(exceptfds);
1768   }
1769  }
1770
1771  return ret;
1772 }
1773
1774 // update readfds, writefds, exceptfds:
1775 if ( readfds != NULL )
1776  FD_ZERO(readfds);
1777
1778 if ( writefds != NULL )
1779  FD_ZERO(writefds);
1780
1781 if ( exceptfds != NULL )
1782  FD_ZERO(exceptfds);
1783
1784 for (idx = 0; idx < num; idx++) {
1785  if ( sv[idx].eventsa == 0 )
1786   continue;
1787
1788  if ( sv[idx].eventsa & ROAR_VIO_SELECT_READ )
1789   if ( readfds != NULL )
1790    FD_SET(sv[idx].ud.si, readfds);
1791
1792  if ( sv[idx].eventsa & ROAR_VIO_SELECT_WRITE )
1793   if ( writefds != NULL )
1794    FD_SET(sv[idx].ud.si, writefds);
1795
1796  if ( sv[idx].eventsa & ROAR_VIO_SELECT_EXCEPT )
1797   if ( exceptfds != NULL )
1798    FD_SET(sv[idx].ud.si, exceptfds);
1799 }
1800
1801 roar_mm_free(sv);
1802
1803 ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = %i", nfds, readfds, writefds, exceptfds, timeout, (int)ret);
1804 return ret;
1805}
1806
1807int fcntl(int fd, int cmd, ...) {
1808 enum { NONE, UNKNOWN, LONG, POINTER } type = NONE;
1809 struct pointer * pointer;
1810 va_list ap;
1811 long argl = -1;
1812 void * vp = NULL;
1813 int ret   = -1;
1814 int diff;
1815
1816 _init();
1817
1818 ROAR_DBG("fcntl(fd=%i, cmd=%i, ...) = ?", fd, cmd);
1819
1820 switch (cmd) {
1821  case F_DUPFD:
1822  case F_SETFD:
1823  case F_SETFL:
1824  case F_SETOWN:
1825#ifdef F_SETSIG
1826  case F_SETSIG:
1827#endif
1828#ifdef F_SETLEASE
1829  case F_SETLEASE:
1830#endif
1831#ifdef F_NOTIFY
1832  case F_NOTIFY:
1833#endif
1834    type = LONG;
1835   break;
1836  case F_GETFD:
1837  case F_GETFL:
1838  case F_GETOWN:
1839#ifdef F_GETSIG
1840  case F_GETSIG:
1841#endif
1842#ifdef F_GETLEASE
1843  case F_GETLEASE:
1844#endif
1845    type = NONE;
1846   break;
1847  case F_GETLK:
1848  case F_SETLK:
1849  case F_SETLKW:
1850#ifdef F_GETLK64
1851#if F_GETLK64 != F_GETLK
1852  case F_GETLK64:
1853#endif
1854#endif
1855#ifdef F_SETLK64
1856#if F_SETLK64 != F_SETLK
1857  case F_SETLK64:
1858#endif
1859#endif
1860#ifdef F_SETLKW64
1861#if F_SETLKW64 != F_SETLKW
1862  case F_SETLKW64:
1863#endif
1864#endif
1865    type = POINTER;
1866   break;
1867/*
1868  case F_EXLCK:
1869  case F_GETLK64:
1870  case F_SETLK64:
1871  case F_SETLKW64:
1872  case F_SHLCK:
1873  case F_LINUX_SPECIFIC_BASE:
1874  case F_INPROGRESS:
1875*/
1876  default:
1877    type = UNKNOWN;
1878 }
1879
1880 if ( type == UNKNOWN ) {
1881  ROAR_DBG("fcntl(fd=%i, cmd=%i, ...): unknown data type!", fd, cmd);
1882  ROAR_DBG("fcntl(fd=%i, cmd=%i, ...) = -1 // errno = EINVAL", fd, cmd);
1883  errno = EINVAL;
1884  return -1;
1885 }
1886
1887 if ( type != NONE ) {
1888  va_start(ap, cmd);
1889  switch (type) {
1890   case LONG:
1891     argl = va_arg(ap, long);
1892    break;
1893   case POINTER:
1894     vp = va_arg(ap, void*);
1895    break;
1896   default: /* make compiler happy */
1897    break;
1898  }
1899  va_end(ap);
1900 }
1901
1902 if ( (pointer = _get_pointer_by_fh(fd)) == NULL ) {
1903  switch (type) {
1904   case NONE:
1905     ROAR_DBG("fcntl(fd=%i, cmd=%i): fd is true sysio, pass call to kernel", fd, cmd);
1906     return _os.fcntl(fd, cmd);
1907    break;
1908   case LONG:
1909     ROAR_DBG("fcntl(fd=%i, cmd=%i, arg=%li): fd is true sysio, pass call to kernel", fd, cmd, argl);
1910     return _os.fcntl(fd, cmd, argl);
1911    break;
1912   case POINTER:
1913     ROAR_DBG("fcntl(fd=%i, cmd=%i, lock=%p): fd is true sysio, pass call to kernel", fd, cmd, vp);
1914     return _os.fcntl(fd, cmd, vp);
1915    break;
1916   default: /* make compiler happy */
1917    break;
1918  }
1919 }
1920
1921 ROAR_DBG("fcntl(fd=%i, cmd=%i, ...): fd is true pointer, handle internaly", fd, cmd);
1922
1923 switch (cmd) {
1924  case F_DUPFD:
1925    ret = _os.fcntl(fd, F_DUPFD, argl);
1926
1927    if ( ret != -1 ) {
1928     if ( _attach_pointer(pointer->handle, ret) == NULL ) {
1929      _os.close(ret);
1930      ret = -1;
1931     }
1932    }
1933   break;
1934  case F_SETFD:
1935    if ( argl == 0 ) {
1936     ret = 0;
1937    } else {
1938     errno = ENOSYS;
1939     ret = -1;
1940    }
1941   break;
1942  case F_GETFD:
1943    ret = 0;
1944   break;
1945  case F_GETFL:
1946    ret = pointer->handle->sysio_flags;
1947   break;
1948  case F_SETFL:
1949    diff  = (int)argl ^ pointer->handle->sysio_flags;
1950    diff &= (int)~(int)_O_PARA_DIR;
1951    diff &= (int)~(int)_O_PARA_IGN;
1952
1953    if ( diff & O_NONBLOCK ) {
1954     diff -= O_NONBLOCK;
1955     pointer->handle->sysio_flags ^= O_NONBLOCK;
1956     if ( _update_nonblock(pointer->handle) == -1 ) {
1957      pointer->handle->sysio_flags ^= O_NONBLOCK;
1958      return -1;
1959     }
1960    }
1961
1962    if ( diff == 0 ) { // only flags changed we ignore anyway.
1963     pointer->handle->sysio_flags  = (int)argl;
1964     ret = 0;
1965    } else {
1966     errno = EINVAL;
1967     ret = -1;
1968    }
1969   break;
1970/* TODO: add support for those types:
1971  case F_SETFD:
1972  case F_SETOWN:
1973  case F_SETSIG:
1974  case F_SETLEASE:
1975  case F_NOTIFY:
1976  case F_GETOWN:
1977  case F_GETSIG:
1978  case F_GETLEASE:
1979  case F_GETLK:
1980  case F_SETLK:
1981  case F_SETLKW:
1982*/
1983  default:
1984    errno = ENOSYS;
1985    ret = -1;
1986   break;
1987 }
1988
1989 return ret;
1990}
1991
1992int access(const char *pathname, int mode) {
1993 struct devices * ptr = NULL;
1994
1995 _init();
1996
1997 if ( (ptr = _get_device(pathname)) != NULL ) {
1998  // the only flag we do not support is +x, which means
1999  // we need to reject all requets with X_OK.
2000  if ( mode & X_OK ) {
2001   errno = EACCES;
2002   return -1;
2003  }
2004
2005  // in addition HT_STATIC files do not support write (+w)
2006  // so we need to reject W_OK.
2007  if ( ptr->type == HT_STATIC && (mode & W_OK) ) {
2008   errno = EACCES;
2009   return -1;
2010  }
2011
2012  // Else the access is granted:
2013  return 0;
2014 }
2015
2016 return _os.access(pathname, mode);
2017}
2018
2019int creat(const char *_CREAT_ARG_PATHNAME, mode_t mode) {
2020 _init();
2021
2022 if ( _get_device(_CREAT_ARG_PATHNAME) != NULL ) {
2023  errno = EEXIST;
2024  return -1;
2025 }
2026
2027 return _os.creat(_CREAT_ARG_PATHNAME, mode);
2028}
2029
2030// -------------------------------------
2031// emulated *stat*() functions follow:
2032// -------------------------------------
2033
2034int stat(const char *path, struct stat *buf) {
2035 struct devices * ptr;
2036
2037 _init();
2038
2039 if ( (ptr = _get_device(path)) != NULL ) {
2040  errno = ENOSYS;
2041  return -1;
2042 }
2043
2044 return _os.stat(path, buf);
2045}
2046
2047int fstat(int filedes, struct stat *buf) {
2048 struct pointer * pointer;
2049
2050 _init();
2051
2052 if ( (pointer = _get_pointer_by_fh(filedes)) == NULL ) {
2053  return _os.fstat(filedes, buf);
2054 }
2055
2056 errno = ENOSYS;
2057 return -1;
2058}
2059
2060int lstat(const char *path, struct stat *buf) {
2061 _init();
2062
2063 if ( _get_device(path) != NULL ) {
2064  return stat(path, buf);
2065 }
2066
2067 return _os.lstat(path, buf);
2068}
2069
2070// -------------------------------------
2071// emulated stdio functions follow:
2072// -------------------------------------
2073
2074//roar_vio_to_stdio
2075
2076static int _vio_close    (struct roar_vio_calls * vio) {
2077 int ret = 0;
2078
2079 if ( roar_vio_get_fh(vio) != -1 )
2080  ret = close(roar_vio_get_fh(vio));
2081
2082 roar_mm_free(vio);
2083
2084 return ret;
2085}
2086
2087FILE *fopen(const char *path, const char *mode) {
2088 struct roar_vio_calls * vio;
2089 FILE  * fr;
2090 int     ret;
2091 int     r = 0, w = 0;
2092 int     flags = 0;
2093 int     i;
2094 register char c;
2095
2096 _init();
2097
2098 if ( path == NULL || mode == NULL ) {
2099  errno = EFAULT;
2100  return NULL;
2101 }
2102
2103 ROAR_DBG("open(path='%s', mode='%s') = ?\n", path, mode);
2104
2105 for (i = 0; (c = mode[i]) != 0; i++) {
2106  switch (c) {
2107   case 'r': r = 1; break;
2108   case 'w': w = 1; break;
2109   case 'a': w = 1; break;
2110   case '+':
2111     r = 1;
2112     w = 1;
2113    break;
2114  }
2115 }
2116
2117 if ( r && w ) {
2118  flags = O_RDWR;
2119 } else if ( r ) {
2120  flags = O_RDONLY;
2121 } else if ( w ) {
2122  flags = O_WRONLY;
2123 } else {
2124  errno = EINVAL;
2125  return NULL;
2126 }
2127
2128 ret = _open_file(path, flags);
2129
2130 switch (ret) {
2131  case -2:       // continue as normal, use _op.open()
2132    ROAR_DBG("fopen(path='%s', mode='%s'): not for us, passing to libc", path, mode);
2133   break;
2134  case -1:       // pass error to caller
2135    return NULL;
2136   break;
2137  default:       // return successfully opened pointer to caller
2138#ifdef __USE_FDOPEN__
2139    ROAR_DBG("fopen(path='%s', mode='%s') = fdopen(%i, '%s')", path, mode, ret, mode);
2140    return fdopen(ret, r ? (w ? "rw" : "r") : "w");
2141#else
2142    if ( (vio = roar_mm_malloc(sizeof(struct roar_vio_calls))) == NULL ) {
2143     return NULL; // errno should be set correctly by roar_mm_malloc().
2144    }
2145
2146    roar_vio_init_calls(vio);  // TODO: add error handling.
2147    roar_vio_set_fh(vio, ret); // TODO: add error handling.
2148    vio->close = _vio_close;
2149    if ( (fr = roar_vio_to_stdio(vio, flags)) == NULL ) {
2150     _vio_close(vio);
2151     errno = EIO;
2152     return NULL;
2153    } else {
2154     return fr;
2155    }
2156#endif
2157   break;
2158 }
2159
2160 return _os.fopen(path, mode);
2161}
2162
2163// -------------------------------------
2164// RoarAudio plugin functions follow:
2165// -------------------------------------
2166
2167ROAR_DL_PLUGIN_START(libroaross) {
2168 (void)para;
2169 _init();
2170} ROAR_DL_PLUGIN_END
2171
2172#endif
2173
2174//ll
Note: See TracBrowser for help on using the repository browser.