📄 sys_sunos.c
字号:
int retrans; /* times to retry send */ char *hostname; /* server's hostname */ int acregmin; /* attr cache file min secs */ int acregmax; /* attr cache file max secs */ int acdirmin; /* attr cache dir min secs */ int acdirmax; /* attr cache dir max secs */ char *netname; /* server's netname */};extern dev_t get_unnamed_dev(void);extern void put_unnamed_dev(dev_t);extern asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen);extern asmlinkage int sys_socket(int family, int type, int protocol);extern asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen);/* Bind the socket on a local reserved port and connect it to the * remote server. This on Linux/i386 is done by the mount program, * not by the kernel. */static intsunos_nfs_get_server_fd (int fd, struct sockaddr_in *addr){ struct sockaddr_in local; struct sockaddr_in server; int try_port; struct socket *socket; struct inode *inode; struct file *file; int ret, result = 0; file = fget(fd); if (!file) goto out; inode = file->f_dentry->d_inode; socket = &inode->u.socket_i; local.sin_family = AF_INET; local.sin_addr.s_addr = INADDR_ANY; /* IPPORT_RESERVED = 1024, can't find the definition in the kernel */ try_port = 1024; do { local.sin_port = htons (--try_port); ret = socket->ops->bind(socket, (struct sockaddr*)&local, sizeof(local)); } while (ret && try_port > (1024 / 2)); if (ret) goto out_putf; server.sin_family = AF_INET; server.sin_addr = addr->sin_addr; server.sin_port = NFS_PORT; /* Call sys_connect */ ret = socket->ops->connect (socket, (struct sockaddr *) &server, sizeof (server), file->f_flags); if (ret >= 0) result = 1;out_putf: fput(file);out: return result;}static int get_default (int value, int def_value){ if (value) return value; else return def_value;}static int sunos_nfs_mount(char *dir_name, int linux_flags, void *data){ int server_fd; char *the_name; struct nfs_mount_data linux_nfs_mount; struct sunos_nfs_mount_args sunos_mount; /* Ok, here comes the fun part: Linux's nfs mount needs a * socket connection to the server, but SunOS mount does not * require this, so we use the information on the destination * address to create a socket and bind it to a reserved * port on this system */ if (copy_from_user(&sunos_mount, data, sizeof(sunos_mount))) return -EFAULT; server_fd = sys_socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (server_fd < 0) return -ENXIO; if (copy_from_user(&linux_nfs_mount.addr,sunos_mount.addr, sizeof(*sunos_mount.addr)) || copy_from_user(&linux_nfs_mount.root,sunos_mount.fh, sizeof(*sunos_mount.fh))) { sys_close (server_fd); return -EFAULT; } if (!sunos_nfs_get_server_fd (server_fd, &linux_nfs_mount.addr)){ sys_close (server_fd); return -ENXIO; } /* Now, bind it to a locally reserved port */ linux_nfs_mount.version = NFS_MOUNT_VERSION; linux_nfs_mount.flags = sunos_mount.flags; linux_nfs_mount.fd = server_fd; linux_nfs_mount.rsize = get_default (sunos_mount.rsize, 8192); linux_nfs_mount.wsize = get_default (sunos_mount.wsize, 8192); linux_nfs_mount.timeo = get_default (sunos_mount.timeo, 10); linux_nfs_mount.retrans = sunos_mount.retrans; linux_nfs_mount.acregmin = sunos_mount.acregmin; linux_nfs_mount.acregmax = sunos_mount.acregmax; linux_nfs_mount.acdirmin = sunos_mount.acdirmin; linux_nfs_mount.acdirmax = sunos_mount.acdirmax; the_name = getname(sunos_mount.hostname); if(IS_ERR(the_name)) return PTR_ERR(the_name); strncpy (linux_nfs_mount.hostname, the_name, 254); linux_nfs_mount.hostname [255] = 0; putname (the_name); return do_mount ("", dir_name, "nfs", linux_flags, &linux_nfs_mount);}asmlinkage intsunos_mount(char *type, char *dir, int flags, void *data){ int linux_flags = MS_MGC_MSK; /* new semantics */ int ret = -EINVAL; char *dev_fname = 0; char *dir_page, *type_page; if (!capable (CAP_SYS_ADMIN)) return -EPERM; lock_kernel(); /* We don't handle the integer fs type */ if ((flags & SMNT_NEWTYPE) == 0) goto out; /* Do not allow for those flags we don't support */ if (flags & (SMNT_GRPID|SMNT_NOSUB|SMNT_MULTI|SMNT_SYS5)) goto out; if(flags & SMNT_REMOUNT) linux_flags |= MS_REMOUNT; if(flags & SMNT_RDONLY) linux_flags |= MS_RDONLY; if(flags & SMNT_NOSUID) linux_flags |= MS_NOSUID; dir_page = getname(dir); ret = PTR_ERR(dir_page); if (IS_ERR(dir_page)) goto out; type_page = getname(type); ret = PTR_ERR(type_page); if (IS_ERR(type_page)) goto out1; if(strcmp(type_page, "ext2") == 0) { dev_fname = getname(data); } else if(strcmp(type_page, "iso9660") == 0) { dev_fname = getname(data); } else if(strcmp(type_page, "minix") == 0) { dev_fname = getname(data); } else if(strcmp(type_page, "nfs") == 0) { ret = sunos_nfs_mount (dir_page, flags, data); goto out2; } else if(strcmp(type_page, "ufs") == 0) { printk("Warning: UFS filesystem mounts unsupported.\n"); ret = -ENODEV; goto out2; } else if(strcmp(type_page, "proc")) { ret = -ENODEV; goto out2; } ret = PTR_ERR(dev_fname); if (IS_ERR(dev_fname)) goto out2; ret = do_mount(dev_fname, dir_page, type_page, linux_flags, NULL); if (dev_fname) putname(dev_fname);out2: putname(type_page);out1: putname(dir_page);out: unlock_kernel(); return ret;}extern asmlinkage int sys_setsid(void);extern asmlinkage int sys_setpgid(pid_t, pid_t);asmlinkage int sunos_setpgrp(pid_t pid, pid_t pgid){ int ret; /* So stupid... */ if((!pid || pid == current->pid) && !pgid) { sys_setsid(); ret = 0; } else { ret = sys_setpgid(pid, pgid); } return ret;}/* So stupid... */extern asmlinkage int sys_wait4(pid_t, unsigned int *, int, struct rusage *);asmlinkage int sunos_wait4(pid_t pid, unsigned int *stat_addr, int options, struct rusage *ru){ int ret; ret = sys_wait4((pid ? pid : -1), stat_addr, options, ru); return ret;}extern int kill_pg(int, int, int);asmlinkage int sunos_killpg(int pgrp, int sig){ int ret; lock_kernel(); ret = kill_pg(pgrp, sig, 0); unlock_kernel(); return ret;}asmlinkage int sunos_audit(void){ lock_kernel(); printk ("sys_audit\n"); unlock_kernel(); return -1;}extern asmlinkage unsigned long sunos_gethostid(void){ unsigned long ret; lock_kernel(); ret = ((unsigned long)idprom->id_machtype << 24) | (unsigned long)idprom->id_sernum; unlock_kernel(); return ret;}/* sysconf options, for SunOS compatibility */#define _SC_ARG_MAX 1#define _SC_CHILD_MAX 2#define _SC_CLK_TCK 3#define _SC_NGROUPS_MAX 4#define _SC_OPEN_MAX 5#define _SC_JOB_CONTROL 6#define _SC_SAVED_IDS 7#define _SC_VERSION 8extern asmlinkage long sunos_sysconf (int name){ long ret; switch (name){ case _SC_ARG_MAX: ret = ARG_MAX; break; case _SC_CHILD_MAX: ret = CHILD_MAX; break; case _SC_CLK_TCK: ret = HZ; break; case _SC_NGROUPS_MAX: ret = NGROUPS_MAX; break; case _SC_OPEN_MAX: ret = OPEN_MAX; break; case _SC_JOB_CONTROL: ret = 1; /* yes, we do support job control */ break; case _SC_SAVED_IDS: ret = 1; /* yes, we do support saved uids */ break; case _SC_VERSION: /* mhm, POSIX_VERSION is in /usr/include/unistd.h * should it go on /usr/include/linux? */ ret = 199009L; break; default: ret = -1; break; }; return ret;}asmlinkage int sunos_semsys(int op, unsigned long arg1, unsigned long arg2, unsigned long arg3, void *ptr){ union semun arg4; int ret; switch (op) { case 0: /* Most arguments match on a 1:1 basis but cmd doesn't */ switch(arg3) { case 4: arg3=GETPID; break; case 5: arg3=GETVAL; break; case 6: arg3=GETALL; break; case 3: arg3=GETNCNT; break; case 7: arg3=GETZCNT; break; case 8: arg3=SETVAL; break; case 9: arg3=SETALL; break; } /* sys_semctl(): */ arg4.__pad=ptr; /* value to modify semaphore to */ ret = sys_semctl((int)arg1, (int)arg2, (int)arg3, arg4 ); break; case 1: /* sys_semget(): */ ret = sys_semget((key_t)arg1, (int)arg2, (int)arg3); break; case 2: /* sys_semop(): */ ret = sys_semop((int)arg1, (struct sembuf *)arg2, (unsigned)arg3); break; default: ret = -EINVAL; break; }; return ret;}asmlinkage int sunos_msgsys(int op, unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4){ struct sparc_stackf *sp; unsigned long arg5; int rval; switch(op) { case 0: rval = sys_msgget((key_t)arg1, (int)arg2); break; case 1: rval = sys_msgctl((int)arg1, (int)arg2, (struct msqid_ds *)arg3); break; case 2: lock_kernel(); sp = (struct sparc_stackf *)current->thread.kregs->u_regs[UREG_FP]; arg5 = sp->xxargs[0]; unlock_kernel(); rval = sys_msgrcv((int)arg1, (struct msgbuf *)arg2, (size_t)arg3, (long)arg4, (int)arg5); break; case 3: rval = sys_msgsnd((int)arg1, (struct msgbuf *)arg2, (size_t)arg3, (int)arg4); break; default: rval = -EINVAL; break; } return rval;}asmlinkage int sunos_shmsys(int op, unsigned long arg1, unsigned long arg2, unsigned long arg3){ unsigned long raddr; int rval; switch(op) { case 0: /* sys_shmat(): attach a shared memory area */ rval = sys_shmat((int)arg1,(char *)arg2,(int)arg3,&raddr); if(!rval) rval = (int) raddr; break; case 1: /* sys_shmctl(): modify shared memory area attr. */ rval = sys_shmctl((int)arg1,(int)arg2,(struct shmid_ds *)arg3); break; case 2: /* sys_shmdt(): detach a shared memory area */ rval = sys_shmdt((char *)arg1); break; case 3: /* sys_shmget(): get a shared memory area */ rval = sys_shmget((key_t)arg1,(int)arg2,(int)arg3); break; default: rval = -EINVAL; break; }; return rval;}#define SUNOS_EWOULDBLOCK 35/* see the sunos man page read(2v) for an explanation of this garbage. We use O_NDELAY to mark file descriptors that have been set non-blocking using 4.2BSD style calls. (tridge) */static inline int check_nonblock(int ret, int fd){ if (ret == -EAGAIN) { struct file * file = fget(fd); if (file) { if (file->f_flags & O_NDELAY) ret = -SUNOS_EWOULDBLOCK; fput(file); } } return ret;}extern asmlinkage int sys_read(unsigned int fd,char *buf,int count);extern asmlinkage int sys_write(unsigned int fd,char *buf,int count);extern asmlinkage int sys_recv(int fd, void * ubuf, int size, unsigned flags);extern asmlinkage int sys_send(int fd, void * buff, int len, unsigned flags);extern asmlinkage int sys_accept(int fd, struct sockaddr *sa, int *addrlen);extern asmlinkage int sys_readv(unsigned long fd, const struct iovec * vector, long count);extern asmlinkage int sys_writev(unsigned long fd, const struct iovec * vector, long count);asmlinkage int sunos_read(unsigned int fd,char *buf,int count){ int ret; ret = check_nonblock(sys_read(fd,buf,count),fd); return ret;}asmlinkage int sunos_readv(unsigned long fd, const struct iovec * vector, long count){ int ret; ret = check_nonblock(sys_readv(fd,vector,count),fd); return ret;}asmlinkage int sunos_write(unsigned int fd,char *buf,int count){ int ret; ret = check_nonblock(sys_write(fd,buf,count),fd); return ret;}asmlinkage int sunos_writev(unsigned long fd, const struct iovec * vector, long count){ int ret; ret = check_nonblock(sys_writev(fd,vector,count),fd); return ret;}asmlinkage int sunos_recv(int fd, void * ubuf, int size, unsigned flags){ int ret; ret = check_nonblock(sys_recv(fd,ubuf,size,flags),fd); return ret;}asmlinkage int sunos_send(int fd, void * buff, int len, unsigned flags){ int ret; ret = check_nonblock(sys_send(fd,buff,len,flags),fd); return ret;}extern asmlinkage int sys_setsockopt(int fd, int level, int optname, char *optval, int optlen);asmlinkage int sunos_socket(int family, int type, int protocol){ int ret, one = 1; ret = sys_socket(family, type, protocol); if (ret < 0) goto out; sys_setsockopt(ret, SOL_SOCKET, SO_BSDCOMPAT, (char *)&one, sizeof(one));out: return ret;}asmlinkage int sunos_accept(int fd, struct sockaddr *sa, int *addrlen){ int ret, one = 1; while (1) { ret = check_nonblock(sys_accept(fd,sa,addrlen),fd); if (ret != -ENETUNREACH && ret != -EHOSTUNREACH) break; } if (ret < 0) goto out; sys_setsockopt(ret, SOL_SOCKET, SO_BSDCOMPAT, (char *)&one, sizeof(one));out: return ret;}#define SUNOS_SV_INTERRUPT 2asmlinkage intsunos_sigaction(int sig, const struct old_sigaction *act, struct old_sigaction *oact){ struct k_sigaction new_ka, old_ka; int ret; if(act) { old_sigset_t mask; if (verify_area(VERIFY_READ, act, sizeof(*act)) || __get_user(new_ka.sa.sa_handler, &act->sa_handler) || __get_user(new_ka.sa.sa_flags, &act->sa_flags)) return -EFAULT; __get_user(mask, &act->sa_mask); new_ka.sa.sa_restorer = NULL; new_ka.ka_restorer = NULL; siginitset(&new_ka.sa.sa_mask, mask); new_ka.sa.sa_flags ^= SUNOS_SV_INTERRUPT; } ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); if (!ret && oact) { /* In the clone() case we could copy half consistant * state to the user, however this could sleep and * deadlock us if we held the signal lock on SMP. So for * now I take the easy way out and do no locking. * But then again we don't support SunOS lwp's anyways ;-) */ old_ka.sa.sa_flags ^= SUNOS_SV_INTERRUPT; if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || __put_user(old_ka.sa.sa_flags, &oact->sa_flags)) return -EFAULT; __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); } return ret;}extern asmlinkage int sys_setsockopt(int fd, int level, int optname, char *optval, int optlen);extern asmlinkage int sys_getsockopt(int fd, int level, int optname, char *optval, int *optlen);asmlinkage int sunos_setsockopt(int fd, int level, int optname, char *optval, int optlen){ int tr_opt = optname; int ret; if (level == SOL_IP) { /* Multicast socketopts (ttl, membership) */ if (tr_opt >=2 && tr_opt <= 6) tr_opt += 30; } ret = sys_setsockopt(fd, level, tr_opt, optval, optlen); return ret;}asmlinkage int sunos_getsockopt(int fd, int level, int optname, char *optval, int *optlen){ int tr_opt = optname; int ret; if (level == SOL_IP) { /* Multicast socketopts (ttl, membership) */ if (tr_opt >=2 && tr_opt <= 6) tr_opt += 30; } ret = sys_getsockopt(fd, level, tr_opt, optval, optlen); return ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -