PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
iomanX.c
Go to the documentation of this file.
1/*
2# _____ ___ ____ ___ ____
3# ____| | ____| | | |____|
4# | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5#-----------------------------------------------------------------------
6# Copyright ps2dev - http://www.ps2dev.org
7# Licenced under Academic Free License version 2.0
8# Review ps2sdk README & LICENSE files for further details.
9*/
10
16#ifdef _IOP
17#include "irx_imports.h"
18#else
19#include <string.h>
20#include <types.h>
21#define index strchr
22#include <intrman.h>
23#include <stdio.h>
24#define Kprintf printf
25#endif
26#include <iomanX.h>
27
28#include <errno.h>
29#include <stdarg.h>
30
31#ifdef IOP
32#ifdef IOMANX_ENABLE_LEGACY_IOMAN_HOOK
33IRX_ID("IOX/File_Manager", 1, 1);
34#else
35IRX_ID("IO/File_Manager", 2, 3);
36// Based on the module from SCE SDK 3.1.0.
37#endif
38#endif
39#ifdef _IOP
40#ifdef IOMANX_ENABLE_LEGACY_IOMAN_HOOK
41extern struct irx_export_table _exp_iomanx;
42#else
43extern struct irx_export_table _exp_ioman;
44#endif
45#endif
46
47#ifdef IOMANX_ENABLE_LEGACY_IOMAN_HOOK
48#define MAX_DEVICES 32
49#define MAX_FILES 128
50#else
51#define MAX_DEVICES 16
52#define MAX_FILES 32
53#endif
54
55#ifndef IOMANX_ENABLE_LEGACY_IOMAN_HOOK
56void iomanX_StdioInit(int mode);
57static int open_tty_handles(const char *tty_name);
58#endif
59static int xx_stat(int op, const char *name, iox_stat_t *stat, unsigned int statmask);
60static int xx_rename(int op, const char *oldname, const char *newname);
61static int xx_dir(int op, const char *name, int mode);
62static int _ioabort(const char *str1, const char *str2);
63static iomanX_iop_file_t *new_iob(void);
64static iomanX_iop_file_t *get_iob(int fd);
65static iomanX_iop_device_t *lookup_dev(const char *name, int show_unkdev_msg);
66static const char *parsefile(const char *path, iomanX_iop_device_t **p_device, int *p_unit);
67#ifndef IOMANX_ENABLE_LEGACY_IOMAN_HOOK
68static int tty_noop(void);
69unsigned int iomanX_GetDevType(int fd);
70#endif
71static void ShowDrv(void);
72#ifndef IOMANX_ENABLE_LEGACY_IOMAN_HOOK
73static void register_tty(void);
74static void register_dummytty(void);
75#endif
76
77#ifdef IOMANX_USE_DEVICE_LINKED_LIST
78struct ioman_dev_listentry
79{
80 struct ioman_dev_listentry *next;
81 iomanX_iop_device_t *device;
82};
83#endif
84
85static int showdrvflag = 1;
86#ifndef IOMANX_ENABLE_LEGACY_IOMAN_HOOK
87
88IOMANX_RETURN_VALUE_IMPL(0);
89
90static iomanX_iop_device_ops_t dev_tty_dev_operations = {
91 IOMANX_RETURN_VALUE(0), // init
92 IOMANX_RETURN_VALUE(0), // deinit
93 IOMANX_RETURN_VALUE(0), // format
94 IOMANX_RETURN_VALUE(0), // open
95 IOMANX_RETURN_VALUE(0), // close
96 IOMANX_RETURN_VALUE(0), // read
97 IOMANX_RETURN_VALUE(0), // write
98 IOMANX_RETURN_VALUE(0), // lseek
99 IOMANX_RETURN_VALUE(0), // ioctl
100 IOMANX_RETURN_VALUE(0), // remove
101 IOMANX_RETURN_VALUE(0), // mkdir
102 IOMANX_RETURN_VALUE(0), // rmdir
103 IOMANX_RETURN_VALUE(0), // dopen
104 IOMANX_RETURN_VALUE(0), // dclose
105 IOMANX_RETURN_VALUE(0), // dread
106 IOMANX_RETURN_VALUE(0), // getstat
107 IOMANX_RETURN_VALUE(0), // chstat
108 IOMANX_RETURN_VALUE(0), // rename
109 IOMANX_RETURN_VALUE(0), // chdir
110 IOMANX_RETURN_VALUE(0), // sync
111 IOMANX_RETURN_VALUE(0), // mount
112 IOMANX_RETURN_VALUE(0), // umount
113 IOMANX_RETURN_VALUE_S64(0), // lseek64
114 IOMANX_RETURN_VALUE(0), // devctl
115 IOMANX_RETURN_VALUE(0), // symlink
116 IOMANX_RETURN_VALUE(0), // readlink
117 IOMANX_RETURN_VALUE(0), // ioctl2
118};
119static iomanX_iop_device_t dev_tty = {
120 "tty",
121 IOP_DT_CHAR,
122 1,
123 "CONSOLE",
124 &dev_tty_dev_operations,
125};
126static iomanX_iop_device_t dev_dummytty = {
127 "dummytty",
128 IOP_DT_CHAR,
129 1,
130 "CONSOLE",
131 &dev_tty_dev_operations,
132};
133#endif
134static int adddeldrv_in_process;
135#ifdef IOMANX_USE_ERRNO
136static int errno_local;
137#endif
138#ifdef IOMANX_USE_DEVICE_LINKED_LIST
139static struct ioman_dev_listentry *device_entry_empty_list_head;
140static struct ioman_dev_listentry *device_entry_used_list_head;
141#endif
142#ifndef IOMANX_ENABLE_LEGACY_IOMAN_HOOK
143static
144#endif
145 iomanX_iop_file_t file_table[MAX_FILES];
146#ifdef IOMANX_USE_DEVICE_LINKED_LIST
147static struct ioman_dev_listentry device_entry_list[MAX_DEVICES];
148#else
149static iomanX_iop_device_t *device_table[MAX_DEVICES];
150#endif
151
152#ifndef isnum
153#define isnum(c) ((c) >= '0' && (c) <= '9')
154#endif
155
156#ifndef EUNSUP
157#ifdef ENOTSUP
158#define EUNSUP ENOTSUP
159#else
160#define EUNSUP 48
161#endif
162#endif
163
164#define HANDLE_RESULT_CLEAR_INFO 1
165#define HANDLE_RESULT_CLEAR_INFO_ON_ERROR 2
166#define HANDLE_RESULT_RETURN_ZERO 4
167#define HANDLE_RESULT_RETURN_FD 8
168
169static inline void write_str_to_stdout(const char *in_str)
170{
171 iomanX_write(1, (void *)in_str, strlen(in_str));
172}
173
174static inline int set_errno(int in_errno)
175{
176#ifdef IOMANX_USE_ERRNO
177 errno_local = in_errno;
178#endif
179 return -in_errno;
180}
181
182static inline void handle_result_pre(int in_result, iomanX_iop_file_t *f, int op)
183{
184 if ( (op & HANDLE_RESULT_CLEAR_INFO) )
185 {
186 if ( f )
187 {
188 // Unofficial: don't clear mode
189 f->device = NULL;
190 }
191 }
192 if ( (op & HANDLE_RESULT_CLEAR_INFO_ON_ERROR) )
193 {
194 if ( f && (in_result < 0) )
195 {
196 f->device = NULL;
197 }
198 }
199}
200
201static inline int handle_result(int in_result, iomanX_iop_file_t *f, int op)
202{
203 handle_result_pre(in_result, f, op);
204 if ( in_result < 0 )
205 return set_errno(-in_result);
206 if ( (op & HANDLE_RESULT_RETURN_ZERO) )
207 return 0;
208 if ( (op & HANDLE_RESULT_RETURN_FD) )
209 return f - file_table;
210 return in_result;
211}
212
213static inline s64 handle_result64(s64 in_result, iomanX_iop_file_t *f, int op)
214{
215 handle_result_pre(in_result, f, op);
216 if ( in_result < 0 )
217 return set_errno(-(int)in_result);
218 if ( (op & HANDLE_RESULT_RETURN_ZERO) )
219 return 0;
220 if ( (op & HANDLE_RESULT_RETURN_FD) )
221 return f - file_table;
222 return in_result;
223}
224
225#ifdef IOMANX_ENABLE_LEGACY_IOMAN_HOOK
226extern int hook_ioman();
227extern int unhook_ioman();
228#endif
229
230#ifndef IOMANX_ENTRYPOINT
231#ifdef _IOP
232#define IOMANX_ENTRYPOINT _start
233#else
234#define IOMANX_ENTRYPOINT iomanX_start
235#endif
236#endif
237
238#ifndef IOMANX_CLEANUP
239#define IOMANX_CLEANUP shutdown
240#endif
241
242int IOMANX_ENTRYPOINT(int ac, char **av)
243{
244#ifdef IOMANX_USE_DEVICE_LINKED_LIST
245 unsigned int i;
246#endif
247
248 (void)ac;
249 (void)av;
250
251#ifdef _IOP
252#ifdef IOMANX_ENABLE_LEGACY_IOMAN_HOOK
253 if ( RegisterLibraryEntries(&_exp_iomanx) )
254 return MODULE_NO_RESIDENT_END;
255#else
256 if ( RegisterLibraryEntries(&_exp_ioman) )
257 return MODULE_NO_RESIDENT_END;
258#if 0
259 SetRebootTimeLibraryHandlingMode(&_exp_ioman, 2);
260#else
261 // Call termination before disabling interrupts
262 _exp_ioman.mode &= ~6;
263 _exp_ioman.mode |= 2;
264#endif
265#endif
266#endif
267 adddeldrv_in_process = 0;
268#ifdef IOMANX_USE_DEVICE_LINKED_LIST
269 // Unofficial: memset instead of bzero
270 memset(device_entry_list, 0, sizeof(device_entry_list));
271 device_entry_used_list_head = NULL;
272 device_entry_empty_list_head = device_entry_list;
273 // Unofficial: link forwards instead of backwards
274 for ( i = 0; i < ((sizeof(device_entry_list) / sizeof(device_entry_list[0])) - 1); i += 1 )
275 device_entry_list[i].next = &device_entry_list[i + 1];
276#else
277 memset(device_table, 0, sizeof(device_table));
278#endif
279 // Unofficial: memset instead of bzero
280 memset(file_table, 0, sizeof(file_table));
281#ifdef IOMANX_ENABLE_LEGACY_IOMAN_HOOK
282 if ( hook_ioman() )
283 return MODULE_NO_RESIDENT_END;
284#else
285 iomanX_StdioInit(0);
286#endif
287 return MODULE_RESIDENT_END;
288}
289
290int IOMANX_CLEANUP(int arg)
291{
292#ifdef IOMANX_ENABLE_LEGACY_IOMAN_HOOK
293 unhook_ioman();
294 return MODULE_NO_RESIDENT_END;
295#else
296#ifdef IOMANX_USE_DEVICE_LINKED_LIST
297 struct ioman_dev_listentry *i;
298#else
299 unsigned int i;
300#endif
301
302 if ( !arg )
303 {
304#ifdef IOMANX_USE_DEVICE_LINKED_LIST
305 for ( i = device_entry_used_list_head; i; i = i->next )
306 {
307 i->device->ops->deinit(i->device);
308 i->device = NULL;
309 }
310#else
311 for ( i = 0; i < (sizeof(device_table) / sizeof(device_table[0])); i += 1 )
312 {
313 if ( device_table[i] )
314 {
315 device_table[i]->ops->deinit(device_table[i]);
316 device_table[i] = NULL;
317 }
318 }
319#endif
320 }
321 return MODULE_RESIDENT_END;
322#endif
323}
324
325#ifdef IOMANX_ENABLE_LEGACY_IOMAN_HOOK
326iomanX_iop_device_t **iomanX_GetDeviceList(void)
327{
328 return device_table;
329}
330
331int mode2modex(int mode)
332{
333 int modex = 0;
334
335 if ( FIO_SO_ISLNK(mode) )
336 modex |= FIO_S_IFLNK;
337 if ( FIO_SO_ISREG(mode) )
338 modex |= FIO_S_IFREG;
339 if ( FIO_SO_ISDIR(mode) )
340 modex |= FIO_S_IFDIR;
341
342 /* Convert the file access modes. */
343 if ( mode & FIO_SO_IROTH )
345 if ( mode & FIO_SO_IWOTH )
347 if ( mode & FIO_SO_IXOTH )
349
350 return modex;
351}
352
353int modex2mode(int modex)
354{
355 int mode = 0;
356
357 if ( FIO_S_ISLNK(modex) )
358 mode |= FIO_SO_IFLNK;
359 if ( FIO_S_ISREG(modex) )
360 mode |= FIO_SO_IFREG;
361 if ( FIO_S_ISDIR(modex) )
362 mode |= FIO_SO_IFDIR;
363
364 /* Convert the file access modes. */
365 if ( modex & (FIO_S_IRUSR | FIO_S_IRGRP | FIO_S_IROTH) )
366 mode |= FIO_SO_IROTH;
367 if ( modex & (FIO_S_IWUSR | FIO_S_IWGRP | FIO_S_IWOTH) )
368 mode |= FIO_SO_IWOTH;
369 if ( modex & (FIO_S_IXUSR | FIO_S_IXGRP | FIO_S_IXOTH) )
370 mode |= FIO_SO_IXOTH;
371
372 return mode;
373}
374
375iomanX_iop_file_t *get_file(int fd)
376{
377 return get_iob(fd);
378}
379#endif
380
381#ifndef IOMANX_ENABLE_LEGACY_IOMAN_HOOK
382void iomanX_StdioInit(int mode)
383{
384#ifdef _IOP
385 const int *BootMode;
386 iop_thread_info_t thinfo;
387#endif
388
389#ifdef _IOP
390 BootMode = QueryBootMode(3);
391 if ( BootMode && (BootMode[1] & 4) )
392 return;
393 ReferThreadStatus(0, &thinfo);
394 ChangeThreadPriority(0, 4);
395#endif
396#ifdef _IOP
397 switch ( mode )
398 {
399 case 0:
400 {
401 iomanX_close(0);
402 iomanX_close(1);
403 register_tty();
404 open_tty_handles("tty:");
405 break;
406 }
407 case 1:
408 {
409 iomanX_close(0);
410 iomanX_close(1);
411 register_dummytty();
412 open_tty_handles("dummytty:");
413 break;
414 }
415 default:
416 break;
417 }
418#else
419 iomanX_close(0);
420 iomanX_close(1);
421 register_tty();
422 open_tty_handles("tty:");
423#endif
424#ifdef _IOP
425 ChangeThreadPriority(0, thinfo.currentPriority);
426#endif
427}
428
429static int open_tty_handles(const char *tty_name)
430{
431 if ( iomanX_open(tty_name, 3) != 0 || iomanX_open(tty_name, 2) != 1 )
432 return -1;
433 return 0;
434}
435#endif
436
437int iomanX_open(const char *name, int flags, ...)
438{
440 const char *parsefile_res;
441 int mode;
442 va_list va;
443
444 va_start(va, flags);
445 mode = va_arg(va, int);
446 va_end(va);
447 f = new_iob();
448 if ( !f )
449 return handle_result(-EMFILE, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
450 parsefile_res = parsefile(name, &(f->device), &(f->unit));
451 if ( !parsefile_res )
452 return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
453 f->mode = flags;
454 return handle_result(
455 f->device->ops->open(f, parsefile_res, flags, mode),
456 f,
457 HANDLE_RESULT_CLEAR_INFO_ON_ERROR | HANDLE_RESULT_RETURN_FD);
458}
459
460int iomanX_lseek(int fd, int offset, int mode)
461{
463
464 f = get_iob(fd);
465 if ( !f )
466 return handle_result(-EBADF, f, 0);
467 switch ( mode )
468 {
469 case FIO_SEEK_SET:
470 case FIO_SEEK_CUR:
471 case FIO_SEEK_END:
472 return handle_result(f->device->ops->lseek(f, offset, mode), f, 0);
473 default:
474 write_str_to_stdout("invalid lseek arg\r\n");
475 return handle_result(-EINVAL, f, 0);
476 }
477}
478
479s64 iomanX_lseek64(int fd, s64 offset, int whence)
480{
482
483 f = get_iob(fd);
484 if ( !f )
485 return handle_result(-EBADF, f, 0);
486 if ( (f->device->type & 0xF0000000) != IOP_DT_FSEXT )
487 return handle_result(-EUNSUP, f, 0);
488 switch ( whence )
489 {
490 case FIO_SEEK_SET:
491 case FIO_SEEK_CUR:
492 case FIO_SEEK_END:
493 return handle_result64(f->device->ops->lseek64(f, offset, whence), f, 0);
494 default:
495 write_str_to_stdout("invalid lseek arg\r\n");
496 return handle_result(-EINVAL, f, 0);
497 }
498}
499
500int iomanX_read(int fd, void *ptr, int size)
501{
503
504 f = get_iob(fd);
505 if ( !f || !(f->mode & FIO_O_RDONLY) )
506 return handle_result(-EBADF, f, 0);
507 return handle_result(f->device->ops->read(f, ptr, size), f, 0);
508}
509
510int iomanX_write(int fd, void *ptr, int size)
511{
513
514 f = get_iob(fd);
515 if ( !f || !(f->mode & FIO_O_WRONLY) )
516 return handle_result(-EBADF, f, 0);
517 return handle_result(f->device->ops->write(f, ptr, size), f, 0);
518}
519
520int iomanX_close(int fd)
521{
523
524 f = get_iob(fd);
525 if ( !f )
526 return handle_result(-EBADF, f, 0);
527 return handle_result(
528 (f->mode & FIO_O_DIROPEN) ? f->device->ops->dclose(f) : f->device->ops->close(f),
529 f,
530 HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_FD);
531}
532
533int iomanX_ioctl(int fd, int cmd, void *param)
534{
536
537 f = get_iob(fd);
538 if ( !f )
539 return handle_result(-EBADF, f, 0);
540 return handle_result(f->device->ops->ioctl(f, cmd, param), f, 0);
541}
542
543int iomanX_ioctl2(int fd, int cmd, void *arg, unsigned int arglen, void *buf, unsigned int buflen)
544{
546
547 f = get_iob(fd);
548 if ( !f )
549 return handle_result(-EBADF, f, 0);
550 // The filesystem must support these ops.
551 if ( (f->device->type & 0xF0000000) != IOP_DT_FSEXT )
552 return handle_result(-EUNSUP, f, 0);
553 return handle_result(f->device->ops->ioctl2(f, cmd, arg, arglen, buf, buflen), f, 0);
554}
555
556int iomanX_dopen(const char *path)
557{
559 const char *parsefile_res;
560
561 f = new_iob();
562 if ( !f )
563 return handle_result(-EMFILE, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
564 parsefile_res = parsefile(path, &(f->device), &(f->unit));
565 if ( !parsefile_res )
566 return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
567 f->mode = FIO_O_DIROPEN;
568 return handle_result(
569 f->device->ops->dopen(f, parsefile_res), f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR | HANDLE_RESULT_RETURN_FD);
570}
571
572int iomanX_dread(int fd, iox_dirent_t *buf)
573{
575
576 f = get_iob(fd);
577 if ( !f || !(f->mode & FIO_O_DIROPEN) )
578 return handle_result(-EBADF, f, 0);
579#ifdef IOMANX_ENABLE_LEGACY_IOMAN_HOOK
580 /* If this is a legacy device (such as mc:) then we need to convert the mode
581 variable of the stat structure to iomanX's extended format. */
582 if ( (f->device->type & 0xF0000000) != IOP_DT_FSEXT )
583 {
584 int res;
585 typedef int io_dread_t(iomanX_iop_file_t *, io_dirent_t *);
586 io_dirent_t io_dirent;
587 io_dread_t *io_dread;
588
589 io_dread = (io_dread_t *)f->device->ops->dread;
590 res = io_dread(f, &io_dirent);
591
592 buf->stat.mode = mode2modex(io_dirent.stat.mode);
593
594 buf->stat.attr = io_dirent.stat.attr;
595 buf->stat.size = io_dirent.stat.size;
596 memcpy(buf->stat.ctime, io_dirent.stat.ctime, sizeof(io_dirent.stat.ctime));
597 memcpy(buf->stat.atime, io_dirent.stat.atime, sizeof(io_dirent.stat.atime));
598 memcpy(buf->stat.mtime, io_dirent.stat.mtime, sizeof(io_dirent.stat.mtime));
599 buf->stat.hisize = io_dirent.stat.hisize;
600
601 strncpy(buf->name, io_dirent.name, sizeof(buf->name));
602 return handle_result(res, f, 0);
603 }
604#endif
605 return handle_result(f->device->ops->dread(f, buf), f, 0);
606}
607
608int iomanX_remove(const char *name)
609{
611 const char *parsefile_res;
612#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
613 iomanX_iop_file_t f_stk;
614#endif
615
616#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
617 f = &f_stk;
618#else
619 f = new_iob();
620 if ( !f )
621 return handle_result(-EMFILE, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
622#endif
623 parsefile_res = parsefile(name, &(f->device), &(f->unit));
624 if ( !parsefile_res )
625 return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
626 return handle_result(
627 f->device->ops->remove(f, parsefile_res), f, HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO);
628}
629
630int iomanX_mkdir(const char *path, int mode)
631{
632 return xx_dir(4, path, mode);
633}
634
635int iomanX_rmdir(const char *path)
636{
637 return xx_dir(5, path, 0);
638}
639
640static int xx_stat(int op, const char *name, iox_stat_t *stat, unsigned int statmask)
641{
643 const char *parsefile_res;
644#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
645 iomanX_iop_file_t f_stk;
646#endif
647
648#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
649 f = &f_stk;
650#else
651 f = new_iob();
652 if ( !f )
653 return handle_result(-EMFILE, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
654#endif
655 parsefile_res = parsefile(name, &(f->device), &(f->unit));
656 if ( !parsefile_res )
657 return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
658 switch ( op )
659 {
660 case 1:
661 {
662#ifdef IOMANX_ENABLE_LEGACY_IOMAN_HOOK
663 /* If this is a legacy device (such as mc:) then we need to convert the mode
664 variable to iomanX's extended format. */
665 if ( (f->device->type & 0xF0000000) != IOP_DT_FSEXT )
666 {
667 iox_stat_t stat_tmp;
668
669 memcpy(&stat_tmp, stat, sizeof(stat_tmp));
670 stat_tmp.mode = modex2mode(stat->mode);
671 return handle_result(
672 f->device->ops->chstat(f, parsefile_res, &stat_tmp, statmask),
673 f,
674 HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO);
675 }
676#endif
677 return handle_result(
678 f->device->ops->chstat(f, parsefile_res, stat, statmask),
679 f,
680 HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO);
681 }
682 case 2:
683 {
684#ifdef IOMANX_ENABLE_LEGACY_IOMAN_HOOK
685 /* If this is a legacy device (such as mc:) then we need to convert the mode
686 variable to iomanX's extended format. */
687 if ( (f->device->type & 0xF0000000) != IOP_DT_FSEXT )
688 {
689 int res;
690
691 res = f->device->ops->getstat(f, parsefile_res, stat);
692 if ( res == 0 )
693 stat->mode = mode2modex(stat->mode);
694 return handle_result(res, f, HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO);
695 }
696#endif
697 return handle_result(
698 f->device->ops->getstat(f, parsefile_res, stat), f, HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO);
699 }
700 default:
701 // Unofficial: return negative instead of positive if op not found
702 return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
703 }
704}
705
706int iomanX_getstat(const char *name, iox_stat_t *stat)
707{
708 return xx_stat(2, name, stat, 0);
709}
710
711int iomanX_chstat(const char *name, iox_stat_t *stat, unsigned int statmask)
712{
713 return xx_stat(1, name, stat, statmask);
714}
715
716int iomanX_format(const char *dev, const char *blockdev, void *arg, int arglen)
717{
719 const char *parsefile_res;
720#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
721 iomanX_iop_file_t f_stk;
722#endif
723
724#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
725 f = &f_stk;
726#else
727 f = new_iob();
728 if ( !f )
729 return handle_result(-EMFILE, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
730#endif
731 parsefile_res = parsefile(dev, &(f->device), &(f->unit));
732 if ( !parsefile_res )
733 return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
734 return handle_result(
735 f->device->ops->format(f, parsefile_res, blockdev, arg, arglen),
736 f,
737 HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO);
738}
739
740static int xx_rename(int op, const char *oldname, const char *newname)
741{
743 const char *parsefile_res;
744 const char *parsefile_res_new;
745 iomanX_iop_device_t *device_new;
746 int unit_new;
747#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
748 iomanX_iop_file_t f_stk;
749#endif
750
751#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
752 f = &f_stk;
753#else
754 f = new_iob();
755 if ( !f )
756 return handle_result(-EMFILE, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
757#endif
758 parsefile_res = parsefile(oldname, &(f->device), &(f->unit));
759 if ( !parsefile_res )
760 return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
761 // Unofficial: initialize variables and check if newname is not NULL
762 parsefile_res_new = newname;
763 device_new = f->device;
764 unit_new = f->unit;
765 if ( newname && index(newname, ':') )
766 parsefile_res_new = parsefile(newname, &device_new, &unit_new);
767 // Make sure the user isn't attempting to link across devices.
768 if ( !parsefile_res_new || (device_new != f->device) || (unit_new != f->unit) )
769 return handle_result(-EXDEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
770 // The filesystem must support these ops.
771 if ( (f->device->type & 0xF0000000) != IOP_DT_FSEXT )
772 return handle_result(-EUNSUP, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
773 switch ( op )
774 {
775 case 7:
776 return handle_result(
777 f->device->ops->rename(f, parsefile_res, parsefile_res_new),
778 f,
779 HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO);
780 case 8:
781 return handle_result(
782 f->device->ops->symlink(f, parsefile_res, parsefile_res_new),
783 f,
784 HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO);
785 default:
786 // Unofficial: return negative instead of positive if op not found
787 return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
788 }
789}
790
791// cppcheck-suppress funcArgNamesDifferent
792int iomanX_rename(const char *oldname, const char *newname)
793{
794 return xx_rename(7, oldname, newname);
795}
796
797// cppcheck-suppress funcArgNamesDifferent
798int iomanX_symlink(const char *oldname, const char *newname)
799{
800 return xx_rename(8, oldname, newname);
801}
802
803int iomanX_chdir(const char *name)
804{
805 return xx_dir(0x103, name, 0);
806}
807
808/* Because mkdir, rmdir, chdir, and sync have similiar arguments (each starts
809 with a path followed by an optional integer), we use a common routine to
810 handle all of them. */
811static int xx_dir(int op, const char *name, int mode)
812{
814 const char *parsefile_res;
815#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
816 iomanX_iop_file_t f_stk;
817#endif
818
819#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
820 f = &f_stk;
821#else
822 f = new_iob();
823 if ( !f )
824 return handle_result(-EMFILE, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
825#endif
826 parsefile_res = parsefile(name, &(f->device), &(f->unit));
827 if ( !parsefile_res )
828 return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
829 // The filesystem must support these ops.
830 if ( (op & 0x100) && ((f->device->type & 0xF0000000) != IOP_DT_FSEXT) )
831 return handle_result(-EUNSUP, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
832 switch ( op )
833 {
834 case 4:
835 return handle_result(
836 f->device->ops->mkdir(f, parsefile_res, mode), f, HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO);
837 case 5:
838 return handle_result(
839 f->device->ops->rmdir(f, parsefile_res), f, HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO);
840 case 0x103:
841 return handle_result(
842 f->device->ops->chdir(f, parsefile_res), f, HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO);
843 case 0x106:
844 return handle_result(
845 f->device->ops->sync(f, parsefile_res, mode), f, HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO);
846 default:
847 // Unofficial: return negative instead of positive if op not found
848 return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
849 }
850}
851
852int iomanX_sync(const char *dev, int flag)
853{
854 return xx_dir(0x106, dev, flag);
855}
856
857int iomanX_mount(const char *fsname, const char *devname, int flag, void *arg, int arglen)
858{
860 const char *parsefile_res;
861#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
862 iomanX_iop_file_t f_stk;
863#endif
864
865#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
866 f = &f_stk;
867#else
868 f = new_iob();
869 if ( !f )
870 return handle_result(-EMFILE, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
871#endif
872 parsefile_res = parsefile(fsname, &(f->device), &(f->unit));
873 if ( !parsefile_res )
874 return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
875 // The filesystem must support these ops.
876 if ( (f->device->type & 0xF0000000) != IOP_DT_FSEXT )
877 return handle_result(-EUNSUP, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
878 return handle_result(
879 f->device->ops->mount(f, parsefile_res, devname, flag, arg, arglen),
880 f,
881 HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO);
882}
883
884int iomanX_umount(const char *fsname)
885{
887 const char *parsefile_res;
888#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
889 iomanX_iop_file_t f_stk;
890#endif
891
892#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
893 f = &f_stk;
894#else
895 f = new_iob();
896 if ( !f )
897 return handle_result(-EMFILE, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
898#endif
899 parsefile_res = parsefile(fsname, &(f->device), &(f->unit));
900 if ( !parsefile_res )
901 return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
902 // The filesystem must support these ops.
903 if ( (f->device->type & 0xF0000000) != IOP_DT_FSEXT )
904 return handle_result(-EUNSUP, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
905 return handle_result(
906 f->device->ops->umount(f, parsefile_res), f, HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO);
907}
908
909int iomanX_devctl(const char *name, int cmd, void *arg, unsigned int arglen, void *buf, unsigned int buflen)
910{
912 const char *parsefile_res;
913#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
914 iomanX_iop_file_t f_stk;
915#endif
916
917#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
918 f = &f_stk;
919#else
920 f = new_iob();
921 if ( !f )
922 return handle_result(-EMFILE, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
923#endif
924 parsefile_res = parsefile(name, &(f->device), &(f->unit));
925 if ( !parsefile_res )
926 return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
927 // The filesystem must support these ops.
928 if ( (f->device->type & 0xF0000000) != IOP_DT_FSEXT )
929 return handle_result(-EUNSUP, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
930 return handle_result(
931 f->device->ops->devctl(f, parsefile_res, cmd, arg, arglen, buf, buflen), f, HANDLE_RESULT_CLEAR_INFO);
932}
933
934int iomanX_readlink(const char *path, char *buf, unsigned int buflen)
935{
937 const char *parsefile_res;
938#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
939 iomanX_iop_file_t f_stk;
940#endif
941
942#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
943 f = &f_stk;
944#else
945 f = new_iob();
946 if ( !f )
947 return handle_result(-EMFILE, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
948#endif
949 parsefile_res = parsefile(path, &(f->device), &(f->unit));
950 if ( !parsefile_res )
951 return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
952 // The filesystem must support these ops.
953 if ( (f->device->type & 0xF0000000) != IOP_DT_FSEXT )
954 return handle_result(-EUNSUP, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
955 return handle_result(f->device->ops->readlink(f, parsefile_res, buf, buflen), f, HANDLE_RESULT_CLEAR_INFO);
956}
957
958static int _ioabort(const char *str1, const char *str2)
959{
960 return Kprintf("ioabort exit:%s %s\n", str1, str2);
961}
962
963static iomanX_iop_file_t *new_iob(void)
964{
965 iomanX_iop_file_t *file_table_entry;
966 int state;
967 int fd;
968
969 fd = 0;
970 CpuSuspendIntr(&state);
971 file_table_entry = NULL;
972 while ( fd < (int)(sizeof(file_table) / sizeof(file_table[0])) )
973 {
974 if ( !file_table[fd].device )
975 {
976 file_table_entry = &file_table[fd];
977 break;
978 }
979 fd += 1;
980 }
981 // fill in "device" temporarily to mark the fd as allocated.
982 if ( file_table_entry )
983 file_table_entry->device = (iomanX_iop_device_t *)(uiptr)0xFFFFFFEC;
984 CpuResumeIntr(state);
985 if ( !file_table_entry )
986 _ioabort("out of file descriptors", "[too many open]");
987 return file_table_entry;
988}
989
990static iomanX_iop_file_t *get_iob(int fd)
991{
992 if ( (fd < 0) || (fd >= (int)(sizeof(file_table) / sizeof(file_table[0]))) || (!file_table[fd].device) )
993 return NULL;
994 return &file_table[fd];
995}
996
997static iomanX_iop_device_t *lookup_dev(const char *name, int show_unkdev_msg)
998{
999#ifdef IOMANX_USE_DEVICE_LINKED_LIST
1000 struct ioman_dev_listentry *entry;
1001#else
1002 iomanX_iop_device_t *device;
1003 unsigned int i;
1004#endif
1005 int state;
1006
1007 CpuSuspendIntr(&state);
1008#ifdef IOMANX_USE_DEVICE_LINKED_LIST
1009 entry = device_entry_used_list_head;
1010 while ( entry && strcmp(name, entry->device->name) )
1011 entry = entry->next;
1012 if ( !entry && show_unkdev_msg )
1013 {
1014 Kprintf("Unknown device '%s'\n", name);
1015 ShowDrv();
1016 }
1017#else
1018 device = NULL;
1019 for ( i = 0; i < (sizeof(device_table) / sizeof(device_table[0])); i += 1 )
1020 {
1021 if ( device_table[i] && !strcmp(name, device_table[i]->name) )
1022 {
1023 device = device_table[i];
1024 break;
1025 }
1026 }
1027 if ( !device && show_unkdev_msg )
1028 {
1029 Kprintf("Unknown device '%s'\n", name);
1030 ShowDrv();
1031 }
1032#endif
1033 CpuResumeIntr(state);
1034#ifdef IOMANX_USE_DEVICE_LINKED_LIST
1035 return entry ? entry->device : NULL;
1036#else
1037 return device;
1038#endif
1039}
1040
1041static const char *parsefile(const char *path, iomanX_iop_device_t **p_device, int *p_unit)
1042{
1043 const char *path_trimmed;
1044 char *colon_index;
1045 size_t devname_len;
1046 iomanX_iop_device_t *device;
1047 int unit;
1048 char canon[32];
1049
1050 path_trimmed = path;
1051 while ( *path_trimmed == ' ' )
1052 path_trimmed += 1;
1053 colon_index = index(path_trimmed, ':');
1054 // Unofficial: On error, return NULL instead of -1
1055 if ( !colon_index )
1056 {
1057 Kprintf("Unknown device '%s'\n", path_trimmed);
1058 return NULL;
1059 }
1060 devname_len = colon_index - path_trimmed;
1061 // Unofficial: bounds check
1062 if ( devname_len > (sizeof(canon) - 1) )
1063 return NULL;
1064 strncpy(canon, path_trimmed, devname_len);
1065 canon[devname_len] = 0;
1066 unit = 0;
1067 // Search backward for the unit number.
1068 while ( isnum(canon[devname_len - 1]) )
1069 devname_len -= 1;
1070 if ( isnum(canon[devname_len]) )
1071 unit = strtol(&canon[devname_len], 0, 10);
1072 canon[devname_len] = 0;
1073 // Find the actual device.
1074 device = lookup_dev(canon, 1);
1075 // Unofficial: On error, return NULL instead of -1
1076 if ( !device )
1077 return NULL;
1078 // Unofficial: set unit and device only after success
1079 *p_unit = unit;
1080 *p_device = device;
1081 // This is the name passed to the device op.
1082 return colon_index + 1;
1083}
1084
1085// Unofficial: unused "io request for unsupported operation" func removed
1086
1087int iomanX_AddDrv(iomanX_iop_device_t *device)
1088{
1089#ifdef IOMANX_USE_DEVICE_LINKED_LIST
1090 struct ioman_dev_listentry *entry;
1091 struct ioman_dev_listentry *old_head;
1092#else
1093 unsigned int i;
1094#endif
1095 int state;
1096
1097 CpuSuspendIntr(&state);
1098 if ( adddeldrv_in_process )
1099 {
1100 Kprintf("AddDrv()/DelDrv() recursive/mutithread call error !!");
1101 CpuResumeIntr(state);
1102 return -1;
1103 }
1104 // Unofficial: move list check out of interrupt disabled area
1105 adddeldrv_in_process = 1;
1106 CpuResumeIntr(state);
1107#ifdef IOMANX_USE_DEVICE_LINKED_LIST
1108 entry = device_entry_empty_list_head;
1109 // Unofficial: check if entry exists first
1110 if ( !entry || lookup_dev(device->name, 0) )
1111 {
1112 adddeldrv_in_process = 0;
1113 return -1;
1114 }
1115 entry->device = device;
1116 device_entry_empty_list_head = entry->next;
1117 if ( device->ops->init(device) < 0 )
1118 {
1119 old_head = device_entry_empty_list_head;
1120 entry->device = NULL;
1121 device_entry_empty_list_head = entry;
1122 entry->next = old_head;
1123 adddeldrv_in_process = 0;
1124 return -1;
1125 }
1126 old_head = device_entry_used_list_head;
1127 device_entry_used_list_head = entry;
1128 entry->next = old_head;
1129#else
1130 for ( i = 0; i < (sizeof(device_table) / sizeof(device_table[0])); i += 1 )
1131 {
1132 if ( !device_table[i] )
1133 break;
1134 }
1135
1136 if ( i >= (sizeof(device_table) / sizeof(device_table[0])) )
1137 {
1138 adddeldrv_in_process = 0;
1139 return -1;
1140 }
1141
1142 device_table[i] = device;
1143#ifdef _IOP
1144 FlushIcache();
1145#endif
1146 if ( device->ops->init(device) < 0 )
1147 {
1148 device_table[i] = NULL;
1149 adddeldrv_in_process = 0;
1150 return -1;
1151 }
1152#endif
1153 showdrvflag = 1;
1154 adddeldrv_in_process = 0;
1155 return 0;
1156}
1157
1158int iomanX_DelDrv(const char *name)
1159{
1160#ifdef IOMANX_USE_DEVICE_LINKED_LIST
1161 struct ioman_dev_listentry *entry;
1162 struct ioman_dev_listentry **p_next;
1163 struct ioman_dev_listentry *old_head;
1164#else
1165 unsigned int i;
1166#endif
1167 int state;
1168
1169 CpuSuspendIntr(&state);
1170 if ( adddeldrv_in_process )
1171 {
1172 Kprintf("AddDrv()/DelDrv() recursive/mutithread call error !!");
1173 CpuResumeIntr(state);
1174 return -1;
1175 }
1176 adddeldrv_in_process = 1;
1177 CpuResumeIntr(state);
1178#ifdef IOMANX_USE_DEVICE_LINKED_LIST
1179 entry = device_entry_used_list_head;
1180 p_next = &device_entry_used_list_head;
1181 while ( entry && strcmp(name, entry->device->name) )
1182 {
1183 p_next = &entry->next;
1184 entry = entry->next;
1185 }
1186 if ( !entry || entry->device->ops->deinit(entry->device) < 0 )
1187 {
1188 adddeldrv_in_process = 0;
1189 return -1;
1190 }
1191 old_head = device_entry_empty_list_head;
1192 entry->device = NULL;
1193 device_entry_empty_list_head = entry;
1194 *p_next = entry->next;
1195 entry->next = old_head;
1196 adddeldrv_in_process = 0;
1197 return 0;
1198#else
1199 for ( i = 0; i < (sizeof(device_table) / sizeof(device_table[0])); i += 1 )
1200 {
1201 if ( device_table[i] && !strcmp(name, device_table[i]->name) )
1202 {
1203 device_table[i]->ops->deinit(device_table[i]);
1204 device_table[i] = NULL;
1205 adddeldrv_in_process = 0;
1206 return 0;
1207 }
1208 }
1209
1210 adddeldrv_in_process = 0;
1211 return -1;
1212#endif
1213}
1214
1215#ifndef IOMANX_ENABLE_LEGACY_IOMAN_HOOK
1216unsigned int iomanX_GetDevType(int fd)
1217{
1219
1220 f = get_iob(fd);
1221 if ( !f )
1222 return handle_result(-EBADF, f, 0);
1223 return f->device->type;
1224}
1225#endif
1226
1227static void ShowDrv(void)
1228{
1229#ifdef IOMANX_USE_DEVICE_LINKED_LIST
1230 struct ioman_dev_listentry *i;
1231#else
1232 unsigned int i;
1233#endif
1234
1235 if ( !showdrvflag )
1236 return;
1237 Kprintf("Known devices are ");
1238#ifdef IOMANX_USE_DEVICE_LINKED_LIST
1239 for ( i = device_entry_used_list_head; i; i = i->next )
1240 Kprintf(" %s:(%s) ", i->device->name, i->device->desc);
1241#else
1242 for ( i = 0; i < (sizeof(device_table) / sizeof(device_table[0])); i += 1 )
1243 if ( device_table[i] != NULL && device_table[i]->name != NULL )
1244 Kprintf(" %s:(%s) ", device_table[i]->name, device_table[i]->desc);
1245#endif
1246 Kprintf("\n");
1247 showdrvflag = 0;
1248}
1249
1250#ifndef IOMANX_ENABLE_LEGACY_IOMAN_HOOK
1251static void register_tty(void)
1252{
1253 iomanX_DelDrv(dev_tty.name);
1254 iomanX_AddDrv(&dev_tty);
1255}
1256
1257static void register_dummytty(void)
1258{
1259 iomanX_DelDrv(dev_dummytty.name);
1260 iomanX_AddDrv(&dev_dummytty);
1261}
1262#endif
#define EINVAL
Definition errno.h:63
#define EUNSUP
Definition errno.h:117
#define EXDEV
Definition errno.h:55
#define EMFILE
Definition errno.h:67
#define ENODEV
Definition errno.h:57
#define EBADF
Definition errno.h:37
int CpuResumeIntr(int state)
Definition intrman.c:227
int CpuSuspendIntr(int *state)
Definition intrman.c:205
int iomanX_format(const char *dev, const char *blockdev, void *arg, int arglen)
Definition iomanX.c:716
struct _iomanX_iop_device * device
Definition iomanX.h:76
#define IOP_DT_FSEXT
Definition iomanX.h:66
#define FIO_S_IXGRP
Definition iox_stat.h:71
#define FIO_SO_IFDIR
Definition iox_stat.h:128
#define FIO_SO_IFLNK
Definition iox_stat.h:124
#define FIO_S_IROTH
Definition iox_stat.h:76
#define FIO_SO_IXOTH
Definition iox_stat.h:135
#define FIO_S_IXUSR
Definition iox_stat.h:62
#define FIO_S_IRGRP
Definition iox_stat.h:67
#define FIO_S_IXOTH
Definition iox_stat.h:80
#define FIO_S_IWOTH
Definition iox_stat.h:78
#define FIO_S_IRUSR
Definition iox_stat.h:58
#define FIO_S_IWGRP
Definition iox_stat.h:69
#define FIO_SO_IWOTH
Definition iox_stat.h:133
#define FIO_S_IFLNK
Definition iox_stat.h:41
#define FIO_SO_IFREG
Definition iox_stat.h:126
#define FIO_S_IFDIR
Definition iox_stat.h:45
#define FIO_SO_IROTH
Definition iox_stat.h:131
#define FIO_S_IFREG
Definition iox_stat.h:43
#define FIO_S_IWUSR
Definition iox_stat.h:60